1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2025 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.gui;
21
22 import java.io.Serial;
23
24 import javax.swing.ListSelectionModel;
25 import javax.swing.tree.DefaultTreeSelectionModel;
26 import javax.swing.tree.TreePath;
27
28 /**
29 * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
30 * to listen for changes in the ListSelectionModel it maintains. Once
31 * a change in the ListSelectionModel happens, the paths are updated
32 * in the DefaultTreeSelectionModel.
33 *
34 */
35 final class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
36
37 /** A unique serial version identifier. */
38 @Serial
39 private static final long serialVersionUID = 2267930983939339510L;
40 /** TreeTable to perform updates on. */
41 private final TreeTable treeTable;
42 /** Set to true when we are updating the ListSelectionModel. */
43 private boolean updatingListSelectionModel;
44
45 /**
46 * Constructor to initialise treeTable.
47 *
48 * @param jTreeTable TreeTable to perform updates on.
49 */
50 /* package */ ListToTreeSelectionModelWrapper(TreeTable jTreeTable) {
51 treeTable = jTreeTable;
52 getListSelectionModel().addListSelectionListener(event -> {
53 updateSelectedPathsFromSelectedRows();
54 });
55 }
56
57 /**
58 * Returns the list selection model. ListToTreeSelectionModelWrapper
59 * listens for changes to this model and updates the selected paths
60 * accordingly.
61 *
62 * @return the list selection model
63 */
64 public ListSelectionModel getListSelectionModel() {
65 return listSelectionModel;
66 }
67
68 /**
69 * This is overridden to set {@code updatingListSelectionModel}
70 * and message super. This is the only place DefaultTreeSelectionModel
71 * alters the ListSelectionModel.
72 */
73 @Override
74 public void resetRowSelection() {
75 if (!updatingListSelectionModel) {
76 updatingListSelectionModel = true;
77 try {
78 super.resetRowSelection();
79 }
80 finally {
81 updatingListSelectionModel = false;
82 }
83 }
84 // Notice how we don't message super if
85 // updatingListSelectionModel is true. If
86 // updatingListSelectionModel is true, it implies the
87 // ListSelectionModel has already been updated and the
88 // paths are the only thing that needs to be updated.
89 }
90
91 /**
92 * If {@code updatingListSelectionModel} is false, this will
93 * reset the selected paths from the selected rows in the list
94 * selection model.
95 */
96 private void updateSelectedPathsFromSelectedRows() {
97 if (!updatingListSelectionModel) {
98 updatingListSelectionModel = true;
99 try {
100 // This is way expensive, ListSelectionModel needs an
101 // enumerator for iterating.
102 final int min = listSelectionModel.getMinSelectionIndex();
103 final int max = listSelectionModel.getMaxSelectionIndex();
104
105 clearSelection();
106 if (min != -1 && max != -1) {
107 for (int counter = min; counter <= max; counter++) {
108 updateSelectedPathIfRowIsSelected(counter);
109 }
110 }
111 }
112 finally {
113 updatingListSelectionModel = false;
114 }
115 }
116 }
117
118 /**
119 * If the row at given index is selected, selected paths are updated.
120 *
121 * @param counter number of row.
122 */
123 private void updateSelectedPathIfRowIsSelected(int counter) {
124 if (listSelectionModel.isSelectedIndex(counter)) {
125 final TreePath selPath = treeTable.getTree().getPathForRow(counter);
126
127 if (selPath != null) {
128 addSelectionPath(selPath);
129 }
130 }
131 }
132
133 }