diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java index 03843f7..dae8530 100644 --- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java +++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java @@ -32,4 +32,26 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution { return components; } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + int nIsolated = 0; + int nGt10 = 0; + for (ArrayList component: components) { + if (component.size() == 1) { + nIsolated += 1; + } + else if (component.size() > 10) { + nGt10 += 1; + } + } + return "Found " + components.size() + " components (" + nGt10 + " with more than 10 nodes, " + + nIsolated + " isolated nodes) in " + getSolvingTime().getSeconds() + " seconds."; + + } + } diff --git a/src/main/org/insa/graphics/AlgorithmPanel.java b/src/main/org/insa/graphics/AlgorithmPanel.java index 7e280f1..d0358ea 100644 --- a/src/main/org/insa/graphics/AlgorithmPanel.java +++ b/src/main/org/insa/graphics/AlgorithmPanel.java @@ -60,8 +60,9 @@ public class AlgorithmPanel extends JPanel { private final boolean graphicVisualization; private final boolean textualVisualization; - public StartActionEvent(Class> algoClass, List nodes, Mode mode, - ArcFilter arcFilter, boolean graphicVisualization, boolean textualVisualization) { + public StartActionEvent(Class> algoClass, List nodes, + Mode mode, ArcFilter arcFilter, boolean graphicVisualization, + boolean textualVisualization) { super(AlgorithmPanel.this, START_EVENT_ID, START_EVENT_COMMAND); this.nodes = nodes; this.mode = mode; @@ -131,39 +132,27 @@ public class AlgorithmPanel extends JPanel { /** */ - public AlgorithmPanel(Component parent, Class> baseAlgorithm) { + public AlgorithmPanel(Component parent, Class> baseAlgorithm, + String title, String[] nodeNames, boolean enableModeSelection, + boolean enableArcFilterSelection) { 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(createTitleLabel(title)); add(Box.createVerticalStrut(8)); // Add algorithm selection - JComboBox algoSelect = new JComboBox<>( - AlgorithmFactory.getAlgorithmNames(baseAlgorithm).toArray(new String[0])); - algoSelect.setBackground(Color.WHITE); - algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT); - add(algoSelect); - components.add(algoSelect); + JComboBox algoSelect = createAlgoritmSelectComboBox(baseAlgorithm); + if (algoSelect.getItemCount() > 1) { + add(algoSelect); + components.add(algoSelect); + } // Add inputs for node. - this.nodesInputPanel = new NodesInputPanel(); - this.nodesInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - nodesInputPanel.addTextField("Origin: ", new Color(57, 172, 115)); - nodesInputPanel.addTextField("Destination: ", new Color(255, 77, 77)); - nodesInputPanel.setEnabled(false); - + this.nodesInputPanel = createNodesInputPanel(nodeNames); add(this.nodesInputPanel); components.add(this.nodesInputPanel); @@ -190,16 +179,18 @@ public class AlgorithmPanel extends JPanel { c.fill = GridBagConstraints.HORIZONTAL; - c.gridx = 0; - c.gridy = 0; - c.weightx = 0; - modeAndObserverPanel.add(new JLabel("Mode: "), c); - c.gridx = 1; - c.weightx = 1; - modeAndObserverPanel.add(lengthModeButton, c); - c.gridx = 2; - c.weightx = 1; - modeAndObserverPanel.add(timeModeButton, c); + if (enableModeSelection) { + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + modeAndObserverPanel.add(new JLabel("Mode: "), c); + c.gridx = 1; + c.weightx = 1; + modeAndObserverPanel.add(lengthModeButton, c); + c.gridx = 2; + c.weightx = 1; + modeAndObserverPanel.add(timeModeButton, c); + } c.gridy = 2; c.gridx = 0; @@ -212,14 +203,16 @@ public class AlgorithmPanel extends JPanel { c.weightx = 1; modeAndObserverPanel.add(textObserver, c); - c.gridy = 1; - c.gridx = 0; - c.weightx = 0; - modeAndObserverPanel.add(new JLabel("Restrictions: "), c); - c.gridx = 1; - c.gridwidth = 2; - c.weightx = 1; - modeAndObserverPanel.add(arcFilterSelect, c); + if (enableArcFilterSelection) { + c.gridy = 1; + c.gridx = 0; + c.weightx = 0; + modeAndObserverPanel.add(new JLabel("Restrictions: "), c); + c.gridx = 1; + c.gridwidth = 2; + c.weightx = 1; + modeAndObserverPanel.add(arcFilterSelect, c); + } components.add(timeModeButton); components.add(lengthModeButton); @@ -244,17 +237,17 @@ public class AlgorithmPanel extends JPanel { startAlgoButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - AbstractInputData.Mode mode = lengthModeButton.isSelected() ? AbstractInputData.Mode.LENGTH + AbstractInputData.Mode mode = lengthModeButton.isSelected() + ? AbstractInputData.Mode.LENGTH : AbstractInputData.Mode.TIME; for (ActionListener lis: startActionListeners) { - lis.actionPerformed( - new StartActionEvent( - AlgorithmFactory.getAlgorithmClass(baseAlgorithm, - (String) algoSelect.getSelectedItem()), - nodesInputPanel.getNodeForInputs(), mode, - (AbstractInputData.ArcFilter) arcFilterSelect.getSelectedItem(), - graphicObserver.isSelected(), textObserver.isSelected())); + lis.actionPerformed(new StartActionEvent( + AlgorithmFactory.getAlgorithmClass(baseAlgorithm, + (String) algoSelect.getSelectedItem()), + nodesInputPanel.getNodeForInputs(), mode, + (AbstractInputData.ArcFilter) arcFilterSelect.getSelectedItem(), + graphicObserver.isSelected(), textObserver.isSelected())); } } }); @@ -306,6 +299,57 @@ public class AlgorithmPanel extends JPanel { setEnabled(false); } + /** + * Create the title JLabel for this panel. + * + * @param title Title for the label. + * + * @return + */ + protected JLabel createTitleLabel(String title) { + JLabel titleLabel = new JLabel(title); + 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); + return titleLabel; + } + + /** + * Create the combo box for the algorithm selection. + * + * @return + */ + protected JComboBox createAlgoritmSelectComboBox( + Class> baseAlgorithm) { + JComboBox algoSelect = new JComboBox<>( + AlgorithmFactory.getAlgorithmNames(baseAlgorithm).toArray(new String[0])); + algoSelect.setBackground(Color.WHITE); + algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT); + return algoSelect; + + } + + /** + * Create a node input panel with the given node input names. + * + * @param nodeNames + * @return + */ + protected NodesInputPanel createNodesInputPanel(String[] nodeNames) { + final Color[] nodeColors = { new Color(57, 172, 115), new Color(255, 77, 77), + new Color(77, 77, 255), new Color(77, 255, 77) }; + NodesInputPanel panel = new NodesInputPanel(); + panel.setAlignmentX(Component.LEFT_ALIGNMENT); + for (int i = 0; i < nodeNames.length; ++i) { + panel.addTextField(nodeNames[i] + ": ", nodeColors[i % nodeColors.length]); + } + panel.setEnabled(false); + return panel; + } + protected boolean allNotNull(List nodes) { boolean allNotNull = true; for (Node node: nodes) { diff --git a/src/main/org/insa/graphics/MainWindow.java b/src/main/org/insa/graphics/MainWindow.java index 8fbc0dd..40dc195 100644 --- a/src/main/org/insa/graphics/MainWindow.java +++ b/src/main/org/insa/graphics/MainWindow.java @@ -42,6 +42,7 @@ import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileNameExtensionFilter; +import org.insa.algo.AbstractSolution; import org.insa.algo.AlgorithmFactory; import org.insa.algo.shortestpath.ShortestPathAlgorithm; import org.insa.algo.shortestpath.ShortestPathData; @@ -100,20 +101,21 @@ public class MainWindow extends JFrame { // Drawing and click adapter. protected Drawing drawing; - private MapViewDrawing mapViewDrawing; - private BasicDrawing basicDrawing; + private final MapViewDrawing mapViewDrawing; + private final BasicDrawing basicDrawing; // Main panel. - private JSplitPane mainPanel; + private final JSplitPane mainPanel; - // Algorithm panel - private AlgorithmPanel spPanel; + // Algorithm panels + private final List algoPanels = new ArrayList<>(); + private final AlgorithmPanel wccPanel, spPanel; // Path panel - private PathsPanel pathPanel; + private final PathsPanel pathPanel; // List of items that cannot be used without a graph - private ArrayList graphLockItems = new ArrayList(); + private final ArrayList graphLockItems = new ArrayList(); // Label containing the map ID of the current graph. private JLabel graphInfoPanel; @@ -151,7 +153,43 @@ public class MainWindow extends JFrame { this.drawing = this.basicDrawing; - spPanel = new AlgorithmPanel(this, ShortestPathAlgorithm.class); + wccPanel = new AlgorithmPanel(this, WeaklyConnectedComponentsAlgorithm.class, + "Weakly-Connected Components", new String[] {}, false, false); + wccPanel.addStartActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StartActionEvent evt = (StartActionEvent) e; + WeaklyConnectedComponentsData data = new WeaklyConnectedComponentsData(graph); + + WeaklyConnectedComponentsAlgorithm wccAlgorithm = null; + try { + wccAlgorithm = (WeaklyConnectedComponentsAlgorithm) AlgorithmFactory + .createAlgorithm(evt.getAlgorithmClass(), 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(); + return; + } + + wccPanel.setEnabled(false); + + if (evt.isGraphicVisualizationEnabled()) { + wccAlgorithm.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); + } + if (evt.isTextualVisualizationEnabled()) { + wccAlgorithm.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); + } + + launchWeaklyConnectedComponentsThread(wccAlgorithm); + } + }); + + spPanel = new AlgorithmPanel(this, ShortestPathAlgorithm.class, "Shortest-Path", + new String[] { "Origin", "Destination" }, true, true); spPanel.addStartActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -185,7 +223,10 @@ public class MainWindow extends JFrame { launchShortestPathThread(spAlgorithm); } }); - spPanel.setVisible(false); + + // add algorithm panels + algoPanels.add(wccPanel); + algoPanels.add(spPanel); this.pathPanel = new PathsPanel(this); @@ -242,7 +283,10 @@ public class MainWindow extends JFrame { rightComponent.add(pathPanel, c); c.gridy = 1; - rightComponent.add(spPanel, c); + for (AlgorithmPanel panel: algoPanels) { + panel.setVisible(false); + rightComponent.add(panel, c); + } c = new GridBagConstraints(); c.gridx = 0; @@ -312,6 +356,19 @@ public class MainWindow extends JFrame { spPanel.solutionPanel.setVisible(true); } + private void launchWeaklyConnectedComponentsThread( + WeaklyConnectedComponentsAlgorithm wccAlgorithm) { + launchThread(new Runnable() { + @Override + public void run() { + AbstractSolution solution = wccAlgorithm.run(); + wccPanel.solutionPanel.addSolution(solution, false); + wccPanel.solutionPanel.setVisible(true); + wccPanel.setEnabled(true); + } + }); + } + private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) { launchThread(new Runnable() { @Override @@ -475,6 +532,19 @@ public class MainWindow extends JFrame { }, false); } + /** + * Show and enable the given AlgorithmPanel (and hide all others). + * + * @param algorithmPanel + */ + private void enableAlgorithmPanel(AlgorithmPanel algorithmPanel) { + int dividerLocation = mainPanel.getDividerLocation(); + for (AlgorithmPanel panel: algoPanels) { + panel.setVisible(panel == algorithmPanel); + } + mainPanel.setDividerLocation(dividerLocation); + } + private JMenuBar createMenuBar() { // Open Map item... @@ -648,16 +718,7 @@ public class MainWindow extends JFrame { wccItem.addActionListener(baf.createBlockingAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm( - new WeaklyConnectedComponentsData(graph)); - algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); - algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); - launchThread(new Runnable() { - @Override - public void run() { - algo.run(); - } - }); + enableAlgorithmPanel(wccPanel); } })); @@ -666,9 +727,7 @@ public class MainWindow extends JFrame { spItem.addActionListener(baf.createBlockingAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - int dividerLocation = mainPanel.getDividerLocation(); - spPanel.setVisible(true); - mainPanel.setDividerLocation(dividerLocation); + enableAlgorithmPanel(spPanel); } })); graphLockItems.add(wccItem);