Fix output stream in textarea. Add blocking actions.

This commit is contained in:
Holt59 2018-02-24 16:21:59 +01:00
parent 0514c627b4
commit ca94ddf7ff
7 changed files with 315 additions and 119 deletions

View File

@ -0,0 +1,58 @@
package org.insa.graphics;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class BlockingActionFactory {
// List of running actions.
private ArrayList<RunningAction> actions = new ArrayList<>();
// Parent component.
private Component parentComponent;
public BlockingActionFactory(Component parentComponent) {
this.parentComponent = parentComponent;
}
public void addAction(RunningAction action) {
actions.add(action);
}
public ActionListener createBlockingAction(ActionListener listener) {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean accepted = true;
// Check if actions...
for (int i = 0; i < actions.size() && accepted; ++i) {
RunningAction action = actions.get(i);
// If action is running, ask user...
if (action.isRunning()) {
System.out.println("Action " + action.getInformation() + " is running... ");
if (JOptionPane.showConfirmDialog(parentComponent, "Action {" + action.getInformation()
+ "} is running, do you want to stop it?") == JOptionPane.OK_OPTION) {
System.out.println("Action " + action.getInformation() + " has been interrupted.");
action.interrupt();
}
else {
System.out.println("Action " + action.getInformation() + " not interrupted... ");
accepted = false;
}
}
}
// If action is accepted, run it...
if (accepted) {
listener.actionPerformed(e);
}
}
};
}
}

View File

@ -1,14 +0,0 @@
package org.insa.graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public abstract class BlockingActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
this.actionAccepted(e);
}
public abstract void actionAccepted(ActionEvent e);
}

View File

@ -12,10 +12,7 @@ import java.awt.event.WindowEvent;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
@ -44,17 +41,19 @@ import org.insa.algo.shortestpath.ShortestPathData.Mode;
import org.insa.algo.shortestpath.ShortestPathGraphicObserver; import org.insa.algo.shortestpath.ShortestPathGraphicObserver;
import org.insa.algo.shortestpath.ShortestPathSolution; import org.insa.algo.shortestpath.ShortestPathSolution;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentTextObserver;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.Node; import org.insa.graph.Node;
import org.insa.graph.Path; import org.insa.graph.Path;
import org.insa.graph.io.GraphReader;
import org.insa.graph.io.BinaryGraphReader; import org.insa.graph.io.BinaryGraphReader;
import org.insa.graph.io.BinaryGraphReaderV2; import org.insa.graph.io.BinaryGraphReaderV2;
import org.insa.graph.io.BinaryPathReader; import org.insa.graph.io.BinaryPathReader;
import org.insa.graph.io.GraphReader;
import org.insa.graph.io.MapMismatchException; import org.insa.graph.io.MapMismatchException;
import org.insa.graph.io.Openfile; import org.insa.graph.io.Openfile;
import org.insa.graphics.MultiPointsClickListener.CallableWithNodes;
import org.insa.graphics.drawing.BasicDrawing; import org.insa.graphics.drawing.BasicDrawing;
import org.insa.graphics.drawing.BlackAndWhiteGraphPalette; import org.insa.graphics.drawing.BlackAndWhiteGraphPalette;
import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.Drawing;
@ -62,30 +61,6 @@ import org.insa.graphics.drawing.MapViewDrawing;
public class MainWindow extends JFrame { public class MainWindow extends JFrame {
protected class JOutputStream extends OutputStream {
private JTextArea textArea;
public JOutputStream(JTextArea textArea) {
this.textArea = textArea;
}
@Override
public void write(int b) throws IOException {
// redirects data to the text area
textArea.setText(textArea.getText() + String.valueOf((char) b));
// scrolls the text area to the end of data
textArea.setCaretPosition(textArea.getDocument().getLength());
// keeps the textArea up to date
textArea.update(textArea.getGraphics());
}
}
protected interface CallableWithNodes {
void call(ArrayList<Node> nodes);
};
/** /**
* *
*/ */
@ -102,14 +77,13 @@ public class MainWindow extends JFrame {
private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds
// Current graph. // Current graph.
private Graph graph; protected Graph graph;
// Current loaded path. // Current loaded path.
private Path currentPath; // private Path currentPath;
// Drawing and click adapter. // Drawing and click adapter.
private Drawing drawing; protected Drawing drawing;
private MultiPointsClickListener clickAdapter = null;
// Main panel. // Main panel.
private JSplitPane mainPanel; private JSplitPane mainPanel;
@ -124,23 +98,41 @@ public class MainWindow extends JFrame {
private JLabel mapIdPanel; private JLabel mapIdPanel;
// Thread information // Thread information
private Instant threadStartTime;
private Timer threadTimer; private Timer threadTimer;
private JPanel threadPanel; private JPanel threadPanel;
// Log stream and print stream // Log stream and print stream
private JOutputStream logStream; private StreamCapturer logStream;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private PrintStream printStream; private PrintStream printStream;
// Current running thread // Current running thread
private Thread currentThread; private ThreadWrapper currentThread;
// Multi point listener
private MultiPointsClickListener clickAdapter = null;
// Factory
private BlockingActionFactory baf;
public MainWindow() { public MainWindow() {
super(WINDOW_TITLE); super(WINDOW_TITLE);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setLayout(new BorderLayout()); setLayout(new BorderLayout());
// Create drawing and action listeners...
this.drawing = new BasicDrawing();
this.clickAdapter = new MultiPointsClickListener(this);
this.currentThread = new ThreadWrapper(this);
this.baf = new BlockingActionFactory(this);
this.baf.addAction(clickAdapter);
this.baf.addAction(currentThread);
// Click adapter
addDrawingClickListeners();
setJMenuBar(createMenuBar()); setJMenuBar(createMenuBar());
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
@ -158,21 +150,15 @@ public class MainWindow extends JFrame {
// Create graph area // Create graph area
mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
this.drawing = new BasicDrawing();
// Click adapter
addDrawingClickListeners();
JTextArea infoPanel = new JTextArea(); JTextArea infoPanel = new JTextArea();
infoPanel.setMinimumSize(new Dimension(200, 50)); infoPanel.setMinimumSize(new Dimension(200, 50));
infoPanel.setBackground(Color.WHITE); infoPanel.setBackground(Color.WHITE);
infoPanel.setLineWrap(true); infoPanel.setLineWrap(true);
infoPanel.setEditable(false); infoPanel.setEditable(false);
this.logStream = new JOutputStream(infoPanel); this.logStream = new StreamCapturer(infoPanel);
this.printStream = new PrintStream(this.logStream); this.printStream = new PrintStream(this.logStream);
mainPanel.setResizeWeight(0.8); mainPanel.setResizeWeight(0.8);
// sp.setEnabled(false);
mainPanel.setDividerSize(5); mainPanel.setDividerSize(5);
mainPanel.setBackground(Color.WHITE); mainPanel.setBackground(Color.WHITE);
@ -183,10 +169,10 @@ public class MainWindow extends JFrame {
// Top Panel // Top Panel
this.add(createTopPanel(), BorderLayout.NORTH); this.add(createTopPanel(), BorderLayout.NORTH);
this.add(createStatusBar(), BorderLayout.SOUTH); this.add(createStatusBar(), BorderLayout.SOUTH);
} }
private void restartThreadTimer() { private void restartThreadTimer() {
threadStartTime = Instant.now();
threadTimer.restart(); threadTimer.restart();
} }
@ -200,7 +186,7 @@ public class MainWindow extends JFrame {
*/ */
private void launchThread(Runnable runnable, boolean canInterrupt) { private void launchThread(Runnable runnable, boolean canInterrupt) {
if (canInterrupt) { if (canInterrupt) {
currentThread = new Thread(new Runnable() { currentThread.setThread(new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
restartThreadTimer(); restartThreadTimer();
@ -208,22 +194,22 @@ public class MainWindow extends JFrame {
runnable.run(); runnable.run();
clearCurrentThread(); clearCurrentThread();
} }
}); }));
} }
else { else {
currentThread = new Thread(runnable); currentThread.setThread(new Thread(runnable));
} }
currentThread.start(); currentThread.startThread();
} }
private void launchThread(Runnable runnable) { private void launchThread(Runnable runnable) {
launchThread(runnable, true); launchThread(runnable, true);
} }
private void clearCurrentThread() { protected void clearCurrentThread() {
stopThreadTimer(); stopThreadTimer();
threadPanel.setVisible(false); threadPanel.setVisible(false);
currentThread = null; currentThread.setThread(null);
} }
private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) { private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
@ -241,7 +227,6 @@ public class MainWindow extends JFrame {
} }
private void addDrawingClickListeners() { private void addDrawingClickListeners() {
this.clickAdapter = new MultiPointsClickListener(graph, drawing);
drawing.addDrawingClickListener(this.clickAdapter); drawing.addDrawingClickListener(this.clickAdapter);
} }
@ -265,9 +250,9 @@ public class MainWindow extends JFrame {
// Open Map item... // Open Map item...
openMapItem = new JMenuItem("Open Map... ", KeyEvent.VK_O); openMapItem = new JMenuItem("Open Map... ", KeyEvent.VK_O);
openMapItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); openMapItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
openMapItem.addActionListener(new BlockingActionListener() { openMapItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser(); JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Map & compressed map files", "map", FileNameExtensionFilter filter = new FileNameExtensionFilter("Map & compressed map files", "map",
"map2", "mapgr", "map.gz"); "map2", "mapgr", "map.gz");
@ -313,14 +298,14 @@ public class MainWindow extends JFrame {
}, false); }, false);
} }
} }
}); }));
// Open Path item... // Open Path item...
JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P); JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P);
openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK)); openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK));
openPathItem.addActionListener(new BlockingActionListener() { openPathItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser(); JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Path & compressed path files", "path", FileNameExtensionFilter filter = new FileNameExtensionFilter("Path & compressed path files", "path",
"path.gz"); "path.gz");
@ -336,7 +321,8 @@ public class MainWindow extends JFrame {
return; return;
} }
try { try {
currentPath = reader.readPath(graph); Path path = reader.readPath(graph);
drawing.drawPath(path);
} }
catch (MapMismatchException exception) { catch (MapMismatchException exception) {
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this,
@ -347,18 +333,17 @@ public class MainWindow extends JFrame {
JOptionPane.showMessageDialog(MainWindow.this, "Unable to read path from the selected file."); JOptionPane.showMessageDialog(MainWindow.this, "Unable to read path from the selected file.");
return; return;
} }
drawing.drawPath(currentPath);
} }
} }
}); }));
graphLockItems.add(openPathItem); graphLockItems.add(openPathItem);
// Close item // Close item
JMenuItem closeItem = new JMenuItem("Quit", KeyEvent.VK_Q); JMenuItem closeItem = new JMenuItem("Quit", KeyEvent.VK_Q);
closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK)); closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK));
closeItem.addActionListener(new BlockingActionListener() { closeItem.addActionListener(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING)); MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
} }
}); });
@ -373,9 +358,9 @@ public class MainWindow extends JFrame {
// Second menu // Second menu
JMenuItem drawGraphItem = new JMenuItem("Redraw", KeyEvent.VK_R); JMenuItem drawGraphItem = new JMenuItem("Redraw", KeyEvent.VK_R);
drawGraphItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); drawGraphItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK));
drawGraphItem.addActionListener(new BlockingActionListener() { drawGraphItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -384,13 +369,13 @@ public class MainWindow extends JFrame {
} }
}); });
} }
}); }));
graphLockItems.add(drawGraphItem); graphLockItems.add(drawGraphItem);
JMenuItem drawGraphBWItem = new JMenuItem("Redraw (B&W)", KeyEvent.VK_B); JMenuItem drawGraphBWItem = new JMenuItem("Redraw (B&W)", KeyEvent.VK_B);
drawGraphBWItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK)); drawGraphBWItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK));
drawGraphBWItem.addActionListener(new BlockingActionListener() { drawGraphBWItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -399,13 +384,13 @@ public class MainWindow extends JFrame {
} }
}); });
} }
}); }));
graphLockItems.add(drawGraphBWItem); graphLockItems.add(drawGraphBWItem);
JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M); JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M);
drawGraphMapsforgeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK)); drawGraphMapsforgeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
drawGraphMapsforgeItem.addActionListener(new BlockingActionListener() { drawGraphMapsforgeItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -414,7 +399,7 @@ public class MainWindow extends JFrame {
} }
}); });
} }
}); }));
graphLockItems.add(drawGraphMapsforgeItem); graphLockItems.add(drawGraphMapsforgeItem);
JMenu graphMenu = new JMenu("Graph"); JMenu graphMenu = new JMenu("Graph");
@ -428,13 +413,13 @@ public class MainWindow extends JFrame {
// Weakly connected components // Weakly connected components
JMenuItem wccItem = new JMenuItem("Weakly Connected Components"); JMenuItem wccItem = new JMenuItem("Weakly Connected Components");
wccItem.addActionListener(new BlockingActionListener() { wccItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph); WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph);
WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance); WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance);
algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing));
// algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream));
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -442,13 +427,13 @@ public class MainWindow extends JFrame {
} }
}); });
} }
}); }));
// Shortest path // Shortest path
JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)"); JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)");
bellmanItem.addActionListener(new BlockingActionListener() { bellmanItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionAccepted(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", "Mode selection", int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", "Mode selection",
JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, Mode.values(), Mode.LENGTH); JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, Mode.values(), Mode.LENGTH);
@ -463,7 +448,7 @@ public class MainWindow extends JFrame {
}); });
} }
} }
}); }));
graphLockItems.add(wccItem); graphLockItems.add(wccItem);
graphLockItems.add(bellmanItem); graphLockItems.add(bellmanItem);
@ -487,14 +472,6 @@ public class MainWindow extends JFrame {
return menuBar; return menuBar;
} }
@SuppressWarnings("deprecation")
private void stopCurrentThread() {
// Should not be used in production code, but here I have no idea how
// to do this properly... Cannot use .interrupt() because it would requires
// the algorithm to watch the ThreadInteruption exception.
currentThread.stop();
}
private JPanel createStatusBar() { private JPanel createStatusBar() {
// create the status bar panel and shove it down the bottom of the frame // create the status bar panel and shove it down the bottom of the frame
JPanel statusPanel = new JPanel(); JPanel statusPanel = new JPanel();
@ -513,14 +490,12 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (currentThread != null && currentThread.isAlive()) { if (currentThread.isRunning()) {
int confirmed = JOptionPane.showConfirmDialog(null, int confirmed = JOptionPane.showConfirmDialog(null,
"Are you sure you want to kill the running thread?", "Kill Confirmation", "Are you sure you want to kill the running thread?", "Kill Confirmation",
JOptionPane.YES_NO_OPTION); JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) { if (confirmed == JOptionPane.YES_OPTION) {
stopCurrentThread(); currentThread.interrupt();
clearCurrentThread();
threadPanel.setVisible(false);
} }
} }
} }
@ -529,8 +504,7 @@ public class MainWindow extends JFrame {
threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() { threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Duration elapsed = Duration.between(threadStartTime, Instant.now()); long seconds = currentThread.getDuration().getSeconds();
long seconds = elapsed.getSeconds();
threadTimerLabel threadTimerLabel
.setText(String.format("%02d:%02d:%02d", seconds / 3600, seconds / 60 % 60, seconds % 60)); .setText(String.format("%02d:%02d:%02d", seconds / 3600, seconds / 60 % 60, seconds % 60));
} }

View File

@ -1,16 +1,26 @@
package org.insa.graphics; package org.insa.graphics;
import java.awt.Color; import java.awt.Color;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import org.insa.graph.Graph;
import org.insa.graph.Node; import org.insa.graph.Node;
import org.insa.graph.Point; import org.insa.graph.Point;
import org.insa.graphics.MainWindow.CallableWithNodes;
import org.insa.graphics.drawing.Drawing;
import org.insa.graphics.drawing.DrawingClickListener; import org.insa.graphics.drawing.DrawingClickListener;
public class MultiPointsClickListener implements DrawingClickListener { public class MultiPointsClickListener implements DrawingClickListener, RunningAction {
protected interface CallableWithNodes {
/**
* Function called when the given number of nodes is reached.
*
* @param nodes
*/
void call(ArrayList<Node> nodes);
};
// Enable/Disable. // Enable/Disable.
private boolean enabled = false; private boolean enabled = false;
@ -18,6 +28,9 @@ public class MultiPointsClickListener implements DrawingClickListener {
// List of points. // List of points.
private ArrayList<Node> points = new ArrayList<Node>(); private ArrayList<Node> points = new ArrayList<Node>();
// Starting time
private Instant startTime;
// Number of points to find before running. // Number of points to find before running.
private int nTargetPoints = 0; private int nTargetPoints = 0;
@ -25,14 +38,10 @@ public class MultiPointsClickListener implements DrawingClickListener {
CallableWithNodes callable = null; CallableWithNodes callable = null;
// Graph // Graph
private final Graph graph; private final MainWindow mainWindow;
// Drawing public MultiPointsClickListener(MainWindow mainWindow) {
private final Drawing drawing; this.mainWindow = mainWindow;
public MultiPointsClickListener(Graph graph, Drawing drawing) {
this.graph = graph;
this.drawing = drawing;
} }
/** /**
@ -45,14 +54,14 @@ public class MultiPointsClickListener implements DrawingClickListener {
/** /**
* Enable this listener. * Enable this listener.
* *
* @param nTargetPoints * @param nTargetPoints Number of point to found before calling the callable.
* Number of point to found before calling the callable.
*/ */
public void enable(int nTargetPoints, CallableWithNodes callable) { public void enable(int nTargetPoints, CallableWithNodes callable) {
this.enabled = true; this.enabled = true;
this.nTargetPoints = nTargetPoints; this.nTargetPoints = nTargetPoints;
this.points.clear(); this.points.clear();
this.callable = callable; this.callable = callable;
this.startTime = Instant.now();
} }
/** /**
@ -67,8 +76,8 @@ public class MultiPointsClickListener implements DrawingClickListener {
if (!isEnabled()) { if (!isEnabled()) {
return; return;
} }
Node node = graph.findClosestNode(lonlat); Node node = mainWindow.graph.findClosestNode(lonlat);
drawing.drawMarker(node.getPoint(), Color.BLUE); mainWindow.drawing.drawMarker(node.getPoint(), Color.BLUE);
points.add(node); points.add(node);
if (points.size() == nTargetPoints) { if (points.size() == nTargetPoints) {
callable.call(points); callable.call(points);
@ -76,4 +85,29 @@ public class MultiPointsClickListener implements DrawingClickListener {
} }
} }
@Override
public boolean isRunning() {
return isEnabled();
}
@Override
public void interrupt() {
disable();
}
@Override
public Instant getStartingTime() {
return startTime;
}
@Override
public Duration getDuration() {
return Duration.between(getStartingTime(), Instant.now());
}
@Override
public String getInformation() {
return getClass().getName();
}
} }

View File

@ -0,0 +1,33 @@
package org.insa.graphics;
import java.time.Duration;
import java.time.Instant;
public interface RunningAction {
/**
* @return true if this action is running.
*/
public boolean isRunning();
/**
* Interrupt this action.
*/
public void interrupt();
/**
* @return Starting time of this action.
*/
public Instant getStartingTime();
/**
* @return Current duration of this action.
*/
public Duration getDuration();
/**
* @return Information for this action.
*/
public String getInformation();
}

View File

@ -0,0 +1,49 @@
package org.insa.graphics;
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JTextArea;
public class StreamCapturer extends OutputStream {
private StringBuilder buffer;
private String prefix = null;
private JTextArea output;
/**
* @param prefix
* @param output
*/
public StreamCapturer(JTextArea output, String prefix) {
this.prefix = prefix;
buffer = new StringBuilder(128);
this.output = output;
}
public StreamCapturer(JTextArea output) {
this(output, null);
}
@Override
public void write(int b) throws IOException {
char c = (char) b;
String value = Character.toString(c);
buffer.append(value);
if (value.equals("\n")) {
output.append(getPrefix() + buffer.toString());
output.setCaretPosition(output.getText().length());
buffer.delete(0, buffer.length());
}
}
/**
* @return Formatted prefix, or empty string if no prefix is set.
*/
public String getPrefix() {
if (this.prefix == null) {
return "";
}
return "[" + prefix + "] ";
}
}

View File

@ -0,0 +1,62 @@
package org.insa.graphics;
import java.time.Duration;
import java.time.Instant;
public class ThreadWrapper implements RunningAction {
// Thread hold by this wrapper.
private Thread thread;
// Starting time of the thread.
Instant startingTime;
// MainWindow
private MainWindow mainWindow;
public ThreadWrapper(MainWindow mainWindow) {
this.thread = null;
this.mainWindow = mainWindow;
}
public void setThread(Thread thread) {
this.thread = thread;
}
public void startThread() {
this.startingTime = Instant.now();
this.thread.start();
}
public Thread getThread() {
return this.thread;
}
@Override
public boolean isRunning() {
return thread != null && thread.isAlive();
}
@SuppressWarnings("deprecation")
@Override
public void interrupt() {
thread.stop();
this.mainWindow.clearCurrentThread();
}
@Override
public Instant getStartingTime() {
return startingTime;
}
@Override
public Duration getDuration() {
return Duration.between(getStartingTime(), Instant.now());
}
@Override
public String getInformation() {
return getClass().getName();
}
}