diff --git a/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java b/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java index cc94359..3c46b0a 100644 --- a/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java +++ b/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java @@ -16,6 +16,7 @@ public class Messages { protected String info; protected String examplesFound; protected String enableTraceToSeeExamplesDetails; - protected String enableDebugToSeeExamplesList; - protected String separator; + protected String enableDebugToSeeExamplesList; + protected String separator; + protected String outputTitle; } diff --git a/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java b/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java new file mode 100644 index 0000000..1056fe7 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java @@ -0,0 +1,30 @@ +package com.penapereira.example.constructs.app.ui; + +import java.awt.EventQueue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +@Component +public class GuiAppender extends AppenderBase implements InitializingBean { + + @Autowired + private MainWindow mainWindow; + + @Override + public void afterPropertiesSet() throws Exception { + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + EventQueue.invokeLater(() -> mainWindow.appendOutput(eventObject.getFormattedMessage() + System.lineSeparator())); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java b/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java index dbbe964..a112fd3 100644 --- a/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java +++ b/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.awt.Cursor; import java.awt.Font; +import java.awt.BorderLayout; import java.awt.GridLayout; import java.io.IOException; @@ -10,7 +11,9 @@ import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JSeparator; +import javax.swing.JTextArea; import javax.swing.SwingConstants; import org.slf4j.Logger; @@ -26,7 +29,9 @@ public class MainWindow extends JFrame { private static final Logger log = LoggerFactory.getLogger(MainWindow.class); - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + + private JTextArea outputArea; @Autowired Messages msg; @@ -65,13 +70,23 @@ private void loadIcon() { } } - private JPanel getMainComponent() { - JPanel mainPanel = new JPanel(new GridLayout(4, 1)); - createCenteredTitle(msg.getGreeting(), mainPanel); - createCenteredLabelOnPanel(msg.getInfo(), mainPanel); - createCenteredHyperlink(msg.getHomeUrl(), mainPanel); - return mainPanel; - } + private JPanel getMainComponent() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + JPanel infoPanel = new JPanel(new GridLayout(4, 1)); + createCenteredTitle(msg.getGreeting(), infoPanel); + createCenteredLabelOnPanel(msg.getInfo(), infoPanel); + createCenteredHyperlink(msg.getHomeUrl(), infoPanel); + mainPanel.add(infoPanel, BorderLayout.NORTH); + + outputArea = new JTextArea(10, 40); + outputArea.setEditable(false); + JScrollPane scrollPane = new JScrollPane(outputArea); + scrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder(msg.getOutputTitle())); + mainPanel.add(scrollPane, BorderLayout.CENTER); + + return mainPanel; + } private void createCenteredTitle(String text, JPanel panel) { JLabel title = new JLabel(text, JLabel.CENTER); @@ -89,10 +104,17 @@ private void createCenteredHyperlink(String text, JPanel panel) { panel.add(hyperlink); } - private void createCenteredLabelOnPanel(String text, JPanel panel) { - JLabel label = new JLabel(text); - label.setHorizontalAlignment(JLabel.CENTER); - panel.add(label); - } + private void createCenteredLabelOnPanel(String text, JPanel panel) { + JLabel label = new JLabel(text); + label.setHorizontalAlignment(JLabel.CENTER); + panel.add(label); + } + + public void appendOutput(String text) { + if (outputArea != null) { + outputArea.append(text); + outputArea.setCaretPosition(outputArea.getDocument().getLength()); + } + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e5a6e1c..44ac060 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -18,5 +18,6 @@ msg.examplesFound=Implemented examples found msg.enableTraceToSeeExamplesDetails= [*] Please enable TRACE log level if you want to see examples output msg.enableDebugToSeeExamplesList= [*] Please enable DEBUG log level if you want to see the examples list +msg.outputTitle=Output msg.separator=------------------------------------------------------------- \ No newline at end of file diff --git a/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java b/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java index e084e3f..723bbe6 100644 --- a/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java +++ b/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java @@ -16,6 +16,7 @@ void settersAndGettersWork() { m.setEnableTraceToSeeExamplesDetails("TD"); m.setEnableDebugToSeeExamplesList("DL"); m.setSeparator("-"); + m.setOutputTitle("OT"); assertEquals("G", m.getGreeting()); assertEquals("T", m.getWindowTitle()); @@ -25,6 +26,7 @@ void settersAndGettersWork() { assertEquals("TD", m.getEnableTraceToSeeExamplesDetails()); assertEquals("DL", m.getEnableDebugToSeeExamplesList()); assertEquals("-", m.getSeparator()); + assertEquals("OT", m.getOutputTitle()); String s = m.toString(); assertTrue(s.contains("G")); @@ -40,6 +42,7 @@ void settersAndGettersWork() { other.setEnableTraceToSeeExamplesDetails("TD"); other.setEnableDebugToSeeExamplesList("DL"); other.setSeparator("-"); + other.setOutputTitle("OT"); assertEquals(m, other); assertEquals(m.hashCode(), other.hashCode()); assertNotEquals(m, "foo"); diff --git a/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java b/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java new file mode 100644 index 0000000..598d2d9 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java @@ -0,0 +1,44 @@ +package com.penapereira.example.constructs.app.ui; + +import static org.junit.jupiter.api.Assertions.*; + +import java.awt.EventQueue; +import java.lang.reflect.Field; + +import javax.swing.JTextArea; + +import org.junit.jupiter.api.Test; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.LoggingEvent; + +class GuiAppenderTests { + @Test + void appendsMessageToTextArea() throws Exception { + // Allocate a MainWindow instance without triggering the JFrame constructor + Field theUnsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafeField.get(null); + + MainWindow window = (MainWindow) unsafe.allocateInstance(MainWindow.class); + JTextArea area = new JTextArea(); + Field f = MainWindow.class.getDeclaredField("outputArea"); + f.setAccessible(true); + f.set(window, area); + + GuiAppender appender = new GuiAppender(); + Field mw = GuiAppender.class.getDeclaredField("mainWindow"); + mw.setAccessible(true); + mw.set(appender, window); + appender.start(); + + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + event.setMessage("test message"); + + appender.doAppend(event); + EventQueue.invokeAndWait(() -> {}); + + assertEquals("test message" + System.lineSeparator(), area.getText()); + } +}