View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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      private static final long serialVersionUID = 8269213416115369275L;
46  
47      /** JTree component. */
48      private final JTree tree;
49      /** Tree table model. */
50      private final transient ParseTreeTableModel treeTableModel;
51  
52      /**
53       * Initialise tree and treeTableModel class attributes.
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      * @param row Row for which to find a related node.
105      * @return Node for a given row.
106      */
107     private Object nodeForRow(int row) {
108         final TreePath treePath = tree.getPathForRow(row);
109         return treePath.getLastPathComponent();
110     }
111 
112     /**
113      * Invokes fireTableDataChanged after all the pending events have been
114      * processed. SwingUtilities.invokeLater is used to handle this.
115      */
116     private void delayedFireTableDataChanged() {
117         SwingUtilities.invokeLater(this::fireTableDataChanged);
118     }
119 
120     /**
121      * TreeExpansionListener that can update the table when tree changes.
122      */
123     private class UpdatingTreeExpansionListener implements TreeExpansionListener {
124         // Don't use fireTableRowsInserted() here; the selection model
125         // would get updated twice.
126         @Override
127         public void treeExpanded(TreeExpansionEvent event) {
128             fireTableDataChanged();
129         }
130 
131         @Override
132         public void treeCollapsed(TreeExpansionEvent event) {
133             fireTableDataChanged();
134         }
135     }
136 
137     /**
138      * TreeModelListener that can update the table when tree changes.
139      */
140     private class UpdatingTreeModelListener implements TreeModelListener {
141         @Override
142         public void treeNodesChanged(TreeModelEvent event) {
143             delayedFireTableDataChanged();
144         }
145 
146         @Override
147         public void treeNodesInserted(TreeModelEvent event) {
148             delayedFireTableDataChanged();
149         }
150 
151         @Override
152         public void treeNodesRemoved(TreeModelEvent event) {
153             delayedFireTableDataChanged();
154         }
155 
156         @Override
157         public void treeStructureChanged(TreeModelEvent event) {
158             delayedFireTableDataChanged();
159         }
160     }
161 }