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