This repository was archived by the owner on Jun 18, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArticulationPanelController.java
More file actions
165 lines (143 loc) · 6.81 KB
/
Copy pathArticulationPanelController.java
File metadata and controls
165 lines (143 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package gvisual;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import java.util.*;
import java.util.function.Supplier;
/**
* Encapsulates the "Articulation Points & Bridges" analysis panel previously
* embedded in Main.java. Owns UI, analysis lifecycle, and overlay state.
*/
public class ArticulationPanelController {
private final JPanel panel;
private final JLabel resilienceLabel;
private final JLabel summaryLabel;
private final JLabel detailsLabel;
private final JButton analyzeButton;
private final JButton clearButton;
private final Supplier<Graph<String, Edge>> graphSupplier;
private final Runnable onOverlayChanged;
private boolean overlayActive;
private final Set<String> articulationPoints = new HashSet<>();
private final Set<Edge> bridgeEdges = new HashSet<>();
/**
* @param graphSupplier supplies the current graph
* @param onOverlayChanged callback to refresh renderers/visualization after overlay changes
*/
public ArticulationPanelController(Supplier<Graph<String, Edge>> graphSupplier,
Runnable onOverlayChanged) {
this.graphSupplier = graphSupplier;
this.onOverlayChanged = onOverlayChanged;
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),
"Articulation Points & Bridges",
TitledBorder.LEFT, TitledBorder.TOP));
resilienceLabel = new JLabel("Resilience: \u2014");
resilienceLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
summaryLabel = new JLabel("<html>Click 'Analyze' to find critical nodes and edges.</html>");
summaryLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
detailsLabel = new JLabel("");
detailsLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
analyzeButton = new JButton("Analyze");
analyzeButton.setAlignmentX(JButton.LEFT_ALIGNMENT);
analyzeButton.addActionListener(e -> runAnalysis());
clearButton = new JButton("Clear");
clearButton.setAlignmentX(JButton.LEFT_ALIGNMENT);
clearButton.addActionListener(e -> clear());
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
buttonPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
buttonPanel.add(analyzeButton);
buttonPanel.add(Box.createHorizontalStrut(5));
buttonPanel.add(clearButton);
panel.add(resilienceLabel);
panel.add(summaryLabel);
panel.add(Box.createVerticalStrut(4));
panel.add(buttonPanel);
panel.add(Box.createVerticalStrut(4));
panel.add(detailsLabel);
}
public JPanel getPanel() { return panel; }
public boolean isOverlayActive() { return overlayActive; }
public Set<String> getArticulationPoints() { return Collections.unmodifiableSet(articulationPoints); }
public Set<Edge> getBridgeEdges() { return Collections.unmodifiableSet(bridgeEdges); }
private void runAnalysis() {
Graph<String, Edge> g = graphSupplier.get();
if (g == null || g.getVertexCount() == 0) {
summaryLabel.setText("<html>No graph loaded.</html>");
return;
}
ArticulationPointAnalyzer analyzer = new ArticulationPointAnalyzer(g);
ArticulationPointAnalyzer.AnalysisResult result = analyzer.analyze();
overlayActive = true;
articulationPoints.clear();
bridgeEdges.clear();
articulationPoints.addAll(result.getArticulationPoints());
for (ArticulationPointAnalyzer.Bridge b : result.getBridges()) {
bridgeEdges.add(b.getEdge());
}
resilienceLabel.setText(String.format(
"Resilience: %.0f/100 (%s)", result.getResilienceScore(),
result.getVulnerabilityLevel()));
StringBuilder sb = new StringBuilder("<html>");
sb.append(String.format("<b>Cut vertices:</b> %d (%.1f%%)<br/>",
result.getArticulationPointCount(), result.getArticulationPointPercentage()));
sb.append(String.format("<b>Bridges:</b> %d<br/>", result.getBridgeCount()));
sb.append(String.format("<b>Components:</b> %d", result.getConnectedComponents()));
sb.append("</html>");
summaryLabel.setText(sb.toString());
StringBuilder details = new StringBuilder("<html>");
List<ArticulationPointAnalyzer.ArticulationPointInfo> apDetails =
result.getArticulationPointDetails();
if (!apDetails.isEmpty()) {
details.append("<b>Critical nodes:</b><br/>");
int shown = Math.min(5, apDetails.size());
for (int i = 0; i < shown; i++) {
ArticulationPointAnalyzer.ArticulationPointInfo info = apDetails.get(i);
details.append(String.format(" Node %s (deg=%d, crit=%.1f)<br/>",
info.getVertex(), info.getDegree(), info.getCriticality()));
}
if (apDetails.size() > 5) {
details.append(String.format(" ... and %d more<br/>", apDetails.size() - 5));
}
}
List<ArticulationPointAnalyzer.Bridge> bridges = result.getBridges();
if (!bridges.isEmpty()) {
details.append("<b>Bridges:</b><br/>");
int shown = Math.min(5, bridges.size());
for (int i = 0; i < shown; i++) {
ArticulationPointAnalyzer.Bridge bridge = bridges.get(i);
details.append(String.format(" %s\u2014%s (sev=%.2f, split=%d/%d)<br/>",
bridge.getEndpoint1(), bridge.getEndpoint2(),
bridge.getSeverity(),
bridge.getComponentSizeA(), bridge.getComponentSizeB()));
}
if (bridges.size() > 5) {
details.append(String.format(" ... and %d more<br/>", bridges.size() - 5));
}
}
if (apDetails.isEmpty() && bridges.isEmpty()) {
details.append("<i>No critical elements \u2014 network is robust.</i>");
}
details.append("</html>");
detailsLabel.setText(details.toString());
onOverlayChanged.run();
panel.revalidate();
panel.repaint();
}
public void clear() {
overlayActive = false;
articulationPoints.clear();
bridgeEdges.clear();
resilienceLabel.setText("Resilience: \u2014");
summaryLabel.setText("<html>Click 'Analyze' to find critical nodes and edges.</html>");
detailsLabel.setText("");
onOverlayChanged.run();
panel.revalidate();
panel.repaint();
}
}