Fix output stream in textarea. Add blocking actions.
This commit is contained in:
parent
0514c627b4
commit
ca94ddf7ff
58
src/main/org/insa/graphics/BlockingActionFactory.java
Normal file
58
src/main/org/insa/graphics/BlockingActionFactory.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
33
src/main/org/insa/graphics/RunningAction.java
Normal file
33
src/main/org/insa/graphics/RunningAction.java
Normal 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();
|
||||||
|
|
||||||
|
}
|
49
src/main/org/insa/graphics/StreamCapturer.java
Normal file
49
src/main/org/insa/graphics/StreamCapturer.java
Normal 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 + "] ";
|
||||||
|
}
|
||||||
|
}
|
62
src/main/org/insa/graphics/ThreadWrapper.java
Normal file
62
src/main/org/insa/graphics/ThreadWrapper.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user