001    /*
002     * $Id: AbstractMutableTreeTableNode.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    package org.jdesktop.swingx.treetable;
022    
023    import java.util.ArrayList;
024    import java.util.Collections;
025    import java.util.Enumeration;
026    import java.util.List;
027    
028    import javax.swing.tree.TreeNode;
029    
030    /**
031     * {@code AbstractMutableTreeTableNode} provides an implementation of most of
032     * the {@code MutableTreeTableNode} features.
033     * 
034     * @author Karl Schaefer
035     */
036    public abstract class AbstractMutableTreeTableNode implements
037            MutableTreeTableNode {
038        /** this node's parent, or null if this node has no parent */
039        protected MutableTreeTableNode parent;
040    
041        /**
042         * List of children, if this node has no children the list will be empty.
043         * This list will never be null.
044         */
045        protected final List<MutableTreeTableNode> children;
046    
047        /** optional user object */
048        protected transient Object userObject;
049    
050        protected boolean allowsChildren;
051    
052        public AbstractMutableTreeTableNode() {
053            this(null);
054        }
055    
056        public AbstractMutableTreeTableNode(Object userObject) {
057            this(userObject, true);
058        }
059    
060        public AbstractMutableTreeTableNode(Object userObject,
061                boolean allowsChildren) {
062            this.userObject = userObject;
063            this.allowsChildren = allowsChildren;
064            children = createChildrenList();
065        }
066    
067        /**
068         * Creates the list used to manage the children of this node.
069         * <p>
070         * This method is called by the constructor.
071         * 
072         * @return a list; this list is guaranteed to be non-{@code null}
073         */
074        protected List<MutableTreeTableNode> createChildrenList() {
075            return new ArrayList<MutableTreeTableNode>();
076        }
077        
078        public void add(MutableTreeTableNode child) {
079            insert(child, getChildCount());
080        }
081    
082        /**
083         * {@inheritDoc}
084         */
085        public void insert(MutableTreeTableNode child, int index) {
086            if (!allowsChildren) {
087                throw new IllegalStateException("this node cannot accept children");
088            }
089    
090            if (children.contains(child)) {
091                children.remove(child);
092                index--;
093            }
094            
095            children.add(index, child);
096    
097            if (child.getParent() != this) {
098                child.setParent(this);
099            }
100        }
101    
102        /**
103         * {@inheritDoc}
104         */
105        public void remove(int index) {
106            children.remove(index).setParent(null);
107        }
108    
109        /**
110         * {@inheritDoc}
111         */
112        public void remove(MutableTreeTableNode node) {
113            children.remove(node);
114            node.setParent(null);
115        }
116    
117        /**
118         * {@inheritDoc}
119         */
120        public void removeFromParent() {
121            parent.remove(this);
122        }
123    
124        /**
125         * {@inheritDoc}
126         */
127        public void setParent(MutableTreeTableNode newParent) {
128            if (newParent == null || newParent.getAllowsChildren()) {
129                if (parent != null && parent.getIndex(this) != -1) {
130                    parent.remove(this);
131                }
132            } else {
133                throw new IllegalArgumentException(
134                        "newParent does not allow children");
135            }
136    
137            parent = newParent;
138    
139            if (parent != null && parent.getIndex(this) == -1) {
140                parent.insert(this, parent.getChildCount());
141            }
142        }
143    
144        /**
145         * Returns this node's user object.
146         * 
147         * @return the Object stored at this node by the user
148         * @see #setUserObject
149         * @see #toString
150         */
151        public Object getUserObject() {
152            return userObject;
153        }
154    
155        /**
156         * {@inheritDoc}
157         */
158        public void setUserObject(Object object) {
159            userObject = object;
160        }
161    
162        /**
163         * {@inheritDoc}
164         */
165        public TreeTableNode getChildAt(int childIndex) {
166            return children.get(childIndex);
167        }
168    
169        /**
170         * {@inheritDoc}
171         */
172        public int getIndex(TreeNode node) {
173            return children.indexOf(node);
174        }
175    
176        /**
177         * {@inheritDoc}
178         */
179        public TreeTableNode getParent() {
180            return parent;
181        }
182    
183        /**
184         * {@inheritDoc}
185         */
186        public Enumeration<? extends MutableTreeTableNode> children() {
187            return Collections.enumeration(children);
188        }
189    
190        /**
191         * {@inheritDoc}
192         */
193        public boolean getAllowsChildren() {
194            return allowsChildren;
195        }
196    
197        /**
198         * Determines whether or not this node is allowed to have children. If
199         * {@code allowsChildren} is {@code false}, all of this node's children are
200         * removed.
201         * <p>
202         * Note: By default, a node allows children.
203         * 
204         * @param allowsChildren
205         *            {@code true} if this node is allowed to have children
206         */
207        public void setAllowsChildren(boolean allowsChildren) {
208            this.allowsChildren = allowsChildren;
209    
210            if (!this.allowsChildren) {
211                children.clear();
212            }
213        }
214    
215        /**
216         * {@inheritDoc}
217         */
218        public int getChildCount() {
219            return children.size();
220        }
221    
222        /**
223         * {@inheritDoc}
224         */
225        public boolean isLeaf() {
226            return getChildCount() == 0;
227        }
228    
229        /**
230         * Determines whether the specified column is editable.
231         * 
232         * @param column
233         *            the column to query
234         * @return always returns {@code false}
235         */
236        public boolean isEditable(int column) {
237            return false;
238        }
239    
240        /**
241         * Sets the value for the given {@code column}.
242         * 
243         * @impl does nothing. It is provided for convenience.
244         * @param aValue
245         *            the value to set
246         * @param column
247         *            the column to set the value on
248         */
249        public void setValueAt(Object aValue, int column) {
250            // does nothing
251        }
252    
253        /**
254         * Returns the result of sending <code>toString()</code> to this node's
255         * user object, or null if this node has no user object.
256         * 
257         * @see #getUserObject
258         */
259        @Override
260        public String toString() {
261            if (userObject == null) {
262                return "";
263            } else {
264                return userObject.toString();
265            }
266        }
267    }