Add shortest path panel.
This commit is contained in:
parent
b6eb6d97ea
commit
6bc633e5bb
3 changed files with 633 additions and 21 deletions
|
@ -4,6 +4,8 @@ import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
@ -34,10 +36,11 @@ import javax.swing.Timer;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
|
||||||
|
import org.insa.algo.shortestpath.AStarAlgorithm;
|
||||||
import org.insa.algo.shortestpath.BellmanFordAlgorithm;
|
import org.insa.algo.shortestpath.BellmanFordAlgorithm;
|
||||||
|
import org.insa.algo.shortestpath.DijkstraAlgorithm;
|
||||||
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
|
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
|
||||||
import org.insa.algo.shortestpath.ShortestPathData;
|
import org.insa.algo.shortestpath.ShortestPathData;
|
||||||
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;
|
||||||
|
@ -45,7 +48,6 @@ 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.Path;
|
import org.insa.graph.Path;
|
||||||
import org.insa.graph.io.BinaryGraphReader;
|
import org.insa.graph.io.BinaryGraphReader;
|
||||||
import org.insa.graph.io.BinaryGraphReaderV2;
|
import org.insa.graph.io.BinaryGraphReaderV2;
|
||||||
|
@ -53,7 +55,7 @@ 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.graph.io.Openfile;
|
import org.insa.graph.io.Openfile;
|
||||||
import org.insa.graphics.MultiPointsClickListener.CallableWithNodes;
|
import org.insa.graphics.ShortestPathPanel.StartActionEvent;
|
||||||
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;
|
||||||
|
@ -88,6 +90,9 @@ public class MainWindow extends JFrame {
|
||||||
// Main panel.
|
// Main panel.
|
||||||
private JSplitPane mainPanel;
|
private JSplitPane mainPanel;
|
||||||
|
|
||||||
|
// Shortest path panel
|
||||||
|
private ShortestPathPanel spPanel;
|
||||||
|
|
||||||
// List of item for the top menus.
|
// List of item for the top menus.
|
||||||
private JMenuItem openMapItem;
|
private JMenuItem openMapItem;
|
||||||
|
|
||||||
|
@ -158,12 +163,24 @@ public class MainWindow extends JFrame {
|
||||||
this.logStream = new StreamCapturer(infoPanel);
|
this.logStream = new StreamCapturer(infoPanel);
|
||||||
this.printStream = new PrintStream(this.logStream);
|
this.printStream = new PrintStream(this.logStream);
|
||||||
|
|
||||||
|
JPanel rightComponent = new JPanel();
|
||||||
|
rightComponent.setLayout(new GridBagLayout());
|
||||||
|
|
||||||
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 1;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.weighty = 1;
|
||||||
|
c.fill = GridBagConstraints.BOTH;
|
||||||
|
c.gridheight = GridBagConstraints.REMAINDER;
|
||||||
|
rightComponent.add(new JScrollPane(infoPanel), c);
|
||||||
|
|
||||||
mainPanel.setResizeWeight(0.8);
|
mainPanel.setResizeWeight(0.8);
|
||||||
mainPanel.setDividerSize(5);
|
mainPanel.setDividerSize(5);
|
||||||
|
|
||||||
mainPanel.setBackground(Color.WHITE);
|
mainPanel.setBackground(Color.WHITE);
|
||||||
mainPanel.setLeftComponent((Component) this.drawing);
|
mainPanel.setLeftComponent((Component) this.drawing);
|
||||||
mainPanel.setRightComponent(new JScrollPane(infoPanel));
|
mainPanel.setRightComponent(rightComponent);
|
||||||
this.add(mainPanel, BorderLayout.CENTER);
|
this.add(mainPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Top Panel
|
// Top Panel
|
||||||
|
@ -201,6 +218,7 @@ public class MainWindow extends JFrame {
|
||||||
threadTimer.stop();
|
threadTimer.stop();
|
||||||
threadPanel.setVisible(false);
|
threadPanel.setVisible(false);
|
||||||
currentThread.setThread(null);
|
currentThread.setThread(null);
|
||||||
|
spPanel.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
|
private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
|
||||||
|
@ -422,33 +440,49 @@ public class MainWindow extends JFrame {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Shortest path
|
// Shortest path
|
||||||
JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)");
|
JMenuItem spItem = new JMenuItem("Shortest Path");
|
||||||
bellmanItem.addActionListener(baf.createBlockingAction(new ActionListener() {
|
spItem.addActionListener(baf.createBlockingAction(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", "Mode selection",
|
int dividerLocation = mainPanel.getDividerLocation();
|
||||||
JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, Mode.values(), Mode.LENGTH);
|
spPanel = new ShortestPathPanel(drawing, graph);
|
||||||
|
|
||||||
if (idx != -1) {
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
Mode mode = Mode.values()[idx];
|
c.gridx = 0;
|
||||||
clickAdapter.enable(2, new CallableWithNodes() {
|
c.gridy = 0;
|
||||||
@Override
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
public void call(ArrayList<Node> nodes) {
|
((JPanel) mainPanel.getRightComponent()).add(spPanel, c);
|
||||||
launchShortestPathThread(new BellmanFordAlgorithm(
|
|
||||||
new ShortestPathData(graph, nodes.get(0), nodes.get(1), mode)));
|
mainPanel.setDividerLocation(dividerLocation);
|
||||||
|
|
||||||
|
spPanel.addStartActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
});
|
else if (evt.getAlgorithmClass() == DijkstraAlgorithm.class) {
|
||||||
}
|
spAlgorithm = new DijkstraAlgorithm(data);
|
||||||
|
}
|
||||||
|
else if (evt.getAlgorithmClass() == AStarAlgorithm.class) {
|
||||||
|
spAlgorithm = new AStarAlgorithm(data);
|
||||||
|
}
|
||||||
|
spPanel.setEnabled(false);
|
||||||
|
launchShortestPathThread(spAlgorithm);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
graphLockItems.add(wccItem);
|
graphLockItems.add(wccItem);
|
||||||
graphLockItems.add(bellmanItem);
|
graphLockItems.add(spItem);
|
||||||
|
|
||||||
algoMenu.add(wccItem);
|
algoMenu.add(wccItem);
|
||||||
algoMenu.addSeparator();
|
algoMenu.addSeparator();
|
||||||
algoMenu.add(bellmanItem);
|
algoMenu.add(spItem);
|
||||||
// algoMenu.add(djikstraItem);
|
|
||||||
// algoMenu.add(aStarItem);
|
|
||||||
|
|
||||||
// Create the menu bar.
|
// Create the menu bar.
|
||||||
JMenuBar menuBar = new JMenuBar();
|
JMenuBar menuBar = new JMenuBar();
|
||||||
|
|
307
src/main/org/insa/graphics/NodesInputPanel.java
Normal file
307
src/main/org/insa/graphics/NodesInputPanel.java
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
package org.insa.graphics;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridBagConstraints;
|
||||||
|
import java.awt.GridBagLayout;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
|
import org.insa.graph.Graph;
|
||||||
|
import org.insa.graph.Node;
|
||||||
|
import org.insa.graph.Point;
|
||||||
|
import org.insa.graphics.drawing.Drawing;
|
||||||
|
import org.insa.graphics.drawing.DrawingClickListener;
|
||||||
|
import org.insa.graphics.drawing.MarkerTracker;
|
||||||
|
|
||||||
|
public class NodesInputPanel extends JPanel implements DrawingClickListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -1638302070013027690L;
|
||||||
|
|
||||||
|
private static final Color DEFAULT_MARKER_COLOR = Color.BLUE;
|
||||||
|
|
||||||
|
public class InputChangedEvent extends ActionEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 3440024811352247731L;
|
||||||
|
|
||||||
|
protected static final String ALL_INPUT_FILLED_EVENT_COMMAND = "allInputFilled";
|
||||||
|
|
||||||
|
protected static final int ALL_INPUT_FILLED_EVENT_ID = 0x1;
|
||||||
|
|
||||||
|
// List of nodes
|
||||||
|
List<Node> nodes;
|
||||||
|
|
||||||
|
public InputChangedEvent(List<Node> nodes2) {
|
||||||
|
super(NodesInputPanel.this, ALL_INPUT_FILLED_EVENT_ID, ALL_INPUT_FILLED_EVENT_COMMAND);
|
||||||
|
this.nodes = nodes2;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Node> getNodes() {
|
||||||
|
return Collections.unmodifiableList(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node inputs and markers.
|
||||||
|
private ArrayList<JTextField> nodeInputs = new ArrayList<>();
|
||||||
|
private Map<JTextField, MarkerTracker> markerTrackers = new IdentityHashMap<JTextField, MarkerTracker>();
|
||||||
|
|
||||||
|
// Component that can be enabled/disabled.
|
||||||
|
private ArrayList<JComponent> components = new ArrayList<>();
|
||||||
|
private int inputToFillIndex;
|
||||||
|
|
||||||
|
// ActionListener called when all inputs are filled.
|
||||||
|
private ArrayList<ActionListener> inputChangeListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
// Graph & Drawing.
|
||||||
|
private Graph graph;
|
||||||
|
private Drawing drawing;
|
||||||
|
|
||||||
|
public NodesInputPanel(Drawing drawing, Graph graph) {
|
||||||
|
super(new GridBagLayout());
|
||||||
|
this.graph = graph;
|
||||||
|
this.drawing = drawing;
|
||||||
|
initInputToFill();
|
||||||
|
drawing.addDrawingClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInputChangedListener(ActionListener listener) {
|
||||||
|
inputChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
for (JComponent component: components) {
|
||||||
|
component.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
super.setEnabled(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
// Enable: Check if there is an input to fill, otherwize find the next one.
|
||||||
|
if (getInputToFill() == null) {
|
||||||
|
nextInputToFill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Disable, next input to fill = -1.
|
||||||
|
this.inputToFillIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
for (JTextField field: nodeInputs) {
|
||||||
|
field.setText("");
|
||||||
|
}
|
||||||
|
initInputToFill();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTextField(String label) {
|
||||||
|
addTextField(label, DEFAULT_MARKER_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTextField(String label, Color markerColor) {
|
||||||
|
|
||||||
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
|
c.insets = new Insets(3, 3, 3, 3);
|
||||||
|
|
||||||
|
JLabel jLabel = new JLabel(label);
|
||||||
|
jLabel.setFont(jLabel.getFont().deriveFont(~Font.BOLD));
|
||||||
|
JTextField textField = new JTextField();
|
||||||
|
jLabel.setLabelFor(textField);
|
||||||
|
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = nodeInputs.size();
|
||||||
|
c.weightx = 0;
|
||||||
|
c.gridwidth = 1;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
add(jLabel, c);
|
||||||
|
|
||||||
|
c.gridx = 1;
|
||||||
|
c.gridy = nodeInputs.size();
|
||||||
|
c.weightx = 1;
|
||||||
|
c.gridwidth = 1;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
add(textField, c);
|
||||||
|
|
||||||
|
JButton clearButton = new JButton("Clear");
|
||||||
|
c.gridx = 2;
|
||||||
|
c.gridy = nodeInputs.size();
|
||||||
|
c.weightx = 0;
|
||||||
|
c.gridwidth = 1;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
add(clearButton, c);
|
||||||
|
|
||||||
|
JButton clickButton = new JButton("Click");
|
||||||
|
c.gridx = 3;
|
||||||
|
c.gridy = nodeInputs.size();
|
||||||
|
c.weightx = 0;
|
||||||
|
c.gridwidth = 1;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
add(clickButton, c);
|
||||||
|
|
||||||
|
// Did not find something easier that this... ?
|
||||||
|
textField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
insertUpdate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
insertUpdate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
|
||||||
|
// Draw marker if possible
|
||||||
|
Node curnode = getNodeForInput(textField);
|
||||||
|
MarkerTracker tracker = markerTrackers.getOrDefault(textField, null);
|
||||||
|
if (curnode != null) {
|
||||||
|
if (tracker == null) {
|
||||||
|
tracker = drawing.drawMarker(curnode.getPoint(), markerColor);
|
||||||
|
markerTrackers.put(textField, tracker);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tracker.moveTo(curnode.getPoint());
|
||||||
|
}
|
||||||
|
tracker.setVisible(true);
|
||||||
|
}
|
||||||
|
else if (tracker != null) {
|
||||||
|
tracker.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create array of nodes
|
||||||
|
List<Node> nodes = getNodeForInputs();
|
||||||
|
|
||||||
|
// Trigger change event.
|
||||||
|
for (ActionListener lis: inputChangeListeners) {
|
||||||
|
lis.actionPerformed(new InputChangedEvent(nodes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clearButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
textField.setText("");
|
||||||
|
setInputToFill(textField);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clickButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
setInputToFill(textField);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeInputs.add(textField);
|
||||||
|
components.add(textField);
|
||||||
|
components.add(clearButton);
|
||||||
|
components.add(clickButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The node for the given text field, or null if the content of the text
|
||||||
|
* field is invalid.
|
||||||
|
*/
|
||||||
|
protected Node getNodeForInput(JTextField textfield) {
|
||||||
|
try {
|
||||||
|
Node node = graph.getNodes().get(Integer.valueOf(textfield.getText().trim()));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of nodes associated with the input. Some nodes may be null if
|
||||||
|
* their associated input is invalid.
|
||||||
|
*/
|
||||||
|
public List<Node> getNodeForInputs() {
|
||||||
|
List<Node> nodes = new ArrayList<>(nodeInputs.size());
|
||||||
|
for (JTextField input: nodeInputs) {
|
||||||
|
nodes.add(getNodeForInput(input));
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next input that should be filled by a click, or null if none should
|
||||||
|
* be filled.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected JTextField getInputToFill() {
|
||||||
|
if (inputToFillIndex < 0 || inputToFillIndex >= nodeInputs.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return nodeInputs.get(inputToFillIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the next input to fill.
|
||||||
|
*/
|
||||||
|
protected void initInputToFill() {
|
||||||
|
inputToFillIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the next input to fill to the given text field.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
*/
|
||||||
|
protected void setInputToFill(JTextField input) {
|
||||||
|
inputToFillIndex = nodeInputs.indexOf(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the next input to fill, if any.
|
||||||
|
*/
|
||||||
|
protected void nextInputToFill() {
|
||||||
|
boolean found = false;
|
||||||
|
for (int i = 1; i < nodeInputs.size() && !found; ++i) {
|
||||||
|
int nextIndex = (i + inputToFillIndex) % nodeInputs.size();
|
||||||
|
JTextField input = nodeInputs.get(nextIndex);
|
||||||
|
if (input.getText().trim().isEmpty()) {
|
||||||
|
inputToFillIndex = nextIndex;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
inputToFillIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(Point point) {
|
||||||
|
Node node = graph.findClosestNode(point);
|
||||||
|
JTextField input = getInputToFill();
|
||||||
|
if (input != null) {
|
||||||
|
input.setText(String.valueOf(node.getId()));
|
||||||
|
nextInputToFill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
271
src/main/org/insa/graphics/ShortestPathPanel.java
Normal file
271
src/main/org/insa/graphics/ShortestPathPanel.java
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
package org.insa.graphics;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
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.ShortestPathData.Mode;
|
||||||
|
import org.insa.graph.Graph;
|
||||||
|
import org.insa.graph.Node;
|
||||||
|
import org.insa.graph.io.BinaryGraphReaderV2;
|
||||||
|
import org.insa.graph.io.GraphReader;
|
||||||
|
import org.insa.graph.io.Openfile;
|
||||||
|
import org.insa.graphics.NodesInputPanel.InputChangedEvent;
|
||||||
|
import org.insa.graphics.drawing.BasicDrawing;
|
||||||
|
import org.insa.graphics.drawing.Drawing;
|
||||||
|
|
||||||
|
public class ShortestPathPanel extends JPanel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 406148710808045035L;
|
||||||
|
|
||||||
|
public class StartActionEvent extends ActionEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 4090710269781229078L;
|
||||||
|
|
||||||
|
protected static final String START_EVENT_COMMAND = "allInputFilled";
|
||||||
|
|
||||||
|
protected static final int START_EVENT_ID = 0x1;
|
||||||
|
|
||||||
|
private final Node origin, destination;
|
||||||
|
private final Mode mode;
|
||||||
|
private final Class<? extends ShortestPathAlgorithm> algoClass;
|
||||||
|
|
||||||
|
public StartActionEvent(Class<? extends ShortestPathAlgorithm> algoClass, Node origin, Node destination,
|
||||||
|
Mode mode) {
|
||||||
|
super(ShortestPathPanel.this, START_EVENT_ID, START_EVENT_COMMAND);
|
||||||
|
this.origin = origin;
|
||||||
|
this.destination = destination;
|
||||||
|
this.mode = mode;
|
||||||
|
this.algoClass = algoClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Origin node associated with this event.
|
||||||
|
*/
|
||||||
|
public Node getOrigin() {
|
||||||
|
return this.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Destination node associated with this event.
|
||||||
|
*/
|
||||||
|
public Node getDestination() {
|
||||||
|
return this.destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Mode associated with this event.
|
||||||
|
*/
|
||||||
|
public Mode getMode() {
|
||||||
|
return this.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Algorithm class associated with this event.
|
||||||
|
*/
|
||||||
|
public Class<? extends ShortestPathAlgorithm> getAlgorithmClass() {
|
||||||
|
return this.algoClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map between algorithm names and class, see end of this class for
|
||||||
|
// initialization.
|
||||||
|
private static Map<String, Class<? extends ShortestPathAlgorithm>> SHORTEST_PATH_ALGORITHMS = new HashMap<>();
|
||||||
|
|
||||||
|
// Input panels for node.
|
||||||
|
private NodesInputPanel nodesInputPanel;
|
||||||
|
|
||||||
|
// Component that can be enabled/disabled.
|
||||||
|
private ArrayList<JComponent> components = new ArrayList<>();
|
||||||
|
|
||||||
|
// Start listeners
|
||||||
|
List<ActionListener> startActionListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public ShortestPathPanel(Drawing drawing, Graph graph) {
|
||||||
|
super();
|
||||||
|
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||||
|
|
||||||
|
setBorder(new EmptyBorder(15, 15, 15, 15));
|
||||||
|
|
||||||
|
// Set title.
|
||||||
|
JLabel titleLabel = new JLabel("Shortest-Path");
|
||||||
|
titleLabel.setBackground(Color.RED);
|
||||||
|
titleLabel.setHorizontalAlignment(JLabel.LEFT);
|
||||||
|
titleLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
Font font = titleLabel.getFont();
|
||||||
|
font = font.deriveFont(Font.BOLD, 18);
|
||||||
|
titleLabel.setFont(font);
|
||||||
|
add(titleLabel);
|
||||||
|
|
||||||
|
add(Box.createVerticalStrut(8));
|
||||||
|
|
||||||
|
// Add algorithm selection
|
||||||
|
JComboBox<String> algoSelect = new JComboBox<>(SHORTEST_PATH_ALGORITHMS.keySet().toArray(new String[0]));
|
||||||
|
algoSelect.setBackground(Color.WHITE);
|
||||||
|
algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
add(algoSelect);
|
||||||
|
components.add(algoSelect);
|
||||||
|
|
||||||
|
// Add inputs for node.
|
||||||
|
this.nodesInputPanel = new NodesInputPanel(drawing, graph);
|
||||||
|
this.nodesInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
nodesInputPanel.addTextField("Origin: ", new Color(57, 172, 115));
|
||||||
|
nodesInputPanel.addTextField("Destination: ", new Color(255, 77, 77));
|
||||||
|
|
||||||
|
add(this.nodesInputPanel);
|
||||||
|
components.add(this.nodesInputPanel);
|
||||||
|
|
||||||
|
// Add mode selection
|
||||||
|
JPanel modePanel = new JPanel();
|
||||||
|
modePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
modePanel.setLayout(new BoxLayout(modePanel, BoxLayout.LINE_AXIS));
|
||||||
|
JRadioButton lengthModeButton = new JRadioButton("Length");
|
||||||
|
lengthModeButton.setSelected(true);
|
||||||
|
JRadioButton timeModeButton = new JRadioButton("Time");
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
group.add(lengthModeButton);
|
||||||
|
group.add(timeModeButton);
|
||||||
|
modePanel.add(Box.createHorizontalGlue());
|
||||||
|
modePanel.add(lengthModeButton);
|
||||||
|
modePanel.add(Box.createHorizontalGlue());
|
||||||
|
modePanel.add(timeModeButton);
|
||||||
|
modePanel.add(Box.createHorizontalGlue());
|
||||||
|
|
||||||
|
add(modePanel);
|
||||||
|
components.add(timeModeButton);
|
||||||
|
components.add(lengthModeButton);
|
||||||
|
|
||||||
|
// Bottom panel
|
||||||
|
JPanel bottomPanel = new JPanel();
|
||||||
|
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
|
||||||
|
JButton startAlgoButton = new JButton("Start");
|
||||||
|
startAlgoButton.setEnabled(false);
|
||||||
|
startAlgoButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
List<Node> nodes = nodesInputPanel.getNodeForInputs();
|
||||||
|
Node origin = nodes.get(0), destination = nodes.get(1);
|
||||||
|
Mode mode = lengthModeButton.isSelected() ? Mode.LENGTH : Mode.TIME;
|
||||||
|
|
||||||
|
for (ActionListener lis: startActionListeners) {
|
||||||
|
lis.actionPerformed(new StartActionEvent(SHORTEST_PATH_ALGORITHMS.get(algoSelect.getSelectedItem()),
|
||||||
|
origin, destination, mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton hideButton = new JButton("Hide");
|
||||||
|
hideButton.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
nodesInputPanel.setEnabled(false);
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bottomPanel.add(startAlgoButton);
|
||||||
|
bottomPanel.add(Box.createHorizontalGlue());
|
||||||
|
bottomPanel.add(hideButton);
|
||||||
|
|
||||||
|
components.add(startAlgoButton);
|
||||||
|
components.add(hideButton);
|
||||||
|
|
||||||
|
bottomPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
|
||||||
|
add(Box.createVerticalStrut(8));
|
||||||
|
add(bottomPanel);
|
||||||
|
|
||||||
|
nodesInputPanel.addInputChangedListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
InputChangedEvent evt = (InputChangedEvent) e;
|
||||||
|
boolean allNotNull = true;
|
||||||
|
for (Node node: evt.getNodes()) {
|
||||||
|
if (node == null) {
|
||||||
|
allNotNull = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startAlgoButton.setEnabled(allNotNull);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
super.setEnabled(enabled);
|
||||||
|
nodesInputPanel.setEnabled(enabled);
|
||||||
|
for (JComponent component: components) {
|
||||||
|
component.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new start action listener to this class.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void addStartActionListener(ActionListener listener) {
|
||||||
|
this.startActionListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
SHORTEST_PATH_ALGORITHMS.put("Bellman-Ford", BellmanFordAlgorithm.class);
|
||||||
|
SHORTEST_PATH_ALGORITHMS.put("Dijkstra", DijkstraAlgorithm.class);
|
||||||
|
SHORTEST_PATH_ALGORITHMS.put("A*", AStarAlgorithm.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
|
String nomcarte = "../BE_Graphe_Maps/morbihan3.mapgr";
|
||||||
|
GraphReader reader = new BinaryGraphReaderV2(Openfile.open(nomcarte));
|
||||||
|
Graph graph = reader.read();
|
||||||
|
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
frame.setLayout(new BorderLayout());
|
||||||
|
JSplitPane p = new JSplitPane();
|
||||||
|
BasicDrawing drawing = new BasicDrawing();
|
||||||
|
JPanel pane = new ShortestPathPanel(drawing, graph);
|
||||||
|
p.setLeftComponent(drawing);
|
||||||
|
p.setRightComponent(pane);
|
||||||
|
p.setResizeWeight(0.8);
|
||||||
|
frame.add(p, BorderLayout.CENTER);
|
||||||
|
frame.show();
|
||||||
|
frame.setSize(800, 600);
|
||||||
|
// pane.setSize(new Dimension(400, 0));
|
||||||
|
|
||||||
|
drawing.drawGraph(graph);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue