001    /*
002     * $Id: AbstractTreeTableModel.java 3100 2008-10-14 22:33:10Z rah003 $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    
022    package org.jdesktop.swingx.treetable;
023    
024    import javax.swing.event.TreeModelListener;
025    import javax.swing.tree.TreePath;
026    
027    import org.jdesktop.swingx.tree.TreeModelSupport;
028    
029    // There is no javax.swing.tree.AbstractTreeModel; There ought to be one.
030    
031    /**
032     * AbstractTreeTableModel provides an implementation of
033     * {@link org.jdesktop.swingx.treetable.TreeTableModel} as a convenient starting
034     * point in defining custom data models for
035     * {@link org.jdesktop.swingx.JXTreeTable}. It takes care of listener
036     * management and contains convenience methods for creating and dispatching
037     * {@code TreeModelEvent}s. To create a concreate instance of
038     * {@code TreeTableModel} you need only to provide implementations for the
039     * following methods:
040     * 
041     * <pre>
042     * public int getColumnCount();
043     * public Object getValueAt(Object node, int column);
044     * public Object getChild(Object parent, int index);
045     * public int getChildCount(Object parent);
046     * public int getIndexOfChild(Object parent, Object child);
047     * public boolean isLeaf(Object node);
048     * </pre>
049     * 
050     * @author Ramesh Gupta
051     * @author Karl Schaefer
052     */
053    public abstract class AbstractTreeTableModel implements TreeTableModel {
054    
055        /**
056         * Root node of the model
057         */
058        protected Object root;
059    
060        /**
061         * Provides support for event dispatching.
062         */
063        protected TreeModelSupport modelSupport;
064        
065        /**
066         * Constructs an {@code AbstractTreeTableModel} with a {@code null} root
067         * node.
068         */
069        public AbstractTreeTableModel() {
070            this(null);
071        }
072    
073        /**
074         * Constructs an {@code AbstractTreeTableModel} with the specified root
075         * node.
076         * 
077         * @param root
078         *            root node
079         */
080        public AbstractTreeTableModel(Object root) {
081            this.root = root;
082            this.modelSupport = new TreeModelSupport(this);
083        }
084    
085        /**
086         * {@inheritDoc}
087         */
088        public Class<?> getColumnClass(int column) {
089            return Object.class;
090        }
091    
092        /**
093         * {@inheritDoc}
094         */
095        public String getColumnName(int column) {
096            //Copied from AbstractTableModel.
097            //Should use same defaults when possible.
098            String result = "";
099            
100            for (; column >= 0; column = column / 26 - 1) {
101                result = (char) ((char) (column % 26) + 'A') + result;
102            }
103            
104            return result;
105        }
106    
107        /**
108         * {@inheritDoc}
109         */
110        public int getHierarchicalColumn() {
111            if (getColumnCount() == 0) {
112                return -1;
113            }
114            
115            return 0;
116        }
117    
118        /**
119         * {@inheritDoc}
120         */
121        public Object getRoot() {
122            return root;
123        }
124    
125        /**
126         * {@inheritDoc}
127         */
128        public boolean isCellEditable(Object node, int column) {
129            // RG: Fix Issue 49 -- Cell not editable, by default.
130            // Subclasses might override this to return true.
131            return false;
132        }
133    
134        /**
135         * Returns <code>true</code> if <code>node</code> is a leaf.
136         *
137         * @impl {@code true} if {@code getChildCount(node) == 0}
138         * @param   node  a node in the tree, obtained from this data source
139         * @return  true if <code>node</code> is a leaf
140         */
141        public boolean isLeaf(Object node) {
142            return getChildCount(node) == 0;
143        }
144    
145        /**
146         * Sets the value for the {@code node} at {@code columnIndex} to
147         * {@code value}.
148         * 
149         * @impl is no-op; provided for convenience for uneditable models
150         * @param value
151         *            the new value
152         * @param node
153         *            the node whose value is to be changed
154         * @param column
155         *            the column whose value is to be changed
156         * @see #getValueAt
157         * @see #isCellEditable
158         * @see javax.swing.table.TableModel#setValueAt(Object, int, int)
159         */
160        public void setValueAt(Object value, Object node, int column) {
161            //does nothing
162        }
163        
164        /**
165         * Called when value for the item identified by path has been changed. If
166         * newValue signifies a truly new value the model should post a
167         * {@code treeNodesChanged} event.
168         * <p>
169         * 
170         * @impl is no-op. A {@code JXTreeTable} does not usually edit the node directly.
171         * @param path
172         *            path to the node that has changed
173         * @param newValue
174         *            the new value from the <code>TreeCellEditor</code>
175         */
176        public void valueForPathChanged(TreePath path, Object newValue) {
177            //does nothing
178        }
179    
180        /**
181         * {@inheritDoc}
182         */
183        public void addTreeModelListener(TreeModelListener l) {
184            modelSupport.addTreeModelListener(l);
185        }
186    
187        /**
188         * {@inheritDoc}
189         */
190        public void removeTreeModelListener(TreeModelListener l) {
191            modelSupport.removeTreeModelListener(l);
192        }
193    
194        /**
195         * Returns an array of all the <code>TreeModelListener</code>s added
196         * to this JXTreeTable with addTreeModelListener().
197         *
198         * @return all of the <code>TreeModelListener</code>s added or an empty
199         *         array if no listeners have been added
200         */
201        public TreeModelListener[] getTreeModelListeners() {
202            return modelSupport.getTreeModelListeners();
203        }
204    }