001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.gui; 021 022import javax.swing.ListSelectionModel; 023import javax.swing.tree.DefaultTreeSelectionModel; 024import javax.swing.tree.TreePath; 025 026/** 027 * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel 028 * to listen for changes in the ListSelectionModel it maintains. Once 029 * a change in the ListSelectionModel happens, the paths are updated 030 * in the DefaultTreeSelectionModel. 031 * 032 */ 033final class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { 034 035 /** A unique serial version identifier. */ 036 private static final long serialVersionUID = 2267930983939339510L; 037 /** TreeTable to perform updates on. */ 038 private final TreeTable treeTable; 039 /** Set to true when we are updating the ListSelectionModel. */ 040 private boolean updatingListSelectionModel; 041 042 /** 043 * Constructor to initialise treeTable. 044 * 045 * @param jTreeTable TreeTable to perform updates on. 046 */ 047 /* package */ ListToTreeSelectionModelWrapper(TreeTable jTreeTable) { 048 treeTable = jTreeTable; 049 getListSelectionModel().addListSelectionListener(event -> { 050 updateSelectedPathsFromSelectedRows(); 051 }); 052 } 053 054 /** 055 * Returns the list selection model. ListToTreeSelectionModelWrapper 056 * listens for changes to this model and updates the selected paths 057 * accordingly. 058 * 059 * @return the list selection model 060 */ 061 public ListSelectionModel getListSelectionModel() { 062 return listSelectionModel; 063 } 064 065 /** 066 * This is overridden to set {@code updatingListSelectionModel} 067 * and message super. This is the only place DefaultTreeSelectionModel 068 * alters the ListSelectionModel. 069 */ 070 @Override 071 public void resetRowSelection() { 072 if (!updatingListSelectionModel) { 073 updatingListSelectionModel = true; 074 try { 075 super.resetRowSelection(); 076 } 077 finally { 078 updatingListSelectionModel = false; 079 } 080 } 081 // Notice how we don't message super if 082 // updatingListSelectionModel is true. If 083 // updatingListSelectionModel is true, it implies the 084 // ListSelectionModel has already been updated and the 085 // paths are the only thing that needs to be updated. 086 } 087 088 /** 089 * If {@code updatingListSelectionModel} is false, this will 090 * reset the selected paths from the selected rows in the list 091 * selection model. 092 */ 093 private void updateSelectedPathsFromSelectedRows() { 094 if (!updatingListSelectionModel) { 095 updatingListSelectionModel = true; 096 try { 097 // This is way expensive, ListSelectionModel needs an 098 // enumerator for iterating. 099 final int min = listSelectionModel.getMinSelectionIndex(); 100 final int max = listSelectionModel.getMaxSelectionIndex(); 101 102 clearSelection(); 103 if (min != -1 && max != -1) { 104 for (int counter = min; counter <= max; counter++) { 105 updateSelectedPathIfRowIsSelected(counter); 106 } 107 } 108 } 109 finally { 110 updatingListSelectionModel = false; 111 } 112 } 113 } 114 115 /** 116 * If the row at given index is selected, selected paths are updated. 117 * 118 * @param counter number of row. 119 */ 120 private void updateSelectedPathIfRowIsSelected(int counter) { 121 if (listSelectionModel.isSelectedIndex(counter)) { 122 final TreePath selPath = treeTable.getTree().getPathForRow(counter); 123 124 if (selPath != null) { 125 addSelectionPath(selPath); 126 } 127 } 128 } 129 130}