1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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 javax.swing.ListSelectionModel;
23  import javax.swing.tree.DefaultTreeSelectionModel;
24  import javax.swing.tree.TreePath;
25  
26  /**
27   * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
28   * to listen for changes in the ListSelectionModel it maintains. Once
29   * a change in the ListSelectionModel happens, the paths are updated
30   * in the DefaultTreeSelectionModel.
31   *
32   */
33  class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
34  
35      private static final long serialVersionUID = 2267930983939339510L;
36      /** TreeTable to perform updates on. */
37      private final TreeTable treeTable;
38      /** Set to true when we are updating the ListSelectionModel. */
39      private boolean updatingListSelectionModel;
40  
41      /**
42       * Constructor to initialise treeTable.
43       * @param jTreeTable TreeTable to perform updates on.
44       */
45      /* package */ ListToTreeSelectionModelWrapper(TreeTable jTreeTable) {
46          treeTable = jTreeTable;
47          getListSelectionModel().addListSelectionListener(event -> {
48              updateSelectedPathsFromSelectedRows();
49          });
50      }
51  
52      /**
53       * Returns the list selection model. ListToTreeSelectionModelWrapper
54       * listens for changes to this model and updates the selected paths
55       * accordingly.
56       *
57       * @return the list selection model
58       */
59      protected final ListSelectionModel getListSelectionModel() {
60          return listSelectionModel;
61      }
62  
63      /**
64       * This is overridden to set {@code updatingListSelectionModel}
65       * and message super. This is the only place DefaultTreeSelectionModel
66       * alters the ListSelectionModel.
67       */
68      @Override
69      public void resetRowSelection() {
70          if (!updatingListSelectionModel) {
71              updatingListSelectionModel = true;
72              try {
73                  super.resetRowSelection();
74              }
75              finally {
76                  updatingListSelectionModel = false;
77              }
78          }
79          // Notice how we don't message super if
80          // updatingListSelectionModel is true. If
81          // updatingListSelectionModel is true, it implies the
82          // ListSelectionModel has already been updated and the
83          // paths are the only thing that needs to be updated.
84      }
85  
86      /**
87       * If {@code updatingListSelectionModel} is false, this will
88       * reset the selected paths from the selected rows in the list
89       * selection model.
90       */
91      private void updateSelectedPathsFromSelectedRows() {
92          if (!updatingListSelectionModel) {
93              updatingListSelectionModel = true;
94              try {
95                  // This is way expensive, ListSelectionModel needs an
96                  // enumerator for iterating.
97                  final int min = listSelectionModel.getMinSelectionIndex();
98                  final int max = listSelectionModel.getMaxSelectionIndex();
99  
100                 clearSelection();
101                 if (min != -1 && max != -1) {
102                     for (int counter = min; counter <= max; counter++) {
103                         updateSelectedPathIfRowIsSelected(counter);
104                     }
105                 }
106             }
107             finally {
108                 updatingListSelectionModel = false;
109             }
110         }
111     }
112 
113     /**
114      * If the row at given index is selected, selected paths are updated.
115      * @param counter number of row.
116      */
117     private void updateSelectedPathIfRowIsSelected(int counter) {
118         if (listSelectionModel.isSelectedIndex(counter)) {
119             final TreePath selPath = treeTable.getTree().getPathForRow(counter);
120 
121             if (selPath != null) {
122                 addSelectionPath(selPath);
123             }
124         }
125     }
126 
127 }