View Javadoc
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 }