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 }