Make solution panel a bit more generic using reflections.

This commit is contained in:
Holt59 2018-03-03 20:06:38 +01:00
parent 6d8c2462ab
commit f22c1c93fa
5 changed files with 209 additions and 134 deletions

View file

@ -1,22 +1,100 @@
package org.insa.algo; package org.insa.algo;
import org.insa.graph.Arc;
import org.insa.graph.Graph; import org.insa.graph.Graph;
public abstract class AbstractInputData { public abstract class AbstractInputData {
protected Graph graph; public enum Mode {
TIME, LENGTH
}
/** /**
* Create a new AbstractInputData instance with the given graph. *
*
*/
public interface ArcFilter {
/**
* @param arc
*
* @return true if the given arc is allowed.
*/
public boolean isAllowed(Arc arc);
}
// Graph
protected Graph graph;
// Mode for the computation of the costs.
private final AbstractInputData.Mode mode;
// Arc filter.
private final AbstractInputData.ArcFilter arcFilter;
/**
* Create a new AbstractInputData instance for the given graph, mode and filter.
* *
* @param graph * @param graph
*/ */
protected AbstractInputData(Graph graph) { protected AbstractInputData(Graph graph, Mode mode, ArcFilter arcFilter) {
this.graph = graph; this.graph = graph;
this.mode = mode;
this.arcFilter = arcFilter;
} }
/**
* Create a new AbstractInputData instance for the given graph and mode, with no
* filtering on the arc.
*
* @param graph
* @param mode
*/
protected AbstractInputData(Graph graph, Mode mode) {
this(graph, mode, new AbstractInputData.ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return true;
}
});
}
/**
* Create a new AbstractInputData instance for the given graph, with default
* mode (LENGHT), with no filtering on the arc.
*
* @param graph
* @param mode
*/
protected AbstractInputData(Graph graph) {
this(graph, Mode.LENGTH, new AbstractInputData.ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return true;
}
});
}
/**
* @return Graph associated with this input.
*/
public Graph getGraph() { public Graph getGraph() {
return graph; return graph;
} }
/**
* @return Mode of the algorithm (time or length).
*/
public Mode getMode() {
return mode;
}
/**
* @return true if the given arc is allowed.
*/
public boolean isAllowed(Arc arc) {
return this.arcFilter.isAllowed(arc);
}
} }

View file

@ -5,12 +5,12 @@ import org.insa.graph.Graph;
public class StronglyConnectedComponentsData extends AbstractInputData { public class StronglyConnectedComponentsData extends AbstractInputData {
/** /**
* *
* @param graph * @param graph
*/ */
public StronglyConnectedComponentsData(Graph graph) { public StronglyConnectedComponentsData(Graph graph) {
super(graph); super(graph);
} }
} }

View file

@ -25,16 +25,16 @@ import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import org.insa.algo.AbstractAlgorithm; import org.insa.algo.AbstractAlgorithm;
import org.insa.algo.AbstractInputData;
import org.insa.algo.AbstractInputData.ArcFilter;
import org.insa.algo.AbstractInputData.Mode;
import org.insa.algo.AlgorithmFactory; import org.insa.algo.AlgorithmFactory;
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
import org.insa.algo.shortestpath.ShortestPathData.ArcFilter;
import org.insa.algo.shortestpath.ShortestPathData.Mode;
import org.insa.graph.Arc; import org.insa.graph.Arc;
import org.insa.graph.Node; import org.insa.graph.Node;
import org.insa.graph.RoadInformation.AccessMode; import org.insa.graph.RoadInformation.AccessMode;
import org.insa.graphics.NodesInputPanel.InputChangedEvent; import org.insa.graphics.NodesInputPanel.InputChangedEvent;
public class ShortestPathPanel extends JPanel { public class AlgorithmPanel extends JPanel {
/** /**
* *
@ -53,17 +53,17 @@ public class ShortestPathPanel extends JPanel {
protected static final int START_EVENT_ID = 0x1; protected static final int START_EVENT_ID = 0x1;
private final List<Node> nodes; private final List<Node> nodes;
private final Mode mode; private final AbstractInputData.Mode mode;
private final Class<? extends AbstractAlgorithm<?>> algoClass; private final Class<? extends AbstractAlgorithm<?>> algoClass;
private final ArcFilter arcFilter; private final AbstractInputData.ArcFilter arcFilter;
private final boolean graphicVisualization; private final boolean graphicVisualization;
private final boolean textualVisualization; private final boolean textualVisualization;
public StartActionEvent(Class<? extends AbstractAlgorithm<?>> algoClass, List<Node> nodes, Mode mode, public StartActionEvent(Class<? extends AbstractAlgorithm<?>> algoClass, List<Node> nodes, AbstractInputData.Mode mode,
ArcFilter arcFilter, boolean graphicVisualization, boolean textualVisualization) { AbstractInputData.ArcFilter arcFilter, boolean graphicVisualization, boolean textualVisualization) {
super(ShortestPathPanel.this, START_EVENT_ID, START_EVENT_COMMAND); super(AlgorithmPanel.this, START_EVENT_ID, START_EVENT_COMMAND);
this.nodes = nodes; this.nodes = nodes;
this.mode = mode; this.mode = mode;
this.algoClass = algoClass; this.algoClass = algoClass;
@ -82,14 +82,14 @@ public class ShortestPathPanel extends JPanel {
/** /**
* @return Mode associated with this event. * @return Mode associated with this event.
*/ */
public Mode getMode() { public AbstractInputData.Mode getMode() {
return this.mode; return this.mode;
} }
/** /**
* @return Arc filter associated with this event. * @return Arc filter associated with this event.
*/ */
public ArcFilter getArcFilter() { public AbstractInputData.ArcFilter getArcFilter() {
return this.arcFilter; return this.arcFilter;
} }
@ -120,7 +120,7 @@ public class ShortestPathPanel extends JPanel {
protected NodesInputPanel nodesInputPanel; protected NodesInputPanel nodesInputPanel;
// Solution // Solution
protected ShortestPathSolutionPanel solutionPanel; protected SolutionPanel solutionPanel;
// Component that can be enabled/disabled. // Component that can be enabled/disabled.
private ArrayList<JComponent> components = new ArrayList<>(); private ArrayList<JComponent> components = new ArrayList<>();
@ -132,7 +132,7 @@ public class ShortestPathPanel extends JPanel {
/** /**
*/ */
public ShortestPathPanel(Component parent) { public AlgorithmPanel(Component parent, Class<? extends AbstractAlgorithm<?>> baseAlgorithm) {
super(); super();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
@ -152,7 +152,7 @@ public class ShortestPathPanel extends JPanel {
// Add algorithm selection // Add algorithm selection
JComboBox<String> algoSelect = new JComboBox<>( JComboBox<String> algoSelect = new JComboBox<>(
AlgorithmFactory.getAlgorithmNames(ShortestPathAlgorithm.class).toArray(new String[0])); AlgorithmFactory.getAlgorithmNames(baseAlgorithm).toArray(new String[0]));
algoSelect.setBackground(Color.WHITE); algoSelect.setBackground(Color.WHITE);
algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT); algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT);
add(algoSelect); add(algoSelect);
@ -168,7 +168,7 @@ public class ShortestPathPanel extends JPanel {
add(this.nodesInputPanel); add(this.nodesInputPanel);
components.add(this.nodesInputPanel); components.add(this.nodesInputPanel);
JComboBox<ArcFilter> arcFilterSelect = new JComboBox<>(new ArcFilter[] { new ArcFilter() { JComboBox<AbstractInputData.ArcFilter> arcFilterSelect = new JComboBox<>(new AbstractInputData.ArcFilter[] { new AbstractInputData.ArcFilter() {
@Override @Override
public boolean isAllowed(Arc arc) { public boolean isAllowed(Arc arc) {
return true; return true;
@ -178,7 +178,7 @@ public class ShortestPathPanel extends JPanel {
public String toString() { public String toString() {
return "All arcs are allowed"; return "All arcs are allowed";
} }
}, new ArcFilter() { }, new AbstractInputData.ArcFilter() {
@Override @Override
public boolean isAllowed(Arc arc) { public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions().isAllowedFor(AccessMode.MOTORCAR) return arc.getRoadInformation().getAccessRestrictions().isAllowedFor(AccessMode.MOTORCAR)
@ -250,7 +250,7 @@ public class ShortestPathPanel extends JPanel {
add(modeAndObserverPanel); add(modeAndObserverPanel);
solutionPanel = new ShortestPathSolutionPanel(parent); solutionPanel = new SolutionPanel(parent);
solutionPanel.setAlignmentX(Component.LEFT_ALIGNMENT); solutionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
solutionPanel.setVisible(false); solutionPanel.setVisible(false);
add(Box.createVerticalStrut(10)); add(Box.createVerticalStrut(10));
@ -265,13 +265,12 @@ public class ShortestPathPanel extends JPanel {
startAlgoButton.addActionListener(new ActionListener() { startAlgoButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Mode mode = lengthModeButton.isSelected() ? Mode.LENGTH : Mode.TIME; AbstractInputData.Mode mode = lengthModeButton.isSelected() ? AbstractInputData.Mode.LENGTH : AbstractInputData.Mode.TIME;
for (ActionListener lis: startActionListeners) { for (ActionListener lis: startActionListeners) {
lis.actionPerformed(new StartActionEvent( lis.actionPerformed(new StartActionEvent(
AlgorithmFactory.getAlgorithmClass(ShortestPathAlgorithm.class, AlgorithmFactory.getAlgorithmClass(baseAlgorithm, (String) algoSelect.getSelectedItem()),
(String) algoSelect.getSelectedItem()), nodesInputPanel.getNodeForInputs(), mode, (AbstractInputData.ArcFilter) arcFilterSelect.getSelectedItem(),
nodesInputPanel.getNodeForInputs(), mode, (ArcFilter) arcFilterSelect.getSelectedItem(),
graphicObserver.isSelected(), textObserver.isSelected())); graphicObserver.isSelected(), textObserver.isSelected()));
} }
} }

View file

@ -58,7 +58,7 @@ import org.insa.graph.io.BinaryGraphReaderInsa2018;
import org.insa.graph.io.BinaryPathReader; import org.insa.graph.io.BinaryPathReader;
import org.insa.graph.io.GraphReader; import org.insa.graph.io.GraphReader;
import org.insa.graph.io.MapMismatchException; import org.insa.graph.io.MapMismatchException;
import org.insa.graphics.ShortestPathPanel.StartActionEvent; import org.insa.graphics.AlgorithmPanel.StartActionEvent;
import org.insa.graphics.drawing.BasicGraphPalette; import org.insa.graphics.drawing.BasicGraphPalette;
import org.insa.graphics.drawing.BlackAndWhiteGraphPalette; import org.insa.graphics.drawing.BlackAndWhiteGraphPalette;
import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.Drawing;
@ -107,7 +107,7 @@ public class MainWindow extends JFrame {
private JSplitPane mainPanel; private JSplitPane mainPanel;
// Shortest path panel // Shortest path panel
private ShortestPathPanel spPanel; private AlgorithmPanel spPanel;
// List of items that cannot be used without a graph // List of items that cannot be used without a graph
private ArrayList<JMenuItem> graphLockItems = new ArrayList<JMenuItem>(); private ArrayList<JMenuItem> graphLockItems = new ArrayList<JMenuItem>();
@ -148,7 +148,7 @@ public class MainWindow extends JFrame {
this.drawing = this.basicDrawing; this.drawing = this.basicDrawing;
spPanel = new ShortestPathPanel(this); spPanel = new AlgorithmPanel(this, ShortestPathAlgorithm.class);
spPanel.addStartActionListener(new ActionListener() { spPanel.addStartActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {

View file

@ -4,48 +4,45 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.BufferedOutputStream; import java.lang.reflect.InvocationTargetException;
import java.io.DataOutputStream; import java.lang.reflect.Method;
import java.io.File; import java.util.ArrayList;
import java.io.FileOutputStream; import java.util.List;
import java.io.IOException;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.CompoundBorder; import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import org.insa.algo.shortestpath.ShortestPathData; import org.insa.algo.AbstractInputData;
import org.insa.algo.shortestpath.ShortestPathData.Mode; import org.insa.algo.AbstractSolution;
import org.insa.algo.shortestpath.ShortestPathSolution; import org.insa.algo.shortestpath.ShortestPathSolution;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.io.BinaryPathWriter; import org.insa.graph.Path;
import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.Drawing;
import org.insa.graphics.drawing.overlays.PathOverlay; import org.insa.graphics.drawing.overlays.PathOverlay;
public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener { public class SolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener {
/** /**
* *
*/ */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private class ShortestPathBundle { private class SolutionBundle {
// Solution // Solution
private final ShortestPathSolution solution; private final AbstractSolution solution;
// Path Overlay (not final due to redraw) // Path Overlay (not final due to redraw)
private PathOverlay overlay = null; private List<PathOverlay> overlays = new ArrayList<>();
/** /**
* Create a new bundle with the given solution and create a new overlay * Create a new bundle with the given solution and create a new overlay
@ -54,72 +51,88 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
* @param solution Solution for this bundle, must not be null. * @param solution Solution for this bundle, must not be null.
* *
*/ */
public ShortestPathBundle(ShortestPathSolution solution) { public SolutionBundle(AbstractSolution solution) {
this.solution = solution; this.solution = solution;
if (this.solution.isFeasible()) { this.overlays = createOverlaysFromSolution();
this.overlay = drawing.drawPath(this.solution.getPath());
}
} }
/** /**
* @return Solution associated with this bundle. * @return Solution associated with this bundle.
*/ */
public ShortestPathSolution getSolution() { public AbstractSolution getSolution() {
return this.solution; return this.solution;
} }
/** /**
* @return Data assocaited with this bundle. * @return Data assocaited with this bundle.
*/ */
public ShortestPathData getData() { public AbstractInputData getData() {
return this.solution.getInputData(); return this.solution.getInputData();
} }
/** /**
* @return Overlay associated with this bundle, or null. * @return Overlays associated with this bundle, or null.
*/ */
public PathOverlay getOverlay() { public List<PathOverlay> getOverlays() {
return this.overlay; return this.overlays;
} }
/** /**
* Re-draw the current overlay (if any) on the new drawing. * Re-draw the current overlay (if any) on the new drawing.
* *
*/ */
public void updateOverlay(Drawing newDrawing) { public void updateOverlays() {
if (this.overlay != null) { List<PathOverlay> oldOverlays = this.overlays;
PathOverlay oldOverlay = this.overlay; this.overlays = createOverlaysFromSolution();
this.overlay = newDrawing.drawPath(this.solution.getPath()); for (int i = 0; i < oldOverlays.size(); ++i) {
this.overlay.setVisible(oldOverlay.isVisible()); oldOverlays.get(i).delete();
oldOverlay.delete();
} }
} }
private List<PathOverlay> createOverlaysFromSolution() {
List<PathOverlay> overlays = new ArrayList<>();
if (solution.isFeasible()) {
Method[] methods = this.solution.getClass().getDeclaredMethods();
for (Method method: methods) {
if (method.getReturnType().equals(Path.class) && method.getParameterCount() == 0) {
try {
Path path = (Path) method.invoke(this.solution);
overlays.add(drawing.drawPath(path));
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// This has been check before, so should never happen...
e.printStackTrace();
}
}
}
}
return overlays;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
public String toString() { public String toString() {
return "Shortest-path from #" + this.getData().getOrigin().getId() + " to #" return getData().toString();
+ this.getData().getDestination().getId() + " [" + this.getData().getMode().toString().toLowerCase()
+ "]";
} }
} }
// Solution // Solution
private Drawing drawing; private Drawing drawing;
// Solution selector // Solution selector
private final JComboBox<ShortestPathBundle> solutionSelect; private final JComboBox<SolutionBundle> solutionSelect;
// Map solution -> panel // Map solution -> panel
private final JTextArea informationPanel; private final JTextArea informationPanel;
// Current bundle // Current bundle
private ShortestPathBundle currentBundle = null; private SolutionBundle currentBundle = null;
public ShortestPathSolutionPanel(Component parent) { public SolutionPanel(Component parent) {
super(); super();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.LIGHT_GRAY), setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.LIGHT_GRAY),
@ -147,17 +160,15 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
PathOverlay overlay = currentBundle.getOverlay(); for (PathOverlay overlay: currentBundle.getOverlays()) {
if (overlay == null) { if (overlay.isVisible()) {
return; overlay.setVisible(false);
} clearButton.setText("Show");
if (overlay.isVisible()) { }
overlay.setVisible(false); else {
clearButton.setText("Show"); overlay.setVisible(true);
} clearButton.setText("Hide");
else { }
overlay.setVisible(true);
clearButton.setText("Hide");
} }
} }
}); });
@ -166,26 +177,29 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
saveButton.addActionListener(new ActionListener() { saveButton.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String filepath = System.getProperty("user.dir"); // String filepath = System.getProperty("user.dir");
filepath += File.separator + String.format("path_%s_%d_%d.path", // filepath += File.separator + String.format("path_%s_%d_%d.path",
currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]", "_"), // currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]",
currentBundle.getData().getOrigin().getId(), currentBundle.getData().getDestination().getId()); // "_"),
JFileChooser fileChooser = new JFileChooser(); // currentBundle.getData().getOrigin().getId(),
fileChooser.setSelectedFile(new File(filepath)); // currentBundle.getData().getDestination().getId());
fileChooser.setApproveButtonText("Save"); // JFileChooser fileChooser = new JFileChooser();
// fileChooser.setSelectedFile(new File(filepath));
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) { // fileChooser.setApproveButtonText("Save");
File file = fileChooser.getSelectedFile(); //
try { // if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
BinaryPathWriter writer = new BinaryPathWriter( // File file = fileChooser.getSelectedFile();
new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))); // try {
writer.writePath(currentBundle.getSolution().getPath()); // BinaryPathWriter writer = new BinaryPathWriter(
} // new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
catch (IOException e1) { // writer.writePath(currentBundle.getSolution().getPath());
JOptionPane.showMessageDialog(parent, "Unable to write path to the selected file."); // }
e1.printStackTrace(); // catch (IOException e1) {
} // JOptionPane.showMessageDialog(parent, "Unable to write path to the selected
} // file.");
// e1.printStackTrace();
// }
// }
} }
}); });
@ -200,23 +214,25 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
solutionSelect.addActionListener(new ActionListener() { solutionSelect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
ShortestPathBundle bundle = (ShortestPathBundle) solutionSelect.getSelectedItem(); SolutionBundle bundle = (SolutionBundle) solutionSelect.getSelectedItem();
// Handle case when the JComboBox is empty. // Handle case when the JComboBox is empty.
if (bundle == null) { if (bundle == null) {
return; return;
} }
if (currentBundle != null && currentBundle.getOverlay() != null) { if (currentBundle != null) {
currentBundle.getOverlay().setVisible(false); for (PathOverlay overlay: currentBundle.getOverlays()) {
overlay.setVisible(false);
}
} }
updateInformationLabel(bundle); updateInformationLabel(bundle);
buttonPanel.setVisible(bundle.getSolution().isFeasible()); buttonPanel.setVisible(bundle.getSolution().isFeasible());
clearButton.setText(bundle.getSolution().isFeasible() ? "Hide" : "Show"); clearButton.setText(bundle.getSolution().isFeasible() ? "Hide" : "Show");
if (bundle.getOverlay() != null) { for (PathOverlay overlay: bundle.getOverlays()) {
bundle.getOverlay().setVisible(true); overlay.setVisible(true);
} }
currentBundle = bundle; currentBundle = bundle;
@ -226,31 +242,13 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
} }
public void addSolution(ShortestPathSolution solution) { public void addSolution(ShortestPathSolution solution) {
ShortestPathBundle bundle = new ShortestPathBundle(solution); SolutionBundle bundle = new SolutionBundle(solution);
solutionSelect.addItem(bundle); solutionSelect.addItem(bundle);
solutionSelect.setSelectedItem(bundle); solutionSelect.setSelectedItem(bundle);
} }
protected void updateInformationLabel(ShortestPathBundle bundle) { protected void updateInformationLabel(SolutionBundle bundle) {
ShortestPathData data = bundle.getData(); informationPanel.setText(bundle.getSolution().toString());
String info = null;
if (!bundle.getSolution().isFeasible()) {
info = String.format("No path found from node #%d to node #%d.", data.getOrigin().getId(),
data.getDestination().getId());
}
else {
info = String.format("Found a path from node #%d to node #%d", data.getOrigin().getId(),
data.getDestination().getId());
if (data.getMode() == Mode.LENGTH) {
info = String.format("%s, %.4f kilometers.", info,
(bundle.getSolution().getPath().getLength() / 1000.0));
}
else {
info = String.format("%s, %.4f minutes.", info,
(bundle.getSolution().getPath().getMinimumTravelTime() / 60.0));
}
}
informationPanel.setText(info);
} }
@Override @Override
@ -263,19 +261,19 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
solutionSelect.actionPerformed(null); solutionSelect.actionPerformed(null);
} }
else { else {
ShortestPathBundle bundle = (ShortestPathBundle) this.solutionSelect.getSelectedItem(); SolutionBundle bundle = (SolutionBundle) this.solutionSelect.getSelectedItem();
if (bundle != null && bundle.getOverlay() != null) { if (bundle != null) {
bundle.getOverlay().setVisible(false); for (PathOverlay overlay: bundle.getOverlays()) {
overlay.setVisible(false);
}
} }
} }
} }
@Override @Override
public void newGraphLoaded(Graph graph) { public void newGraphLoaded(Graph graph) {
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) { for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
PathOverlay overlay = this.solutionSelect.getItemAt(i).getOverlay(); for (PathOverlay overlay: this.solutionSelect.getItemAt(i).getOverlays()) {
if (overlay != null) {
overlay.delete(); overlay.delete();
} }
} }
@ -294,7 +292,7 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
@Override @Override
public void onRedrawRequest() { public void onRedrawRequest() {
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) { for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
this.solutionSelect.getItemAt(i).updateOverlay(drawing); this.solutionSelect.getItemAt(i).updateOverlays();
} }
} }