avoid extreme long lines in the error message dialog.

This commit is contained in:
hneemann 2017-04-29 22:29:03 +02:00
parent 0cafa12ae7
commit 1716a32e88
5 changed files with 179 additions and 128 deletions

View File

@ -63,7 +63,9 @@ public class ErrorMessage implements Runnable {
* @return this for call chaining
*/
public ErrorMessage show(Component parent) {
JOptionPane.showMessageDialog(parent, message.toString(), Lang.get("error"), JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(parent,
new LineBreaker(120).toHTML().preserveContainedLineBreaks().breakLines(message.toString()),
Lang.get("error"), JOptionPane.ERROR_MESSAGE);
return this;
}

View File

@ -0,0 +1,137 @@
package de.neemann.gui;
/**
* Used to break lines.
* Created by hneemann on 29.04.17.
*/
public class LineBreaker {
private static final int DEF_COLS = 70;
private final String label;
private final int indent;
private final int cols;
private final StringBuilder outText;
private boolean isFirst;
private int pos;
private boolean preserveLineBreaks = false;
private boolean toHTML = false;
private boolean containsLineBreak = false;
/**
* Creates a new instance
*/
public LineBreaker() {
this(DEF_COLS);
}
/**
* Creates a new instance
*
* @param cols number of columns to use
*/
public LineBreaker(int cols) {
this("", 0, cols);
}
/**
* Creates a new instance
*
* @param label the lable to use in the first line
* @param indent columns to indent
* @param cols number of columns to use
*/
public LineBreaker(String label, int indent, int cols) {
this.label = label;
this.indent = indent;
this.cols = cols;
outText = new StringBuilder(label);
isFirst = true;
}
/**
* Breaks the line
*
* @param text the text to handle
* @return the text containing the line breaks
*/
public String breakLines(String text) {
if (text == null)
return null;
for (int i = 0; i < indent - label.length(); i++)
outText.append(" ");
StringBuilder word = new StringBuilder();
pos = indent;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
switch (c) {
case '\n':
if (preserveLineBreaks) {
addWord(word);
lineBreak();
isFirst = true;
break;
}
case '\r':
case ' ':
addWord(word);
break;
default:
word.append(c);
}
}
addWord(word);
String ret = outText.toString();
if (containsLineBreak && toHTML)
ret = "<html>" + ret.replace("\n", "<br>") + "</html>";
return ret;
}
private void addWord(StringBuilder word) {
if (word.length() > 0) {
if (pos + (isFirst ? word.length() : word.length() + 1) > cols) {
lineBreak();
} else {
if (!isFirst) {
outText.append(" ");
pos++;
}
}
outText.append(word);
pos += word.length();
word.setLength(0);
isFirst = false;
}
}
private void lineBreak() {
outText.append('\n');
for (int j = 0; j < indent; j++)
outText.append(" ");
pos = indent;
containsLineBreak = true;
}
/**
* Preserves the contained line breaks
*
* @return this for chained calls
*/
public LineBreaker preserveContainedLineBreaks() {
this.preserveLineBreaks = true;
return this;
}
/**
* Returns an HTML string
*
* @return this for chained calls
*/
public LineBreaker toHTML() {
this.toHTML = true;
return this;
}
}

View File

@ -5,7 +5,6 @@ package de.neemann.gui;
*/
public final class StringUtils {
private static final int DEF_COLS = 70;
private StringUtils() {
}
@ -53,112 +52,13 @@ public final class StringUtils {
/**
* Formats text to html if it contains line breaks.
* Short texts are unchanged.
* Short texts are unchanged. Ignores the containing line breaks.
*
* @param text the text
* @return the unchanged text or a HTML segment
*/
public static String textToHTML(String text) {
String toolTipText = StringUtils.breakLines(text);
if (toolTipText == null)
return null;
if (toolTipText.indexOf('\n') >= 0)
toolTipText = "<html>" + toolTipText.replace("\n", "<br>") + "</html>";
return toolTipText;
}
/**
* Breaks a string separate lines, all multiple spaces and line breaks are removed.
* calls {@code breakLines(text, 60)}.
*
* @param text the text to format
* @return the formatted text
*/
public static String breakLines(String text) {
return breakLines(text, DEF_COLS);
}
/**
* Breaks a string into separate lines, all multiple blanks and line breaks are removed.
*
* @param text the text to format
* @param cols the number of columns
* @return the formatted text
*/
public static String breakLines(String text, int cols) {
return breakLinesLabel("", 0, text, cols);
}
/**
* Format a text width indentation
*
* @param label label to print in front of the text
* @param indent cols to indent the label
* @param text the text
* @return the formatted text
*/
public static String breakLinesLabel(String label, int indent, String text) {
return breakLinesLabel(label, indent, text, DEF_COLS);
}
/**
* Format a text width indentation
*
* @param label label to print in front of the text
* @param indent cols to indent the label
* @param text the text
* @param cols the number of columns
* @return the formatted text
*/
public static String breakLinesLabel(String label, int indent, String text, int cols) {
if (text == null)
return null;
StringBuilder outText = new StringBuilder(label);
for (int i = 0; i < indent - label.length(); i++)
outText.append(" ");
StringBuilder word = new StringBuilder();
boolean isFirst = true;
int pos = indent;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
switch (c) {
case '\n':
case '\r':
case ' ':
pos = addWord(indent, cols, outText, word, pos, isFirst);
isFirst = false;
break;
default:
word.append(c);
}
}
addWord(indent, cols, outText, word, pos, isFirst);
return outText.toString();
}
private static int addWord(int indent, int cols, StringBuilder outText, StringBuilder word, int pos, boolean isFirst) {
if (word.length() > 0) {
if (pos + (isFirst ? word.length() : word.length() + 1) > cols) {
outText.append('\n');
for (int j = 0; j < indent; j++)
outText.append(" ");
pos = indent;
} else {
if (!isFirst) {
outText.append(" ");
pos++;
}
}
outText.append(word);
pos += word.length();
word.setLength(0);
}
return pos;
return new LineBreaker().toHTML().breakLines(text);
}
}

View File

@ -0,0 +1,37 @@
package de.neemann.gui;
import junit.framework.TestCase;
/**
* Created by hneemann on 29.04.17.
*/
public class LineBreakerTest extends TestCase {
public void testBreakLines() throws Exception {
assertEquals("this is a test string", new LineBreaker(60).breakLines("this \n\n is \n a test \n\r string"));
assertEquals("this is a test\nstring", new LineBreaker(14).breakLines("this \n\n is \n a test \n\r string"));
assertEquals("This is a test string. This\n" +
"is a test string. This is a\n" +
"test string.", new LineBreaker(27).breakLines("This is a test string. This is a test string. This is a test string."));
assertEquals("this is\naWordThatIsFarToLongToFitInASingleLine\nThis is a test string", new LineBreaker(21).breakLines("this is aWordThatIsFarToLongToFitInASingleLine This is a test string"));
}
public void testBreakLinesLabel() throws Exception {
assertEquals("a) This is a test string. This\n" +
" is a test string. This is a\n" +
" test string.", new LineBreaker("a)", 3, 30).breakLines("This is a test string. This is a test string. This is a test string."));
}
public void testBreakLinesPreserve() throws Exception {
assertEquals("this is a\ntest string", new LineBreaker(60).preserveContainedLineBreaks().breakLines("this is a\n test string"));
assertEquals("this is a\ntest string. This is\na test string.", new LineBreaker(20).preserveContainedLineBreaks().breakLines("this is a\n test string. This is a test string."));
}
public void testBreakLinesHTML() throws Exception {
assertEquals("this is a test string", new LineBreaker(60).toHTML().breakLines("this is a\n test string"));
assertEquals("<html>this is a<br>test string</html>", new LineBreaker(60).toHTML().preserveContainedLineBreaks().breakLines("this is a\n test string"));
}
}

View File

@ -1,25 +0,0 @@
package de.neemann.gui;
import junit.framework.TestCase;
/**
* Created by hneemann on 29.10.16.
*/
public class StringUtilsTest extends TestCase {
public void testBreakLines() throws Exception {
assertEquals("this is a test string", StringUtils.breakLines("this \n\n is \n a test \n\r string", 60));
assertEquals("this is a test\nstring", StringUtils.breakLines("this \n\n is \n a test \n\r string", 14));
assertEquals("This is a test string. This\n" +
"is a test string. This is a\n" +
"test string.", StringUtils.breakLines("This is a test string. This is a test string. This is a test string.", 27));
assertEquals("this is\naWordThatIsFarToLongToFitInASingleLine\nThis is a test string", StringUtils.breakLines("this is aWordThatIsFarToLongToFitInASingleLine This is a test string", 21));
}
public void testBreakLinesLabel() throws Exception {
assertEquals("a) This is a test string. This\n" +
" is a test string. This is a\n" +
" test string.", StringUtils.breakLinesLabel("a)", 3, "This is a test string. This is a test string. This is a test string.", 30));
}
}