diff --git a/app/src/processing/app/AbstractTextMonitor.java b/app/src/processing/app/AbstractTextMonitor.java index fdfcfba760a..b6e196a16b5 100644 --- a/app/src/processing/app/AbstractTextMonitor.java +++ b/app/src/processing/app/AbstractTextMonitor.java @@ -43,13 +43,10 @@ public abstract class AbstractTextMonitor extends AbstractMonitor { protected JComboBox lineEndings; protected JComboBox serialRates; - private SimpleDateFormat logDateFormat; - public AbstractTextMonitor(BoardPort boardPort) { super(boardPort); - logDateFormat = new SimpleDateFormat("HH:mm:ss.SSS -> "); } - + protected void onCreateWindow(Container mainPane) { Font consoleFont = Theme.getFont("console.font"); Font editorFont = PreferencesData.getFont("editor.font"); @@ -57,7 +54,7 @@ protected void onCreateWindow(Container mainPane) { mainPane.setLayout(new BorderLayout()); - textArea = new TextAreaFIFO(8000000); + textArea = new TextAreaFIFO(8_000_000); textArea.setRows(16); textArea.setColumns(40); textArea.setEditable(false); @@ -70,7 +67,7 @@ protected void onCreateWindow(Container mainPane) { scrollPane = new JScrollPane(textArea); mainPane.add(scrollPane, BorderLayout.CENTER); - + JPanel upperPane = new JPanel(); upperPane.setLayout(new BoxLayout(upperPane, BoxLayout.X_AXIS)); upperPane.setBorder(new EmptyBorder(4, 4, 4, 4)); @@ -165,7 +162,7 @@ public void onSendCommand(ActionListener listener) { textField.addActionListener(listener); sendButton.addActionListener(listener); } - + public void onClearCommand(ActionListener listener) { clearButton.addActionListener(listener); } @@ -173,41 +170,38 @@ public void onClearCommand(ActionListener listener) { public void onSerialRateChange(ActionListener listener) { serialRates.addActionListener(listener); } - - public void message(final String s) { - SwingUtilities.invokeLater(new Runnable() { - // Pre-allocate all objects used for streaming data - Date t = new Date(); - String now; - StringBuilder out = new StringBuilder(16384); - boolean isStartingLine = false; - - public void run() { - if (addTimeStampBox.isSelected()) { - t.setTime(System.currentTimeMillis()); - now = logDateFormat.format(t); - out.setLength(0); - - StringTokenizer tokenizer = new StringTokenizer(s, "\n", true); - while (tokenizer.hasMoreTokens()) { - if (isStartingLine) { - out.append(now); - } - String token = tokenizer.nextToken(); - out.append(token); - // tokenizer returns "\n" as a single token - isStartingLine = token.charAt(0) == '\n'; - } - - textArea.append(out.toString()); - } else { - textArea.append(s); - } - - if (autoscrollBox.isSelected()) { - textArea.setCaretPosition(textArea.getDocument().getLength()); - } + + public void message(String msg) { + SwingUtilities.invokeLater(() -> updateTextArea(msg)); + } + + private static final String LINE_SEPARATOR = "\n"; + private boolean isStartingLine = true; + + protected void updateTextArea(String msg) { + if (addTimeStampBox.isSelected()) { + textArea.append(addTimestamps(msg)); + } else { + textArea.append(msg); + } + if (autoscrollBox.isSelected()) { + textArea.setCaretPosition(textArea.getDocument().getLength()); + } + } + + private String addTimestamps(String text) { + String now = new SimpleDateFormat("HH:mm:ss.SSS -> ").format(new Date()); + final StringBuilder sb = new StringBuilder(text.length() + now.length()); + StringTokenizer tokenizer = new StringTokenizer(text, LINE_SEPARATOR, true); + while (tokenizer.hasMoreTokens()) { + if (isStartingLine) { + sb.append(now); } - }); + String token = tokenizer.nextToken(); + sb.append(token); + // tokenizer returns "\n" as a single token + isStartingLine = token.equals(LINE_SEPARATOR); + } + return sb.toString(); } } diff --git a/app/test/processing/app/UpdateTextAreaActionTest.java b/app/test/processing/app/UpdateTextAreaActionTest.java new file mode 100644 index 00000000000..b32ea1850be --- /dev/null +++ b/app/test/processing/app/UpdateTextAreaActionTest.java @@ -0,0 +1,91 @@ +package processing.app; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Test; + +import cc.arduino.packages.BoardPort; +import processing.app.helpers.PreferencesMap; + +public class UpdateTextAreaActionTest { + + private static final String TIMESTAMP_REGEX = "\\d\\d:\\d\\d:\\d\\d.\\d\\d\\d"; + + class DummyTextMonitor extends AbstractTextMonitor { + public DummyTextMonitor(BoardPort boardPort) { + super(boardPort); + } + } + + @Before + public void setup() { + PreferencesData.defaults = new PreferencesMap(); + PreferencesData.set("editor.font", "Monospaced,plain,12"); + PreferencesData.set("gui.scale", "100"); + Theme.defaults = new PreferencesMap(); + Theme.table.put("console.font", "Monospaced,plain,12"); + } + + @Test + public void noTimestampAdded() { + DummyTextMonitor textMon = new DummyTextMonitor(new BoardPort()); + textMon.addTimeStampBox.setSelected(false); + + textMon.updateTextArea("line1\nline2\r\nline3"); + assertThat(textMon.textArea.getText()).matches("line1\nline2\r\nline3"); + } + + @Test + public void all3LinesHaveTimestampAdded() { + DummyTextMonitor textMon = new DummyTextMonitor(new BoardPort()); + textMon.addTimeStampBox.setSelected(true); + + textMon.updateTextArea("line1\nline2\r\nline3"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> line1\\n" + // + TIMESTAMP_REGEX + " -> line2\\r\\n" + // + TIMESTAMP_REGEX + " -> line3"); + } + + @Test + public void emptyLinesHaveTimestampToo() { + DummyTextMonitor textMon = new DummyTextMonitor(new BoardPort()); + textMon.addTimeStampBox.setSelected(true); + + textMon.updateTextArea("line_1\n\nline_2"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> line_1\\n" + // + TIMESTAMP_REGEX + " -> \\n" + // + TIMESTAMP_REGEX + " -> line_2"); + } + + @Test + public void newLinesAreRememberedWhenNewBufferIsUsed() { + DummyTextMonitor textMon = new DummyTextMonitor(new BoardPort()); + textMon.addTimeStampBox.setSelected(true); + + textMon.updateTextArea("no newline"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> no newline"); + + textMon.updateTextArea(" more text"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> no newline more text"); + + textMon.updateTextArea("\n"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> no newline more text\n"); + + textMon.updateTextArea("\n"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> no newline more text\n" + // + TIMESTAMP_REGEX + " -> \n"); + + textMon.updateTextArea("third line"); + assertThat(textMon.textArea.getText()) + .matches(TIMESTAMP_REGEX + " -> no newline more text\n" + // + TIMESTAMP_REGEX + " -> \n" + // + TIMESTAMP_REGEX + " -> third line"); + } +} \ No newline at end of file