diff --git a/java_console/ui/src/main/java/com/rusefi/maintenance/DfuFlasher.java b/java_console/ui/src/main/java/com/rusefi/maintenance/DfuFlasher.java index 28bb1ab129..9ad501f7a2 100644 --- a/java_console/ui/src/main/java/com/rusefi/maintenance/DfuFlasher.java +++ b/java_console/ui/src/main/java/com/rusefi/maintenance/DfuFlasher.java @@ -81,6 +81,7 @@ public class DfuFlasher { if (signature.get() == null) { wnd.append("*** ERROR *** rusEFI has not responded on selected " + port + "\n" + "Maybe try automatic serial port detection?"); + wnd.setErrorState(true); return null; } boolean isSignatureValidatedLocal = DfuHelper.sendDfuRebootCommand(parent, signature.get(), stream, wnd); @@ -89,6 +90,7 @@ public class DfuFlasher { wnd.append("Auto-detecting port...\n"); // instead of opening the just-detected port we execute the command using the same stream we used to discover port // it's more reliable this way + // ISSUE: that's blocking stuff on UI thread at the moment, TODO smarter threading! port = PortDetector.autoDetectSerial(callbackContext -> { boolean isSignatureValidatedLocal = DfuHelper.sendDfuRebootCommand(parent, callbackContext.getSignature(), callbackContext.getStream(), wnd); isSignatureValidated.set(isSignatureValidatedLocal); @@ -96,6 +98,7 @@ public class DfuFlasher { }).getSerialPort(); if (port == null) { wnd.append("*** ERROR *** rusEFI serial port not detected"); + wnd.setErrorState(true); return null; } else { wnd.append("Detected rusEFI on " + port + "\n"); diff --git a/java_console/ui/src/main/java/com/rusefi/ui/StatusWindow.java b/java_console/ui/src/main/java/com/rusefi/ui/StatusWindow.java index c80cb03698..5e1d9f4a7f 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/StatusWindow.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/StatusWindow.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.awt.datatransfer.StringSelection; import static com.devexperts.logging.Logging.getLogging; @@ -20,7 +21,7 @@ public class StatusWindow implements StatusConsumer { private static final Logging log = getLogging(StatusWindow.class); private static final Color LIGHT_RED = new Color(255, 102, 102); - private static final Color LIGHT_GREEN = new Color(102, 255 ,102); + private static final Color LIGHT_GREEN = new Color(102, 255, 102); // todo: extract driver from console bundle? find a separate driver bundle? private final JTextArea logTextArea = new JTextArea(); private final JPanel content = new JPanel(new BorderLayout()); @@ -56,6 +57,7 @@ public class StatusWindow implements StatusConsumer { public void setErrorState(boolean isErrorState) { if (isErrorState) { logTextArea.setBackground(LIGHT_RED); + copyContentToClipboard(); } else { logTextArea.setBackground(LIGHT_GREEN); } @@ -74,6 +76,7 @@ public class StatusWindow implements StatusConsumer { @Override public void append(final String string) { + // todo: check if AWT thread and do not invokeLater if already on AWT thread SwingUtilities.invokeLater(() -> { String s = string.replaceAll(Character.toString((char) 219), ""); log.info(s); @@ -82,6 +85,15 @@ public class StatusWindow implements StatusConsumer { }); } + public void copyContentToClipboard() { + // kludge: due to 'append' method using invokeLater even while on AWT thread we also need invokeLater to + // actually get overall status message + SwingUtilities.invokeLater(() -> Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents(new StringSelection(logTextArea.getText()), null)); + + append("hint: error state is already in your clipboard, please use PASTE or Ctrl-V while reporting issues"); + } + public void setStatus(String status) { bottomStatusLabel.setText(status); }