View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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.JTree;
23  import javax.swing.SwingUtilities;
24  import javax.swing.event.TreeExpansionEvent;
25  import javax.swing.event.TreeExpansionListener;
26  import javax.swing.event.TreeModelEvent;
27  import javax.swing.event.TreeModelListener;
28  import javax.swing.table.AbstractTableModel;
29  import javax.swing.tree.TreePath;
30  
31  /**
32   * This is a wrapper class takes a TreeTableModel and implements
33   * the table model interface. The implementation is trivial, with
34   * all the event dispatching support provided by the superclass:
35   * the AbstractTableModel.
36   * <a href=
37   * "https://docs.oracle.com/cd/E48246_01/apirefs.1111/e13403/oracle/ide/controls/TreeTableModel.html">
38   * Original&nbsp;Source&nbsp;Location</a>
39   *
40   */
41  public class TreeTableModelAdapter extends AbstractTableModel {
42  
43      /** A unique serial version identifier. */
44      private static final long serialVersionUID = 8269213416115369275L;
45  
46      /** JTree component. */
47      private final JTree tree;
48      /** Tree table model. */
49      private final transient ParseTreeTableModel treeTableModel;
50  
51      /**
52       * Initialise tree and treeTableModel class attributes.
53       *
54       * @param treeTableModel Tree table model.
55       * @param tree JTree component.
56       */
57      public TreeTableModelAdapter(ParseTreeTableModel treeTableModel, JTree tree) {
58          this.tree = tree;
59          this.treeTableModel = treeTableModel;
60  
61          tree.addTreeExpansionListener(new UpdatingTreeExpansionListener());
62  
63          // Install a TreeModelListener that can update the table when
64          // mTree changes. We use delayedFireTableDataChanged as we can
65          // not be guaranteed the mTree will have finished processing
66          // the event before us.
67          treeTableModel.addTreeModelListener(new UpdatingTreeModelListener());
68      }
69  
70      // Wrappers, implementing TableModel interface.
71  
72      @Override
73      public int getColumnCount() {
74          return treeTableModel.getColumnCount();
75      }
76  
77      @Override
78      public String getColumnName(int column) {
79          return treeTableModel.getColumnName(column);
80      }
81  
82      @Override
83      public Class<?> getColumnClass(int column) {
84          return treeTableModel.getColumnClass(column);
85      }
86  
87      @Override
88      public int getRowCount() {
89          return tree.getRowCount();
90      }
91  
92      @Override
93      public Object getValueAt(int row, int column) {
94          return treeTableModel.getValueAt(nodeForRow(row), column);
95      }
96  
97      @Override
98      public boolean isCellEditable(int row, int column) {
99          return treeTableModel.isCellEditable(column);
100     }
101 
102     /**
103      * Finds node for a given row.
104      *
105      * @param row Row for which to find a related node.
106      * @return Node for a given row.
107      */
108     private Object nodeForRow(int row) {
109         final TreePath treePath = tree.getPathForRow(row);
110         return treePath.getLastPathComponent();
111     }
112 
113     /**
114      * TreeExpansionListener that can update the table when tree changes.
115      */
116     private final class UpdatingTreeExpansionListener implements TreeExpansionListener {
117 
118         // Don't use fireTableRowsInserted() here; the selection model
119         // would get updated twice.
120         @Override
121         public void treeExpanded(TreeExpansionEvent event) {
122             fireTableDataChanged();
123         }
124 
125         @Override
126         public void treeCollapsed(TreeExpansionEvent event) {
127             fireTableDataChanged();
128         }
129 
130     }
131 
132     /**
133      * TreeModelListener that can update the table when tree changes.
134      */
135     private final class UpdatingTreeModelListener implements TreeModelListener {
136 
137         @Override
138         public void treeNodesChanged(TreeModelEvent event) {
139             delayedFireTableDataChanged();
140         }
141 
142         @Override
143         public void treeNodesInserted(TreeModelEvent event) {
144             delayedFireTableDataChanged();
145         }
146 
147         @Override
148         public void treeNodesRemoved(TreeModelEvent event) {
149             delayedFireTableDataChanged();
150         }
151 
152         @Override
153         public void treeStructureChanged(TreeModelEvent event) {
154             delayedFireTableDataChanged();
155         }
156 
157         /**
158          * Invokes fireTableDataChanged after all the pending events have been
159          * processed. SwingUtilities.invokeLater is used to handle this.
160          */
161         private void delayedFireTableDataChanged() {
162             SwingUtilities.invokeLater(TreeTableModelAdapter.this::fireTableDataChanged);
163         }
164 
165     }
166 
167 }