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