Fix output stream in textarea. Add blocking actions.
This commit is contained in:
		
							parent
							
								
									0514c627b4
								
							
						
					
					
						commit
						ca94ddf7ff
					
				
					 7 changed files with 315 additions and 119 deletions
				
			
		
							
								
								
									
										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 a new issue