001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 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.JTree; 023import javax.swing.SwingUtilities; 024import javax.swing.event.TreeExpansionEvent; 025import javax.swing.event.TreeExpansionListener; 026import javax.swing.event.TreeModelEvent; 027import javax.swing.event.TreeModelListener; 028import javax.swing.table.AbstractTableModel; 029import javax.swing.tree.TreePath; 030 031/** 032 * This is a wrapper class takes a TreeTableModel and implements 033 * the table model interface. The implementation is trivial, with 034 * all of the event dispatching support provided by the superclass: 035 * the AbstractTableModel. 036 * 037 * <a href= 038 * "https://docs.oracle.com/cd/E48246_01/apirefs.1111/e13403/oracle/ide/controls/TreeTableModel.html"> 039 * Original Source Location</a> 040 * 041 * @author Philip Milne 042 * @author Scott Violet 043 */ 044public class TreeTableModelAdapter extends AbstractTableModel { 045 /** For Serialisation that will never happen. */ 046 private static final long serialVersionUID = 8269213416115369275L; 047 048 /** JTree component. */ 049 private final JTree tree; 050 /** Tree table model. */ 051 private final transient TreeTableModel treeTableModel; 052 053 /** 054 * @param treeTableModel Tree table model. 055 * @param tree JTree component. 056 */ 057 public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) { 058 this.tree = tree; 059 this.treeTableModel = treeTableModel; 060 061 tree.addTreeExpansionListener(new UpdatingTreeExpansionListener()); 062 063 // Install a TreeModelListener that can update the table when 064 // mTree changes. We use delayedFireTableDataChanged as we can 065 // not be guaranteed the mTree will have finished processing 066 // the event before us. 067 treeTableModel.addTreeModelListener(new UpdatingTreeModelListener()); 068 } 069 070 // Wrappers, implementing TableModel interface. 071 072 @Override 073 public int getColumnCount() { 074 return treeTableModel.getColumnCount(); 075 } 076 077 @Override 078 public String getColumnName(int column) { 079 return treeTableModel.getColumnName(column); 080 } 081 082 @Override 083 public Class<?> getColumnClass(int column) { 084 return treeTableModel.getColumnClass(column); 085 } 086 087 @Override 088 public int getRowCount() { 089 return tree.getRowCount(); 090 } 091 092 @Override 093 public Object getValueAt(int row, int column) { 094 return treeTableModel.getValueAt(nodeForRow(row), column); 095 } 096 097 @Override 098 public boolean isCellEditable(int row, int column) { 099 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(new Runnable() { 118 @Override 119 public void run() { 120 fireTableDataChanged(); 121 } 122 }); 123 } 124 125 /** 126 * TreeExpansionListener that can update the table when tree changes. 127 */ 128 private class UpdatingTreeExpansionListener implements TreeExpansionListener { 129 // Don't use fireTableRowsInserted() here; the selection model 130 // would get updated twice. 131 @Override 132 public void treeExpanded(TreeExpansionEvent event) { 133 fireTableDataChanged(); 134 } 135 136 @Override 137 public void treeCollapsed(TreeExpansionEvent event) { 138 fireTableDataChanged(); 139 } 140 } 141 142 /** 143 * TreeModelListener that can update the table when tree changes. 144 */ 145 private class UpdatingTreeModelListener implements TreeModelListener { 146 @Override 147 public void treeNodesChanged(TreeModelEvent e) { 148 delayedFireTableDataChanged(); 149 } 150 151 @Override 152 public void treeNodesInserted(TreeModelEvent e) { 153 delayedFireTableDataChanged(); 154 } 155 156 @Override 157 public void treeNodesRemoved(TreeModelEvent e) { 158 delayedFireTableDataChanged(); 159 } 160 161 @Override 162 public void treeStructureChanged(TreeModelEvent e) { 163 delayedFireTableDataChanged(); 164 } 165 } 166}