001/*
002 * $Id: AbstractMutableTreeTableNode.java 3780 2010-09-09 16:17:41Z kschaefe $
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 */
021package org.jdesktop.swingx.treetable;
022
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.Enumeration;
026import java.util.List;
027
028import 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 */
036public 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    @Override
086    public void insert(MutableTreeTableNode child, int index) {
087        if (!allowsChildren) {
088            throw new IllegalStateException("this node cannot accept children");
089        }
090
091        if (children.contains(child)) {
092            children.remove(child);
093            index--;
094        }
095        
096        children.add(index, child);
097
098        if (child.getParent() != this) {
099            child.setParent(this);
100        }
101    }
102
103    /**
104     * {@inheritDoc}
105     */
106    @Override
107    public void remove(int index) {
108        children.remove(index).setParent(null);
109    }
110
111    /**
112     * {@inheritDoc}
113     */
114    @Override
115    public void remove(MutableTreeTableNode node) {
116        children.remove(node);
117        node.setParent(null);
118    }
119
120    /**
121     * {@inheritDoc}
122     */
123    @Override
124    public void removeFromParent() {
125        parent.remove(this);
126    }
127
128    /**
129     * {@inheritDoc}
130     */
131    @Override
132    public void setParent(MutableTreeTableNode newParent) {
133        if (newParent == null || newParent.getAllowsChildren()) {
134            if (parent != null && parent.getIndex(this) != -1) {
135                parent.remove(this);
136            }
137        } else {
138            throw new IllegalArgumentException(
139                    "newParent does not allow children");
140        }
141
142        parent = newParent;
143
144        if (parent != null && parent.getIndex(this) == -1) {
145            parent.insert(this, parent.getChildCount());
146        }
147    }
148
149    /**
150     * Returns this node's user object.
151     * 
152     * @return the Object stored at this node by the user
153     * @see #setUserObject
154     * @see #toString
155     */
156    @Override
157    public Object getUserObject() {
158        return userObject;
159    }
160
161    /**
162     * {@inheritDoc}
163     */
164    @Override
165    public void setUserObject(Object object) {
166        userObject = object;
167    }
168
169    /**
170     * {@inheritDoc}
171     */
172    @Override
173    public TreeTableNode getChildAt(int childIndex) {
174        return children.get(childIndex);
175    }
176
177    /**
178     * {@inheritDoc}
179     */
180    @Override
181    public int getIndex(TreeNode node) {
182        return children.indexOf(node);
183    }
184
185    /**
186     * {@inheritDoc}
187     */
188    @Override
189    public TreeTableNode getParent() {
190        return parent;
191    }
192
193    /**
194     * {@inheritDoc}
195     */
196    @Override
197    public Enumeration<? extends MutableTreeTableNode> children() {
198        return Collections.enumeration(children);
199    }
200
201    /**
202     * {@inheritDoc}
203     */
204    @Override
205    public boolean getAllowsChildren() {
206        return allowsChildren;
207    }
208
209    /**
210     * Determines whether or not this node is allowed to have children. If
211     * {@code allowsChildren} is {@code false}, all of this node's children are
212     * removed.
213     * <p>
214     * Note: By default, a node allows children.
215     * 
216     * @param allowsChildren
217     *            {@code true} if this node is allowed to have children
218     */
219    public void setAllowsChildren(boolean allowsChildren) {
220        this.allowsChildren = allowsChildren;
221
222        if (!this.allowsChildren) {
223            children.clear();
224        }
225    }
226
227    /**
228     * {@inheritDoc}
229     */
230    @Override
231    public int getChildCount() {
232        return children.size();
233    }
234
235    /**
236     * {@inheritDoc}
237     */
238    @Override
239    public boolean isLeaf() {
240        return getChildCount() == 0;
241    }
242
243    /**
244     * Determines whether the specified column is editable.
245     * 
246     * @param column
247     *            the column to query
248     * @return always returns {@code false}
249     */
250    @Override
251    public boolean isEditable(int column) {
252        return false;
253    }
254
255    /**
256     * Sets the value for the given {@code column}.
257     * 
258     * @impl does nothing. It is provided for convenience.
259     * @param aValue
260     *            the value to set
261     * @param column
262     *            the column to set the value on
263     */
264    @Override
265    public void setValueAt(Object aValue, int column) {
266        // does nothing
267    }
268
269    /**
270     * Returns the result of sending <code>toString()</code> to this node's
271     * user object, or null if this node has no user object.
272     * 
273     * @see #getUserObject
274     */
275    @Override
276    public String toString() {
277        if (userObject == null) {
278            return "";
279        } else {
280            return userObject.toString();
281        }
282    }
283}