diff --git a/src/main/org/insa/graph/io/BinaryPathWriter.java b/src/main/org/insa/graph/io/BinaryPathWriter.java index 6a74043..ac7cbea 100644 --- a/src/main/org/insa/graph/io/BinaryPathWriter.java +++ b/src/main/org/insa/graph/io/BinaryPathWriter.java @@ -11,7 +11,7 @@ public class BinaryPathWriter extends BinaryWriter implements PathWriter { /** * @param dos */ - protected BinaryPathWriter(DataOutputStream dos) { + public BinaryPathWriter(DataOutputStream dos) { super(dos); } diff --git a/src/main/org/insa/graphics/MainWindow.java b/src/main/org/insa/graphics/MainWindow.java index e3e852b..a8ea007 100644 --- a/src/main/org/insa/graphics/MainWindow.java +++ b/src/main/org/insa/graphics/MainWindow.java @@ -11,13 +11,18 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.BufferedOutputStream; import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -34,13 +39,14 @@ import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.Timer; import javax.swing.UIManager; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileNameExtensionFilter; -import org.insa.algo.shortestpath.AStarAlgorithm; -import org.insa.algo.shortestpath.BellmanFordAlgorithm; -import org.insa.algo.shortestpath.DijkstraAlgorithm; import org.insa.algo.shortestpath.ShortestPathAlgorithm; +import org.insa.algo.shortestpath.ShortestPathAlgorithmFactory; import org.insa.algo.shortestpath.ShortestPathData; +import org.insa.algo.shortestpath.ShortestPathData.Mode; import org.insa.algo.shortestpath.ShortestPathGraphicObserver; import org.insa.algo.shortestpath.ShortestPathSolution; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver; @@ -52,6 +58,7 @@ import org.insa.graph.Path; import org.insa.graph.io.BinaryGraphReader; import org.insa.graph.io.BinaryGraphReaderV2; import org.insa.graph.io.BinaryPathReader; +import org.insa.graph.io.BinaryPathWriter; import org.insa.graph.io.GraphReader; import org.insa.graph.io.MapMismatchException; import org.insa.graph.io.Openfile; @@ -60,6 +67,7 @@ import org.insa.graphics.drawing.BasicDrawing; import org.insa.graphics.drawing.BlackAndWhiteGraphPalette; import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.MapViewDrawing; +import org.insa.graphics.drawing.overlays.PathOverlay; public class MainWindow extends JFrame { @@ -168,7 +176,7 @@ public class MainWindow extends JFrame { GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; - c.gridy = 1; + c.gridy = 2; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; @@ -223,6 +231,97 @@ public class MainWindow extends JFrame { } } + private void displayShortestPathSolution(ShortestPathSolution solution) { + JPanel infoPanel = new JPanel(); + infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.PAGE_AXIS)); + infoPanel.setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.BLACK), + new EmptyBorder(15, 15, 15, 15))); + + ShortestPathData data = (ShortestPathData) solution.getInstance(); + + String info = null; + if (solution == null || !solution.isFeasible()) { + info = String.format("Shortest path: No path found from node #%d to node #%d.", data.getOrigin().getId(), + data.getDestination().getId()); + } + else { + info = String.format("Shortest path: Found a path from node #%d to node #%d", data.getOrigin().getId(), + data.getDestination().getId()); + if (data.getMode() == Mode.LENGTH) { + info = String.format("%s, %.2f kilometers.", info, (solution.getPath().getLength() / 1000.0)); + } + else { + info = String.format("%s, %.2f minutes.", info, (solution.getPath().getMinimumTravelTime() / 60.0)); + } + } + infoPanel.add(new JLabel(info)); + + if (solution != null && solution.isFeasible()) { + infoPanel.add(Box.createVerticalStrut(8)); + + PathOverlay overlay = drawing.drawPath(solution.getPath()); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + JButton clearButton = new JButton("Hide"); + clearButton.addActionListener(new ActionListener() { + + private PathOverlay thisOverlay = overlay; + + @Override + public void actionPerformed(ActionEvent e) { + if (thisOverlay.isVisible()) { + thisOverlay.setVisible(false); + clearButton.setText("Show"); + } + else { + thisOverlay.setVisible(true); + clearButton.setText("Hide"); + } + } + }); + JButton saveButton = new JButton("Save"); + saveButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String filepath = System.getProperty("user.dir"); + filepath += File.separator + String.format("path_%#x_%d_%d.path", graph.getMapId(), + data.getOrigin().getId(), data.getDestination().getId()); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setSelectedFile(new File(filepath)); + fileChooser.setApproveButtonText("Save"); + + if (fileChooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + try { + BinaryPathWriter writer = new BinaryPathWriter( + new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))); + writer.writePath(solution.getPath()); + } + catch (IOException e1) { + JOptionPane.showMessageDialog(MainWindow.this, + "Unable to write path to the selected file."); + e1.printStackTrace(); + } + } + } + }); + buttonPanel.add(clearButton); + buttonPanel.add(saveButton); + infoPanel.add(buttonPanel); + + } + + // Add panel to the right side + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + ((JPanel) mainPanel.getRightComponent()).add(infoPanel, c); + + } + private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) { spAlgorithm.addObserver(new ShortestPathGraphicObserver(drawing)); // algo.addObserver(new ShortestPathTextObserver(printStream)); @@ -230,9 +329,7 @@ public class MainWindow extends JFrame { @Override public void run() { ShortestPathSolution solution = spAlgorithm.run(); - if (solution != null && solution.isFeasible()) { - drawing.drawPath(solution.getPath()); - } + displayShortestPathSolution(solution); } }); } @@ -463,18 +560,18 @@ public class MainWindow extends JFrame { StartActionEvent evt = (StartActionEvent) e; ShortestPathData data = new ShortestPathData(graph, evt.getOrigin(), evt.getDestination(), evt.getMode()); - ShortestPathAlgorithm spAlgorithm = null; - if (evt.getAlgorithmClass() == BellmanFordAlgorithm.class) { - spAlgorithm = new BellmanFordAlgorithm(data); + try { + ShortestPathAlgorithm spAlgorithm = ShortestPathAlgorithmFactory + .createAlgorithm(evt.getAlgorithmClass(), data); + spPanel.setEnabled(false); + launchShortestPathThread(spAlgorithm); } - else if (evt.getAlgorithmClass() == DijkstraAlgorithm.class) { - spAlgorithm = new DijkstraAlgorithm(data); + catch (Exception e1) { + JOptionPane.showMessageDialog(MainWindow.this, + "An error occurred while creating the specified algorithm.", + "Internal error: Algorithm instantiation failure", JOptionPane.ERROR_MESSAGE); + e1.printStackTrace(); } - else if (evt.getAlgorithmClass() == AStarAlgorithm.class) { - spAlgorithm = new AStarAlgorithm(data); - } - spPanel.setEnabled(false); - launchShortestPathThread(spAlgorithm); } }); } diff --git a/src/main/org/insa/graphics/drawing/BasicDrawing.java b/src/main/org/insa/graphics/drawing/BasicDrawing.java index 81e2838..fa4dcaa 100644 --- a/src/main/org/insa/graphics/drawing/BasicDrawing.java +++ b/src/main/org/insa/graphics/drawing/BasicDrawing.java @@ -41,7 +41,7 @@ public class BasicDrawing extends JPanel implements Drawing { */ private static final long serialVersionUID = 96779785877771827L; - public abstract class BasicOverlay implements Overlay { + private abstract class BasicOverlay implements Overlay { // Visible? protected boolean visible; @@ -56,6 +56,11 @@ public class BasicDrawing extends JPanel implements Drawing { BasicDrawing.this.repaint(); } + @Override + public boolean isVisible() { + return this.visible; + } + @Override public void delete() { BasicDrawing.this.overlays.remove(this); @@ -75,7 +80,7 @@ public class BasicDrawing extends JPanel implements Drawing { }; - public class BasicMarkerOverlay extends BasicOverlay implements MarkerOverlay { + private class BasicMarkerOverlay extends BasicOverlay implements MarkerOverlay { // Point of the marker. private Point point; @@ -116,7 +121,7 @@ public class BasicDrawing extends JPanel implements Drawing { }; - public class BasicPathOverlay extends BasicOverlay implements PathOverlay { + private class BasicPathOverlay extends BasicOverlay implements PathOverlay { // List of points List points; diff --git a/src/main/org/insa/graphics/drawing/MapViewDrawing.java b/src/main/org/insa/graphics/drawing/MapViewDrawing.java index 410c8e0..8caff84 100644 --- a/src/main/org/insa/graphics/drawing/MapViewDrawing.java +++ b/src/main/org/insa/graphics/drawing/MapViewDrawing.java @@ -49,7 +49,7 @@ public class MapViewDrawing extends MapView implements Drawing { */ private static final long serialVersionUID = 8606967833704938092L; - public class MapViewOverlay implements Overlay { + private class MapViewOverlay implements Overlay { // Marker associated. protected Layer[] layers; @@ -68,6 +68,11 @@ public class MapViewDrawing extends MapView implements Drawing { } } + @Override + public boolean isVisible() { + return this.layers[0].isVisible(); + } + @Override public void delete() { Layers mlayers = MapViewDrawing.this.getLayerManager().getLayers(); @@ -78,7 +83,7 @@ public class MapViewDrawing extends MapView implements Drawing { }; - public class MapViewMarkerOverlay extends MapViewOverlay implements MarkerOverlay { + private class MapViewMarkerOverlay extends MapViewOverlay implements MarkerOverlay { public MapViewMarkerOverlay(Marker marker) { super(new Layer[] { marker }); @@ -102,7 +107,7 @@ public class MapViewDrawing extends MapView implements Drawing { }; - public class MapViewPathOverlay extends MapViewOverlay implements PathOverlay { + private class MapViewPathOverlay extends MapViewOverlay implements PathOverlay { public MapViewPathOverlay(PolylineAutoScaling path, Marker origin, Marker destination) { super(new Layer[] { path, origin, destination }); diff --git a/src/main/org/insa/graphics/drawing/overlays/Overlay.java b/src/main/org/insa/graphics/drawing/overlays/Overlay.java index 97e4dae..4c3bdce 100644 --- a/src/main/org/insa/graphics/drawing/overlays/Overlay.java +++ b/src/main/org/insa/graphics/drawing/overlays/Overlay.java @@ -9,6 +9,11 @@ public interface Overlay { */ public void setVisible(boolean visible); + /** + * @return true if this overlay is visible. + */ + public boolean isVisible(); + /** * Delete this marker. */