|
24 | 24 | import java.awt.event.MouseListener; |
25 | 25 | import java.awt.geom.Ellipse2D; |
26 | 26 | import java.io.File; |
27 | | -import java.io.FileInputStream; |
28 | 27 | import java.io.FileNotFoundException; |
29 | | -import java.io.FileOutputStream; |
30 | 28 | import java.io.IOException; |
31 | | -import java.io.InputStream; |
32 | | -import java.io.OutputStream; |
33 | 29 | import java.util.ArrayList; |
34 | 30 | import java.util.Collection; |
35 | 31 | import java.util.Collections; |
@@ -1955,50 +1951,71 @@ private void updateStatsPanel() { |
1955 | 1951 | /** |
1956 | 1952 | * creates the right pane containing the communities and notes section |
1957 | 1953 | */ |
| 1954 | + /** |
| 1955 | + * creates the right pane containing the communities and notes section. |
| 1956 | + * |
| 1957 | + * <p>Uses {@link #chainSplitPanes} to avoid deeply nested manual |
| 1958 | + * JSplitPane construction — adding/removing panels now requires |
| 1959 | + * only editing the array and heights, not restructuring nesting.</p> |
| 1960 | + */ |
1958 | 1961 | public final void showRightPane() { |
1959 | 1962 |
|
1960 | | - |
1961 | 1963 | JLabel parameterHeading = new JLabel("Communities", JLabel.CENTER); |
1962 | 1964 | parameterHeading.setPreferredSize(new Dimension(300, 30)); |
1963 | | - JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
| 1965 | + JSplitPane headerSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1964 | 1966 | parameterHeading, parameterSpace); |
1965 | 1967 |
|
1966 | | - JSplitPane splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1967 | | - splitPane, notesPanel); |
1968 | | - |
1969 | | - // Add path panel between notes and stats |
1970 | | - JSplitPane splitPanePath = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1971 | | - splitPane1, pathPanel); |
1972 | | - |
1973 | | - // Add community panel below path panel |
1974 | | - JSplitPane splitPaneCommunity = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1975 | | - splitPanePath, communityPanel); |
1976 | | - |
1977 | | - // Add MST panel below community panel |
1978 | | - JSplitPane splitPaneMST = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1979 | | - splitPaneCommunity, mstPanel); |
| 1968 | + // Panels in display order, with their preferred divider heights. |
| 1969 | + // To add a new panel, just add an entry here — no nesting changes needed. |
| 1970 | + java.awt.Component[] panels = { |
| 1971 | + headerSplit, |
| 1972 | + notesPanel, |
| 1973 | + pathPanel, |
| 1974 | + communityPanel, |
| 1975 | + mstPanel, |
| 1976 | + centralityPanel, |
| 1977 | + articulationPanel, |
| 1978 | + statsPanel, |
| 1979 | + }; |
| 1980 | + int[] dividerLocations = { 400, 510, 640, 760, 920, 1070, 1250 }; |
1980 | 1981 |
|
1981 | | - // Add centrality panel below MST panel |
1982 | | - JSplitPane splitPaneCentrality = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1983 | | - splitPaneMST, centralityPanel); |
| 1982 | + JSplitPane root = chainSplitPanes(panels, dividerLocations); |
| 1983 | + add(root, BorderLayout.EAST); |
| 1984 | + } |
1984 | 1985 |
|
1985 | | - // Add articulation panel below centrality panel |
1986 | | - JSplitPane splitPaneArticulation = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1987 | | - splitPaneCentrality, articulationPanel); |
| 1986 | + /** |
| 1987 | + * Chains an array of components into nested vertical JSplitPanes. |
| 1988 | + * |
| 1989 | + * <p>Given components [A, B, C, D], produces: |
| 1990 | + * <pre> |
| 1991 | + * Split(Split(Split(A, B), C), D) |
| 1992 | + * </pre> |
| 1993 | + * with divider locations applied in order.</p> |
| 1994 | + * |
| 1995 | + * @param components the panels to chain (at least 2) |
| 1996 | + * @param dividerLocations divider positions; length must be components.length - 1 |
| 1997 | + * @return the outermost JSplitPane |
| 1998 | + */ |
| 1999 | + private static JSplitPane chainSplitPanes(java.awt.Component[] components, int[] dividerLocations) { |
| 2000 | + if (components.length < 2) { |
| 2001 | + throw new IllegalArgumentException("Need at least 2 components to chain"); |
| 2002 | + } |
| 2003 | + if (dividerLocations.length != components.length - 1) { |
| 2004 | + throw new IllegalArgumentException("Need exactly (components.length - 1) divider locations"); |
| 2005 | + } |
1988 | 2006 |
|
1989 | | - // Add stats panel below articulation panel |
1990 | | - JSplitPane splitPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
1991 | | - splitPaneArticulation, statsPanel); |
| 2007 | + JSplitPane current = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
| 2008 | + components[0], components[1]); |
| 2009 | + current.setDividerLocation(dividerLocations[0]); |
1992 | 2010 |
|
1993 | | - splitPane1.setDividerLocation(400); |
1994 | | - splitPanePath.setDividerLocation(510); |
1995 | | - splitPaneCommunity.setDividerLocation(640); |
1996 | | - splitPaneMST.setDividerLocation(760); |
1997 | | - splitPaneCentrality.setDividerLocation(920); |
1998 | | - splitPaneArticulation.setDividerLocation(1070); |
1999 | | - splitPane2.setDividerLocation(1250); |
2000 | | - add(splitPane2, BorderLayout.EAST); |
| 2011 | + for (int i = 2; i < components.length; i++) { |
| 2012 | + JSplitPane next = new JSplitPane(JSplitPane.VERTICAL_SPLIT, |
| 2013 | + current, components[i]); |
| 2014 | + next.setDividerLocation(dividerLocations[i - 1]); |
| 2015 | + current = next; |
| 2016 | + } |
2001 | 2017 |
|
| 2018 | + return current; |
2002 | 2019 | } |
2003 | 2020 |
|
2004 | 2021 | /** |
@@ -2399,7 +2416,9 @@ public void actionPerformed(ActionEvent e) { |
2399 | 2416 | Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); |
2400 | 2417 | } |
2401 | 2418 | try { |
2402 | | - copyfile(new File("./graph.txt"), fileChooser.getSelectedFile()); |
| 2419 | + // Use commons-io FileUtils (already a project dependency) |
| 2420 | + // instead of the hand-rolled byte-copy loop. |
| 2421 | + FileUtils.copyFile(new File("./graph.txt"), fileChooser.getSelectedFile()); |
2403 | 2422 | } catch (FileNotFoundException ex) { |
2404 | 2423 | Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); |
2405 | 2424 | } catch (IOException ex) { |
@@ -2476,25 +2495,10 @@ public void actionPerformed(ActionEvent e) { |
2476 | 2495 | contentPanel.add(toolPanel, BorderLayout.WEST); |
2477 | 2496 | } |
2478 | 2497 |
|
2479 | | - /** |
2480 | | - * Copies the contents of one file to another |
2481 | | - * @param srFile source file from which contents are copied |
2482 | | - * @param dtFile destination file to which contents are copied |
2483 | | - * @throws FileNotFoundException |
2484 | | - * @throws IOException |
2485 | | - */ |
2486 | | - private void copyfile(File srFile, File dtFile) throws FileNotFoundException, IOException { |
2487 | | - |
2488 | | - try (InputStream in = new FileInputStream(srFile); |
2489 | | - OutputStream out = new FileOutputStream(dtFile, false)) { |
2490 | | - |
2491 | | - byte[] buf = new byte[8192]; |
2492 | | - int len; |
2493 | | - while ((len = in.read(buf)) > 0) { |
2494 | | - out.write(buf, 0, len); |
2495 | | - } |
2496 | | - } |
2497 | | - } |
| 2498 | + // copyfile() removed — replaced with FileUtils.copyFile() from commons-io |
| 2499 | + // (which was already a project dependency). The hand-rolled byte-copy loop |
| 2500 | + // duplicated well-tested library code and missed features like atomic |
| 2501 | + // writes and proper error cleanup. |
2498 | 2502 |
|
2499 | 2503 | /** |
2500 | 2504 | *main function |
|
0 commit comments