From 08fd7120f2e4ad9af6efef7bd14a60d94b84d7cc Mon Sep 17 00:00:00 2001 From: Mikael Capelle Date: Thu, 1 Mar 2018 19:51:37 +0100 Subject: [PATCH] Create new solution panel. --- src/main/org/insa/graphics/MainWindow.java | 115 ++-------- .../graphics/ShortestPathSolutionPanel.java | 208 ++++++++++++++++++ 2 files changed, 222 insertions(+), 101 deletions(-) create mode 100644 src/main/org/insa/graphics/ShortestPathSolutionPanel.java diff --git a/src/main/org/insa/graphics/MainWindow.java b/src/main/org/insa/graphics/MainWindow.java index 5dbce4e..18c7d00 100644 --- a/src/main/org/insa/graphics/MainWindow.java +++ b/src/main/org/insa/graphics/MainWindow.java @@ -12,20 +12,15 @@ import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -49,7 +44,6 @@ import javax.swing.filechooser.FileNameExtensionFilter; 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; @@ -61,7 +55,6 @@ import org.insa.graph.Path; import org.insa.graph.io.BinaryGraphReaderInsa2016; import org.insa.graph.io.BinaryGraphReaderInsa2018; 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.graphics.ShortestPathPanel.StartActionEvent; @@ -71,7 +64,6 @@ import org.insa.graphics.drawing.BlackAndWhiteGraphPalette; import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.GraphPalette; import org.insa.graphics.drawing.MapViewDrawing; -import org.insa.graphics.drawing.overlays.PathOverlay; public class MainWindow extends JFrame { @@ -106,6 +98,7 @@ public class MainWindow extends JFrame { // Shortest path panel private ShortestPathPanel spPanel; + private ShortestPathSolutionPanel spSolPanel; // List of items that cannot be used without a graph private ArrayList graphLockItems = new ArrayList(); @@ -170,12 +163,17 @@ public class MainWindow extends JFrame { }); spPanel.setVisible(false); + spSolPanel = new ShortestPathSolutionPanel(this, drawing); + spSolPanel.setVisible(false); + // Add click listeners to both drawing. basicDrawing.addDrawingClickListener(spPanel.nodesInputPanel); mapViewDrawing.addDrawingClickListener(spPanel.nodesInputPanel); this.graphChangeListeneres.add(spPanel.nodesInputPanel); + this.graphChangeListeneres.add(spSolPanel); this.drawingChangeListeners.add(spPanel.nodesInputPanel); + this.drawingChangeListeners.add(spSolPanel); // Create action factory. this.currentThread = new ThreadWrapper(this); @@ -218,6 +216,12 @@ public class MainWindow extends JFrame { c.fill = GridBagConstraints.HORIZONTAL; rightComponent.add(spPanel, c); + c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + rightComponent.add(spSolPanel, c); + c = new GridBagConstraints(); c.gridx = 0; c.gridy = 2; @@ -275,99 +279,8 @@ 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); - + spSolPanel.addSolution(solution); + spSolPanel.setVisible(true); } private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) { diff --git a/src/main/org/insa/graphics/ShortestPathSolutionPanel.java b/src/main/org/insa/graphics/ShortestPathSolutionPanel.java new file mode 100644 index 0000000..aaf8be1 --- /dev/null +++ b/src/main/org/insa/graphics/ShortestPathSolutionPanel.java @@ -0,0 +1,208 @@ +package org.insa.graphics; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; + +import org.insa.algo.shortestpath.ShortestPathData; +import org.insa.algo.shortestpath.ShortestPathData.Mode; +import org.insa.algo.shortestpath.ShortestPathSolution; +import org.insa.graph.Graph; +import org.insa.graph.io.BinaryPathWriter; +import org.insa.graphics.drawing.Drawing; +import org.insa.graphics.drawing.overlays.PathOverlay; + +public class ShortestPathSolutionPanel extends JPanel + implements DrawingChangeListener, GraphChangeListener { + + /** + * + */ + private static final long serialVersionUID = 1L; + + // Parent components + Component parent; + + // Solution + private Drawing drawing; + + // Solution selector + JComboBox solutionSelect; + + // Map solution -> panel + Map solutionToPanel = new IdentityHashMap<>(); + + public ShortestPathSolutionPanel(Component parent, Drawing drawing) { + super(); + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.BLACK), + new EmptyBorder(15, 15, 15, 15))); + + this.parent = parent; + this.drawing = drawing; + + // TODO: Create select + Block for JPanel + + solutionSelect = new JComboBox<>(new ShortestPathSolution[0]); + solutionSelect.setBackground(Color.WHITE); + solutionSelect.setAlignmentX(Component.LEFT_ALIGNMENT); + add(solutionSelect); + + JPanel bottomPanel = new JPanel(); + bottomPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + add(bottomPanel); + + solutionSelect.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unchecked") + JComboBox combo = (JComboBox) e + .getSource(); + ShortestPathSolution solution = (ShortestPathSolution) combo.getSelectedItem(); + + bottomPanel.removeAll(); + bottomPanel.add(solutionToPanel.get(solution)); + } + }); + + } + + public void addSolution(ShortestPathSolution solution) { + + // add info panel + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); + panel.add(createInformationLabel(solution)); + if (solution != null && solution.isFeasible()) { + panel.add(Box.createVerticalStrut(8)); + panel.add(createPathPanel(solution)); + } + + solutionToPanel.put(solution, panel); + solutionSelect.addItem(solution); + solutionSelect.setSelectedItem(solution); + } + + protected JLabel createInformationLabel(ShortestPathSolution solution) { + 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)); + } + } + JLabel label = new JLabel(info); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + label.setHorizontalAlignment(JLabel.LEFT); + + return label; + } + + protected JPanel createPathPanel(ShortestPathSolution solution) { + + ShortestPathData data = (ShortestPathData) solution.getInstance(); + + final PathOverlay overlay = drawing.drawPath(solution.getPath()); + + JButton clearButton = new JButton("Hide"); + clearButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (overlay.isVisible()) { + overlay.setVisible(false); + clearButton.setText("Show"); + } + else { + overlay.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", data.getGraph().getMapId(), + data.getOrigin().getId(), data.getDestination().getId()); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setSelectedFile(new File(filepath)); + fileChooser.setApproveButtonText("Save"); + + if (fileChooser.showOpenDialog(parent) == 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(parent, + "Unable to write path to the selected file."); + e1.printStackTrace(); + } + } + } + }); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + buttonPanel.add(clearButton); + buttonPanel.add(saveButton); + + buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + + return buttonPanel; + } + + @Override + public void newGraphLoaded(Graph graph) { + // TODO: + } + + @Override + public void onDrawingLoaded(Drawing oldDrawing, Drawing newDrawing) { + if (newDrawing != drawing) { + drawing = newDrawing; + } + } + + @Override + public void onRedrawRequest() { + // TODO: + } + +}