diff --git a/gclc-swt/pom.xml b/gclc-swt/pom.xml
index c8365a5..1ee5ae8 100644
--- a/gclc-swt/pom.xml
+++ b/gclc-swt/pom.xml
@@ -7,7 +7,7 @@
net.bigeon.gclcswt
- 1.1.7-SNAPSHOT
+ 1.2.0-SNAPSHOTjarGCLC swtA swt window for console applications
@@ -55,6 +55,12 @@
collections1.1.6
+
+ org.mockito
+ mockito-core
+ 2.23.0
+ test
+
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleDelayIO.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleDelayIO.java
index cc5eb04..f274eb2 100644
--- a/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleDelayIO.java
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleDelayIO.java
@@ -35,6 +35,8 @@
*/
package net.bigeon.gclc.swt;
+import java.io.IOException;
+
/*-
* #%L
* GCLC swt
@@ -86,6 +88,8 @@ public interface ConsoleDelayIO {
* @param input the input to set */
void setInput(String input);
- /** Actually send the input as the prompt next input. */
- void validateInput();
+ /** Actually send the input as the prompt next input.
+ *
+ * @throws IOException if an error occurred */
+ void validateInput() throws IOException;
}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleInputManager.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleInputManager.java
new file mode 100644
index 0000000..3c83881
--- /dev/null
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleInputManager.java
@@ -0,0 +1,54 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import java.io.IOException;
+
+import org.eclipse.swt.widgets.Text;
+
+import net.bigeon.gclc.utils.PipedConsoleInput;
+
+/** @author Emmanuel Bigeon */
+public final class ConsoleInputManager implements ConsoleDelayIO {
+
+ private final Text text;
+ private PipedConsoleInput input;
+
+ /** @param text the text */
+ public ConsoleInputManager(final Text text) {
+ super();
+ this.text = text;
+ }
+
+ /** @param string the text */
+ @Override
+ public void setInput(final String string) {
+ text.setText(string);
+ text.setSelection(string.length());
+ }
+
+ /* (non-Javadoc)
+ * @see net.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
+ @Override
+ public String getInput() {
+ return text.getText();
+ }
+
+ @Override
+ public void validateInput() throws IOException {
+ input.type(text.getText());
+ }
+
+ /** Set the input to control
+ *
+ * @param input the input */
+ public void setManager(final PipedConsoleInput input) {
+ this.input = input;
+ }
+
+ /** @return the text */
+ public Text getText() {
+ return text;
+ }
+}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleOutputManager.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleOutputManager.java
new file mode 100644
index 0000000..0097f3e
--- /dev/null
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsoleOutputManager.java
@@ -0,0 +1,96 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import org.eclipse.swt.widgets.Text;
+
+import net.bigeon.gclc.manager.ConsoleOutput;
+import net.bigeon.gclc.utils.AOutputForwardRunnable;
+import net.bigeon.gclc.utils.PipedConsoleOutput;
+
+/** @author Emmanuel Bigeon */
+public final class ConsoleOutputManager {
+ /** The local implementation of the forwarding runnable
+ *
+ * @author Emmanuel Bigeon */
+ private final class ToSWTConsoleForwardRunnable extends AOutputForwardRunnable {
+ /** The running status */
+ private boolean running = true;
+ private final PipedConsoleOutput out;
+
+ /** @param manager the manager */
+ public ToSWTConsoleForwardRunnable(final PipedConsoleOutput manager) {
+ super(manager);
+ out = manager;
+ }
+
+ @Override
+ protected void forwardLine(final String m) {
+ appendConsoleOutput(System.lineSeparator() + m);
+ }
+
+ @Override
+ protected boolean isRunning() {
+ return running && !text.isDisposed();
+ }
+
+ /** @param running the running to set */
+ public void setRunning(final boolean running) {
+ this.running = running;
+ }
+
+ /** @return the currently forwarded output */
+ public PipedConsoleOutput getOuput() {
+ return out;
+ }
+ }
+
+ private final Text text;
+ private ConsoleOutput output;
+ /** The forwarding runnable */
+ private ToSWTConsoleForwardRunnable forward;
+ private Thread forwardThread;
+
+ /** @param text the text to display the output in. */
+ public ConsoleOutputManager(final Text text) {
+ super();
+ this.text = text;
+ }
+
+ /** @param next the next message */
+ public void appendConsoleOutput(final String next) {
+ text.getDisplay().syncExec(new Runnable() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run() {
+ text.append(next);
+ }
+ });
+ }
+
+ /** Set the output.
+ *
+ * @param output the output to set */
+ public void setManager(final PipedConsoleOutput output) {
+ if (forward != null) {
+ if (forward.getOuput() == output) {
+ return;
+ }
+ forward.setRunning(false);
+ }
+ if (output == null) {
+ forward = null;
+ forwardThread = null;
+ return;
+ }
+ forward = new ToSWTConsoleForwardRunnable(output);
+ forwardThread = new Thread(forward, "gclcToSWT"); //$NON-NLS-1$
+ forwardThread.start();
+ }
+
+ /** @return the forwardThread */
+ public Thread getForwardThread() {
+ return forwardThread;
+ }
+}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsolePromptManager.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsolePromptManager.java
new file mode 100644
index 0000000..814dd75
--- /dev/null
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/ConsolePromptManager.java
@@ -0,0 +1,47 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import java.io.BufferedReader;
+
+import org.eclipse.swt.widgets.Label;
+
+/** @author Emmanuel Bigeon */
+public final class ConsolePromptManager {
+
+ private final Label label;
+
+ private PromptReadingRunnable promptRead;
+
+ /** @param label the label to update */
+ public ConsolePromptManager(final Label label) {
+ super();
+ this.label = label;
+ }
+
+ /** @param string the text */
+ public void setPrompt(final String string) {
+ label.setText(string);
+ }
+
+ /** Set the input to control
+ *
+ * @param promptStream the input */
+ public void setStream(final BufferedReader promptStream) {
+ if (promptRead != null) {
+ if (promptRead.getReader() == promptStream) {
+ return;
+ }
+ promptRead.setRunning(false);
+ }
+ if (promptStream == null) {
+ promptRead = null;
+ return;
+ }
+ promptRead = new PromptReadingRunnable(promptStream,
+ label);
+ final Thread th = new Thread(promptRead, "Prompt To Label");
+ th.start();
+ }
+}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/HistoryTextKeyListener.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/HistoryTextKeyListener.java
index 089037d..1710301 100644
--- a/gclc-swt/src/main/java/net/bigeon/gclc/swt/HistoryTextKeyListener.java
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/HistoryTextKeyListener.java
@@ -35,6 +35,10 @@
*/
package net.bigeon.gclc.swt;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
/*-
* #%L
* GCLC swt
@@ -83,7 +87,9 @@ public final class HistoryTextKeyListener extends KeyAdapter {
/** The size of commands history. */
private static final int DEFAULT_HISTORY_SIZE = 10;
/** The empty string constant. */
- private static final String EMPTY = ""; //$NON-NLS-1$
+ private static final String EMPTY = ""; //$NON-NLS-1$
+ private static final Logger LOGGER = Logger
+ .getLogger(HistoryTextKeyListener.class.getName());
/** The history ribbon. */
private final Ribbon commands;
/** The current index in history search. */
@@ -118,7 +124,11 @@ public final class HistoryTextKeyListener extends KeyAdapter {
if (!input.isEmpty()) {
commands.add(input);
}
- console.validateInput();
+ try {
+ console.validateInput();
+ } catch (final IOException e) {
+ LOGGER.log(Level.SEVERE, "Unable to write to console", e);
+ }
currentIndex = -1;
}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/PromptReadingRunnable.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/PromptReadingRunnable.java
new file mode 100644
index 0000000..d50d6cb
--- /dev/null
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/PromptReadingRunnable.java
@@ -0,0 +1,65 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * @author Emmanuel Bigeon
+ *
+ */
+public class PromptReadingRunnable implements Runnable {
+
+ private final BufferedReader reader;
+ private final Label view;
+ private boolean running = true;
+
+ /** @param reader the reader
+ * @param view the view to update on lines. */
+ public PromptReadingRunnable(final BufferedReader reader, final Label view) {
+ super();
+ this.reader = reader;
+ this.view = view;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ String prompt;
+ try {
+ while (isRunning() && (prompt = reader.readLine()) != null) {
+ final String curPrompt = prompt;
+ view.getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ view.setText(curPrompt);
+ }
+ });
+ }
+ } catch (final IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /** @return the running */
+ public synchronized boolean isRunning() {
+ return running;
+ }
+
+ /** @param running the running to set */
+ public synchronized void setRunning(final boolean running) {
+ this.running = running;
+ }
+
+ /** @return the reader */
+ public BufferedReader getReader() {
+ return reader;
+ }
+}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsole.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsole.java
deleted file mode 100644
index 827b324..0000000
--- a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsole.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * GCLC swt, provide a swt window for console applications
- * Copyright (C) 2015-2017 E. Bigeon
- * mailto:emmanuel@bigeon.fr
- *
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- */
-/**
- * gclc-swt:net.bigeon.gclc.swt.SWTConsole.java
- * Created on: Apr 18, 2015
- */
-package net.bigeon.gclc.swt;
-
-/*-
- * #%L
- * GCLC swt
- * %%
- * Copyright (C) 2015 - 2018 Bigeon
- * %%
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- * #L%
- */
-import java.io.IOException;
-import java.util.function.Supplier;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-import net.bigeon.gclc.ConsoleApplication;
-import net.bigeon.gclc.manager.ConsoleInput;
-import net.bigeon.gclc.manager.ConsoleOutput;
-import net.bigeon.gclc.tools.ConstantString;
-
-/** A SWT component to connect to gclc {@link ConsoleApplication}.
- *
- *
- * @author Emmanuel Bigeon */
-public final class SWTConsole extends Composite
- implements ConsoleDelayIO, ConsoleInput, ConsoleOutput {
- private static final int TWO = 2;
- private static final String ERROR_SYNCHRO_PROMPT = "Error in synchronization of prompting";
- /** The number of columns of the layout. */
- private static final int LAYOUT_NB_COLUMNS = 2;
- /** The cmd prefix in the output console. */
- private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$
- /** The class logger. */
- private static final Logger LOGGER = Logger
- .getLogger(SWTConsole.class.getName());
- /** The empty string constant. */
- private static final String EMPTY = ""; //$NON-NLS-1$
-
- /** The console output text field. */
- private final Text consoleOutput;
- /** The console input text field. */
- private final Text consoleInput;
- /** The prompt label. */
- private final Label lblPromptlabel;
- /** The prompt text. */
- private Supplier prompt = new ConstantString("> "); //$NON-NLS-1$
- /** The command entered by the user. */
- private String command = null;
- /** If the prompt should be active. */
- private boolean prompting = false;
- /** The object for thread synchronization with the prompt. */
- private final Object promptLock = new Object();
-
- /** Create the composite.
- *
- * @param parent the prent composite
- * @param style the composite style */
- public SWTConsole(final Composite parent, final int style) {
- super(parent, style);
-
- setLayout(new GridLayout(LAYOUT_NB_COLUMNS, false));
-
- consoleOutput = new Text(this,
- SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
- consoleOutput.setLayoutData(
- new GridData(SWT.FILL, SWT.FILL, true, true, LAYOUT_NB_COLUMNS, 1));
- consoleOutput.setRedraw(true);
-
- lblPromptlabel = new Label(this, SWT.NONE);
- lblPromptlabel.setText(prompt.get());
-
- consoleInput = new Text(this, SWT.BORDER);
- consoleInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- consoleInput.addKeyListener(new HistoryTextKeyListener(this));
-
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.swt.widgets.Composite#checkSubclass() */
- @Override
- protected void checkSubclass() {
- // Disable the check that prevents subclassing of SWT components
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.manager.ConsoleManager#close() */
- @Override
- public void close() {
- synchronized (promptLock) {
- prompting = false;
- promptLock.notifyAll();
- }
- if (consoleInput.isDisposed()) {
- return;
- }
- consoleInput.setEnabled(false);
- consoleOutput.setEnabled(false);
- }
-
- /* (non-Javadoc)
- * @see net.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
- @Override
- public String getInput() {
- return consoleInput.getText();
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#getPrompt() */
- @Override
- public Supplier getPrompt() {
- return prompt;
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
- @Override
- public void interruptPrompt() {
- synchronized (promptLock) {
- promptLock.notifyAll();
- }
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
- @Override
- public boolean isClosed() {
- return isDisposed();
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#print(java.lang.String) */
- @Override
- public void print(final String text) throws IOException {
- if (isDisposed()) {
- throw new IOException();
- }
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- consoleOutput.append(text);
- }
- }
- });
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#println() */
- @Override
- public void println() throws IOException {
- if (isDisposed()) {
- throw new IOException();
- }
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- consoleOutput.append(System.lineSeparator());
- }
- }
- });
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#println(java.lang.String) */
- @Override
- public void println(final String message) throws IOException {
- if (isDisposed()) {
- throw new IOException();
- }
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- consoleOutput.append(message + System.lineSeparator());
- }
- }
- });
-
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#prompt() */
- @Override
- public String prompt() throws IOException {
- synchronized (promptLock) {
- initPrompt(prompt.get());
- promptLock.notifyAll();
- try {
- while (prompting) {
- promptLock.wait();
- }
- } catch (final InterruptedException e) {
- LOGGER.log(Level.WARNING, ERROR_SYNCHRO_PROMPT, e);
- command = null;
- Thread.currentThread().interrupt();
- }
- }
- if (isDisposed()) {
- throw new IOException("Input closed"); //$NON-NLS-1$
- }
- return command;
- }
-
- /** Initialize the prompting.
- *
- * @param message the prompt message
- * @throws IOException if the console is disposed */
- private void initPrompt(final String message) throws IOException {
- if (isDisposed()) {
- throw new IOException();
- }
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- lblPromptlabel.setText(message);
- // relayout
- SWTConsole.this.layout();
- consoleInput.setEnabled(true);
- consoleInput.setFocus();
- }
- }
- });
- prompting = true;
- command = null;
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.manager.ConsoleInput#prompt(long) */
- @Override
- public String prompt(final long timeout) throws IOException {
- synchronized (promptLock) {
- initPrompt(prompt.get());
- promptLock.notifyAll();
- try {
- waitPromptResolution(timeout);
- } catch (final InterruptedException e) {
- LOGGER.log(Level.WARNING, ERROR_SYNCHRO_PROMPT, e);
- command = null;
- Thread.currentThread().interrupt();
- }
- }
- return command;
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
- @Override
- public String prompt(final String message) throws IOException {
- synchronized (promptLock) {
- initPrompt(message);
- promptLock.notifyAll();
- try {
- while (prompting) {
- promptLock.wait();
- }
- if (isDisposed()) {
- throw new IOException();
- }
- } catch (final InterruptedException e) {
- LOGGER.log(Level.WARNING, ERROR_SYNCHRO_PROMPT, e);
- command = null;
- Thread.currentThread().interrupt();
- } finally {
- resetPrompt();
- }
- }
- return command;
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.manager.ConsoleInput#prompt(java.lang.String, long) */
- @Override
- public String prompt(final String message, final long timeout) throws IOException {
- synchronized (promptLock) {
- initPrompt(message);
- promptLock.notifyAll();
- try {
- waitPromptResolution(timeout);
- } catch (final InterruptedException e) {
- LOGGER.log(Level.WARNING, ERROR_SYNCHRO_PROMPT, e);
- command = null;
- Thread.currentThread().interrupt();
- } finally {
- resetPrompt();
- }
- }
- return command;
- }
-
- /** Wait the prompt resolution by user.
- *
- * @param timeout the timeout for the wait
- * @throws InterruptedException if the thread is interrupted
- * @throws IOException if the console is disposed. */
- private void waitPromptResolution(final long timeout)
- throws InterruptedException, IOException {
- final long start = System.currentTimeMillis();
- long cur = start;
- while (prompting && start + timeout > cur) {
- promptLock.wait((cur - start - timeout) / TWO);
- cur = System.currentTimeMillis();
- }
- if (isDisposed()) {
- throw new IOException();
- }
- }
-
- /** Reset the prompt message. */
- private void resetPrompt() {
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- lblPromptlabel.setText(prompt.get());
- // relayout
- SWTConsole.this.layout();
- }
- }
- });
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.swt.widgets.Composite#setFocus() */
- @Override
- public boolean setFocus() {
- return consoleInput.setFocus();
- }
-
- /* (non-Javadoc)
- * @see net.bigeon.gclc.swt.ConsoleDelayIO#setInput(java.lang.String) */
- @Override
- public void setInput(final String input) {
- consoleInput.setText(input);
- consoleInput.setSelection(input.length());
- }
-
- /* (non-Javadoc)
- * @see net.bigeon.gclc.manager.ConsoleInput#setPrompt(java.lang.String) */
- @Override
- public void setPrompt(final String prompt) {
- setPrompt(new ConstantString(prompt));
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.ConsoleManager#setPrompt(java.lang.String) */
- @Override
- public void setPrompt(final Supplier prompt) {
- this.prompt = prompt;
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- if (!consoleOutput.isDisposed()) {
- lblPromptlabel.setText(prompt.get());
- // relayout
- SWTConsole.this.layout();
- }
- }
- });
- }
-
- /** Set the input text.
- *
- * @param string the text */
- public void setText(final String string) {
- consoleInput.setText(string);
- }
-
- /* (non-Javadoc)
- * @see net.bigeon.gclc.swt.ConsoleDelayIO#validateInput() */
- @Override
- public void validateInput() {
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- consoleInput.setEnabled(false);
- }
- });
- synchronized (promptLock) {
- while (!prompting) {
- try {
- promptLock.wait();
- } catch (final InterruptedException e) {
- LOGGER.log(Level.SEVERE, "Interruption while waiting prompt", e); //$NON-NLS-1$
- Thread.currentThread().interrupt();
- }
- }
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- command = consoleInput.getText();
- prompting = false;
- consoleInput.setText(EMPTY);
- consoleOutput.append(CMD_PREFIX + command + System.lineSeparator());
- }
- });
- promptLock.notifyAll();
- }
- }
-
-}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleShell.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleShell.java
index dc30d1e..40bf9de 100644
--- a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleShell.java
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleShell.java
@@ -35,6 +35,8 @@
*/
package net.bigeon.gclc.swt;
+import java.io.BufferedReader;
+
/*-
* #%L
* GCLC swt
@@ -69,26 +71,32 @@ package net.bigeon.gclc.swt;
* #L%
*/
import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
-/** A shell containing a {@link SWTConsole}
+import net.bigeon.gclc.utils.PipedConsoleInput;
+import net.bigeon.gclc.utils.PipedConsoleOutput;
+
+/** A shell containing a {@link SWTConsoleView}
*
*
* @author Emmanuel Bigeon */
public final class SWTConsoleShell extends Shell {
- /** The console component */
- private SWTConsole console;
+ private ConsoleInputManager inputManager;
+ private ConsoleOutputManager outputManager;
+ private ConsolePromptManager promptManager;
/** Create the shell.
*
* @param display the display */
public SWTConsoleShell(final Display display, final int style) {
super(display, style);
- setLayout(new FillLayout(SWT.HORIZONTAL));
-
+ setLayout(new GridLayout(2, false));
createContents();
}
@@ -99,20 +107,39 @@ public final class SWTConsoleShell extends Shell {
/** Create contents of the shell. */
private void createContents() {
- console = new SWTConsole(this, SWT.NONE);
+ final Text output = new Text(this,
+ SWT.WRAP | SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL);
+ output.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ final Label prompt = new Label(this, SWT.NONE);
+ prompt.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+ final Text input = new Text(this, SWT.NONE);
+ input.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ inputManager = new ConsoleInputManager(input);
+ outputManager = new ConsoleOutputManager(output);
+ promptManager = new ConsolePromptManager(prompt);
setText("Console Application"); //$NON-NLS-1$
}
- /* (non-Javadoc)
- * @see org.eclipse.swt.widgets.Shell#dispose() */
- @Override
- public void dispose() {
- super.dispose();
- console.close();
+ public void connect(final PipedConsoleInput input, final PipedConsoleOutput output,
+ final BufferedReader promptStream) {
+ inputManager.setManager(input);
+ outputManager.setManager(output);
+ promptManager.setStream(promptStream);
}
- /** @return the input and output. */
- public SWTConsole getManager() {
- return console;
+ /** @return the inputManager */
+ public ConsoleInputManager getInputManager() {
+ return inputManager;
+ }
+
+ /** @return the outputManager */
+ public ConsoleOutputManager getOutputManager() {
+ return outputManager;
+ }
+
+ /** @return the promptManager */
+ public ConsolePromptManager getPromptManager() {
+ return promptManager;
}
}
diff --git a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleView.java b/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleView.java
index 1443fd6..020f87d 100644
--- a/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleView.java
+++ b/gclc-swt/src/main/java/net/bigeon/gclc/swt/SWTConsoleView.java
@@ -35,52 +35,15 @@
*/
package net.bigeon.gclc.swt;
-/*-
- * #%L
- * GCLC swt
- * %%
- * Copyright (C) 2015 - 2018 Bigeon
- * %%
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- * #L%
- */
-import java.io.IOException;
-import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
import net.bigeon.gclc.ConsoleApplication;
-import net.bigeon.gclc.utils.AOutputForwardRunnable;
import net.bigeon.gclc.utils.PipedConsoleInput;
import net.bigeon.gclc.utils.PipedConsoleOutput;
@@ -88,47 +51,14 @@ import net.bigeon.gclc.utils.PipedConsoleOutput;
*
*
* @author Emmanuel Bigeon */
-public final class SWTConsoleView extends Composite implements ConsoleDelayIO {
- /** The local implementation of the forwarding runnable
- *
- * @author Emmanuel Bigeon */
- private final class ToSWTConsoleForwardRunnable extends AOutputForwardRunnable {
- /** The running status */
- private boolean running = true;
-
- /** @param manager the manager */
- public ToSWTConsoleForwardRunnable(final PipedConsoleOutput manager) {
- super(manager);
- }
-
- @Override
- protected void forwardLine(final String m) {
- appendConsoleOutput(System.lineSeparator() + m);
- }
-
- @Override
- protected boolean isRunning() {
- return running && !isDisposed();
- }
-
- /** @param running the running to set */
- public void setRunning(final boolean running) {
- this.running = running;
- }
- }
-
+public final class SWTConsoleView extends Composite {
/** The class logger */
private static final Logger LOGGER = Logger
.getLogger(SWTConsoleView.class.getName());
- /** The console output text field */
- private final Text consoleOutput;
- /** The console input text field */
- private final Text consoleInput;
/** The input. */
private PipedConsoleInput input;
- /** The forwarding runnable */
- private ToSWTConsoleForwardRunnable forward;
-
+ private final ConsoleInputManager inManager;
+ private final ConsoleOutputManager outManager;
/** Create the composite.
*
* @param parent the prent composite
@@ -138,25 +68,16 @@ public final class SWTConsoleView extends Composite implements ConsoleDelayIO {
setLayout(new GridLayout(1, false));
- consoleOutput = new Text(this,
+ final Text consoleOutput = new Text(this,
SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
consoleOutput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
consoleOutput.setRedraw(true);
+ outManager = new ConsoleOutputManager(consoleOutput);
- consoleInput = new Text(this, SWT.BORDER);
+ final Text consoleInput = new Text(this, SWT.BORDER);
consoleInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- consoleInput.addKeyListener(new HistoryTextKeyListener(this));
- }
-
- /** @param next the next message */
- public void appendConsoleOutput(final String next) {
- Display.getDefault().syncExec(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- consoleOutput.append(next);
- }
- });
+ inManager = new ConsoleInputManager(consoleInput);
+ consoleInput.addKeyListener(new HistoryTextKeyListener(inManager));
}
@Override
@@ -164,26 +85,11 @@ public final class SWTConsoleView extends Composite implements ConsoleDelayIO {
// Disable the check that prevents subclassing of SWT components
}
- /* (non-Javadoc)
- * @see net.bigeon.gclc.swt.ConsoleDelayIO#getInput() */
- @Override
- public String getInput() {
- return consoleInput.getText();
- }
-
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Composite#setFocus() */
@Override
public boolean setFocus() {
- return consoleInput.setFocus();
- }
-
- /* (non-Javadoc)
- * @see net.bigeon.gclc.swt.ConsoleDelayIO#setInput(java.lang.String) */
- @Override
- public void setInput(final String input) {
- consoleInput.setText(input);
- consoleInput.setSelection(input.length());
+ return inManager.getText().setFocus();
}
/** Set the input and output.
@@ -192,29 +98,17 @@ public final class SWTConsoleView extends Composite implements ConsoleDelayIO {
* @param input the input */
public void setManager(final PipedConsoleOutput manager,
final PipedConsoleInput input) {
- this.input = input;
- if (forward != null) {
- forward.setRunning(false);
- }
- forward = new ToSWTConsoleForwardRunnable(manager);
- final Thread th = new Thread(forward, "gclcToSWT"); //$NON-NLS-1$
- th.start();
+ outManager.setManager(manager);
+ inManager.setManager(input);
}
- /** @param string the text */
- public void setText(final String string) {
- consoleInput.setText(string);
+ /** @return the inManager */
+ public ConsoleInputManager getInputManager() {
+ return inManager;
}
- /**
- *
- */
- @Override
- public void validateInput() {
- try {
- input.type(getInput());
- } catch (final IOException e) {
- LOGGER.log(Level.SEVERE, "Unable to input value to console", e); //$NON-NLS-1$
- }
+ /** @return the outManager */
+ public ConsoleOutputManager getOutputManager() {
+ return outManager;
}
}
diff --git a/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleInputManagerTest.java b/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleInputManagerTest.java
new file mode 100644
index 0000000..bf1f286
--- /dev/null
+++ b/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleInputManagerTest.java
@@ -0,0 +1,85 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.eclipse.swt.widgets.Text;
+import org.junit.Test;
+
+import net.bigeon.gclc.utils.PipedConsoleInput;
+
+/** @author Emmanuel Bigeon */
+public class ConsoleInputManagerTest {
+
+ private final Text text = mock(Text.class);
+ private final ConsoleInputManager cim = new ConsoleInputManager(text);
+
+ /** Test method for
+ * {@link net.bigeon.gclc.swt.ConsoleInputManager#setInput(java.lang.String)}. */
+ @Test
+ public void testSetText() {
+ cim.setInput("Text");
+ verify(text).setText("Text");
+ }
+
+ /** Test method for
+ * {@link net.bigeon.gclc.swt.ConsoleInputManager#validateInput()}.
+ *
+ * @throws IOException if an error occurred */
+ @Test
+ public void testValidateInput() throws IOException {
+ // Expected calls
+ when(text.getText()).thenReturn("abc");
+
+ try {
+ cim.validateInput();
+ fail("No input should cause exception for input validation");
+ } catch (final Exception e) {
+ // ok
+ }
+ final PipedConsoleInput input = mock(PipedConsoleInput.class);
+ cim.setManager(input);
+
+ cim.validateInput();
+ verify(input).type("abc");
+ }
+
+ @Test
+ public void testValidateInputWithError() throws IOException {
+ final PipedConsoleInput input = mock(PipedConsoleInput.class);
+ cim.setManager(input);
+ // Expected calls
+ when(text.getText()).thenReturn("abc");
+ doThrow(new IOException()).when(input).type("abc");
+
+ try {
+ cim.validateInput();
+ fail("IO exception should be forwarded");
+ } catch (final IOException e) {
+ // ok
+ }
+ }
+
+ /** Test method for
+ * {@link net.bigeon.gclc.swt.ConsoleInputManager#getText()}. */
+ @Test
+ public void testGetText() {
+ assertEquals("Text component should be preserved", text, cim.getText());
+ }
+
+ @Test
+ public void testGetInput() {
+ when(text.getText()).thenReturn("abc");
+ assertEquals("Text component should be preserved", "abc", cim.getInput());
+ }
+
+}
diff --git a/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleOutputManagerTest.java b/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleOutputManagerTest.java
new file mode 100644
index 0000000..26cdad3
--- /dev/null
+++ b/gclc-swt/src/test/java/net/bigeon/gclc/swt/ConsoleOutputManagerTest.java
@@ -0,0 +1,66 @@
+/**
+ *
+ */
+package net.bigeon.gclc.swt;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import net.bigeon.gclc.utils.PipedConsoleOutput;
+
+/** @author Emmanuel Bigeon */
+public class ConsoleOutputManagerTest {
+ private final Text text = mock(Text.class);
+ private final ConsoleOutputManager com = new ConsoleOutputManager(text);
+ private final Display display = mock(Display.class);
+ {
+ when(text.getDisplay()).thenReturn(display);
+ doAnswer(new Answer