001 package ui.model; 002 003 import javax.swing.JTree; 004 import java.awt.EventQueue; 005 import javax.swing.table.AbstractTableModel; 006 import javax.swing.tree.TreePath; 007 import javax.swing.event.TreeExpansionEvent; 008 import javax.swing.event.TreeExpansionListener; 009 import javax.swing.event.TreeModelEvent; 010 import javax.swing.event.TreeModelListener; 011 012 /** 013 * This is a wrapper class takes a TreeTableModel and implements 014 * the table model interface. The implementation is trivial, with 015 * all of the event dispatching support provided by the superclass: 016 * the AbstractTableModel. 017 * 018 * @version 1.2 10/27/98 019 * 020 * @author Philip Milne 021 * @author Scott Violet 022 */ 023 public class TreeTableModelAdapter extends AbstractTableModel 024 { 025 JTree tree; 026 TreeTableModel treeTableModel; 027 028 public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) { 029 this.tree = tree; 030 this.treeTableModel = treeTableModel; 031 032 tree.addTreeExpansionListener(new TreeExpansionListener() { 033 // Don't use fireTableRowsInserted() here; the selection model 034 // would get updated twice. 035 public void treeExpanded(TreeExpansionEvent event) { 036 fireTableDataChanged(); 037 } 038 public void treeCollapsed(TreeExpansionEvent event) { 039 fireTableDataChanged(); 040 } 041 }); 042 043 // Install a TreeModelListener that can update the table when 044 // tree changes. We use delayedFireTableDataChanged as we can 045 // not be guaranteed the tree will have finished processing 046 // the event before us. 047 treeTableModel.addTreeModelListener(new TreeModelListener() { 048 public void treeNodesChanged(TreeModelEvent e) { 049 delayedFireTableDataChanged(); 050 } 051 052 public void treeNodesInserted(TreeModelEvent e) { 053 delayedFireTableDataChanged(); 054 } 055 056 public void treeNodesRemoved(TreeModelEvent e) { 057 delayedFireTableDataChanged(); 058 } 059 060 public void treeStructureChanged(TreeModelEvent e) { 061 delayedFireTableDataChanged(); 062 } 063 }); 064 } 065 066 // Wrappers, implementing TableModel interface. 067 068 public int getColumnCount() { 069 return treeTableModel.getColumnCount(); 070 } 071 072 public String getColumnName(int column) { 073 return treeTableModel.getColumnName(column); 074 } 075 076 public Class getColumnClass(int column) { 077 return treeTableModel.getColumnClass(column); 078 } 079 080 public int getRowCount() { 081 return tree.getRowCount(); 082 } 083 084 public Object getValueAt(int row, int column) { 085 return treeTableModel.getValueAt(nodeForRow(row), column); 086 } 087 088 public boolean isCellEditable(int row, int column) { 089 return treeTableModel.isCellEditable(nodeForRow(row), column); 090 } 091 092 public void setValueAt(Object value, int row, int column) { 093 treeTableModel.setValueAt(value, nodeForRow(row), column); 094 } 095 096 097 // row to node mapping used only in the last three methods 098 protected Object nodeForRow(int row) { 099 TreePath treePath = tree.getPathForRow(row); 100 return treePath.getLastPathComponent(); 101 } 102 103 /** 104 * Invokes fireTableDataChanged after all the pending events have been processed. 105 * The static method : java.awt.EventQueue.invokeLater() 106 * is used to handle this. 107 */ 108 protected void delayedFireTableDataChanged() { 109 EventQueue.invokeLater(new Runnable() { 110 public void run() { 111 fireTableDataChanged(); 112 } 113 }); 114 } 115 } 116