diff --git a/spi.viewmodel/apichanges.xml b/spi.viewmodel/apichanges.xml --- a/spi.viewmodel/apichanges.xml +++ b/spi.viewmodel/apichanges.xml @@ -366,6 +366,21 @@ + + + Drag and Drop support. + + + + + + This API introduce ReorderableTreeModel and ReorderableTreeModelFilter + that can be used to alter the order of children nodes. + + + + + diff --git a/spi.viewmodel/manifest.mf b/spi.viewmodel/manifest.mf --- a/spi.viewmodel/manifest.mf +++ b/spi.viewmodel/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.spi.viewmodel/2 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/viewmodel/Bundle.properties -OpenIDE-Module-Specification-Version: 1.24 +OpenIDE-Module-Specification-Version: 1.25 diff --git a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java --- a/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java +++ b/spi.viewmodel/src/org/netbeans/modules/viewmodel/TreeModelNode.java @@ -64,6 +64,8 @@ import javax.swing.KeyStroke; import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import org.netbeans.spi.viewmodel.AsynchronousModelFilter; import org.netbeans.spi.viewmodel.AsynchronousModelFilter.CALL; import org.netbeans.spi.viewmodel.ColumnModel; @@ -76,6 +78,7 @@ import org.openide.explorer.view.CheckableNode; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; +import org.openide.nodes.Index; import org.openide.nodes.Node; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; @@ -160,13 +163,34 @@ final TreeModelRoot treeModelRoot, final Object object ) { + this( + model, + columns, + children, + treeModelRoot, + object, + new Index[] { null }); + } + + private TreeModelNode ( + final Models.CompoundModel model, + final ColumnModel[] columns, + final Children children, + final TreeModelRoot treeModelRoot, + final Object object, + final Index[] indexPtr // Hack, because we can not declare variables before call to super() :-( + ) { super ( children, - Lookups.fixed(object, new CheckNodeCookieImpl(model, object)) + createLookup(object, model, children, indexPtr) ); this.model = model; this.treeModelRoot = treeModelRoot; this.object = object; + if (indexPtr[0] != null) { + ((IndexImpl) indexPtr[0]).setNode(this); + setIndexWatcher(indexPtr[0]); + } // // Use the modified CompoundModel class's field to set the @@ -180,6 +204,38 @@ treeModelRoot.registerNode (object, this); refreshNode (); initProperties (columns); + } + + private static Lookup createLookup(Object object, Models.CompoundModel model, + Children ch, Index[] indexPtr) { + CheckNodeCookieImpl cnc = new CheckNodeCookieImpl(model, object); + boolean canReorder; + try { + canReorder = model.canReorder(object); + } catch (UnknownTypeException ex) { + if (!(object instanceof String)) { + Logger.getLogger(TreeModelNode.class.getName()).log(Level.CONFIG, "Model: "+model, ex); + } + canReorder = false; + } + if (canReorder) { + Index i = new IndexImpl(model, object); + indexPtr[0] = i; + return Lookups.fixed(object, cnc, i); + } else { + return Lookups.fixed(object, cnc); + } + } + + private void setIndexWatcher(Index childrenIndex) { + childrenIndex.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + Children ch = getChildren(); + if (ch instanceof TreeModelChildren) { + ((TreeModelChildren) ch).refreshChildren(new TreeModelChildren.RefreshingInfo(false)); + } + } + }); } private static Executor asynchronous(Models.CompoundModel model, CALL asynchCall, Object object) { @@ -1211,8 +1267,51 @@ return refreshSubNodes; } } - } // ItemChildren - + } // TreeModelChildren + + private static final class IndexImpl extends Index.Support { + + private Models.CompoundModel model; + private Object object; + private Node node; + + IndexImpl(Models.CompoundModel model, Object object) { + this.model = model; + this.object = object; + } + + void setNode(Node node) { + this.node = node; + } + + @Override + public Node[] getNodes() { + return node.getChildren().getNodes(); + } + + @Override + public int getNodesCount() { + return node.getChildren().getNodesCount(); + } + + @Override + public void reorder(int[] perm) { + try { + model.reorder(object, perm); + fireChangeEvent(new ChangeEvent(this)); + } catch (UnknownTypeException ex) { + if (!(object instanceof String)) { + Logger.getLogger(TreeModelNode.class.getName()).log(Level.CONFIG, "Model: "+model, ex); + } + } + } + + void fireChange() { + fireChangeEvent(new ChangeEvent(this)); + } + + } + private class MyProperty extends PropertySupport implements Runnable { //LazyEvaluator.Evaluable { private String id; diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java --- a/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/Models.java @@ -450,11 +450,11 @@ * * @returns compund tree model */ - private static TreeModel createCompoundTreeModel ( - TreeModel originalTreeModel, + private static ReorderableTreeModel createCompoundTreeModel ( + ReorderableTreeModel originalTreeModel, List treeModelFilters ) { - TreeModel tm = originalTreeModel; + ReorderableTreeModel tm = originalTreeModel; int i, k = treeModelFilters.size (); for (i = 0; i < k; i++) tm = new CompoundTreeModel ( @@ -686,10 +686,10 @@ * * @author Jan Jancura */ - private final static class CompoundTreeModel implements TreeModel, ModelListener { + private final static class CompoundTreeModel implements ReorderableTreeModel, ModelListener { - private TreeModel model; + private ReorderableTreeModel model; private TreeModelFilter filter; private final Collection modelListeners = new HashSet(); @@ -699,7 +699,7 @@ * Creates {@link org.netbeans.spi.viewmodel.TreeModel} for given TreeModel and * {@link org.netbeans.spi.viewmodel.TreeModelFilter}. */ - CompoundTreeModel (TreeModel model, TreeModelFilter filter) { + CompoundTreeModel (ReorderableTreeModel model, TreeModelFilter filter) { this.model = model; this.filter = filter; } @@ -754,6 +754,22 @@ */ public boolean isLeaf (Object node) throws UnknownTypeException { return filter.isLeaf (model, node); + } + + public boolean canReorder(Object parent) throws UnknownTypeException { + if (filter instanceof ReorderableTreeModelFilter) { + return ((ReorderableTreeModelFilter) filter).canReorder(model, parent); + } else { + return model.canReorder(parent); + } + } + + public void reorder(Object parent, int[] perm) throws UnknownTypeException { + if (filter instanceof ReorderableTreeModelFilter) { + ((ReorderableTreeModelFilter) filter).reorder(model, parent, perm); + } else { + model.reorder(parent, perm); + } } /** @@ -1278,7 +1294,7 @@ * * @author Jan Jancura */ - private final static class DelegatingTreeModel implements TreeModel { + private final static class DelegatingTreeModel implements ReorderableTreeModel { private TreeModel[] models; private HashMap classNameToModel = new HashMap(); @@ -1305,7 +1321,7 @@ * * @param models a array of TreeModel */ - DelegatingTreeModel (TreeModel[] models) { + private DelegatingTreeModel (TreeModel[] models) { this.models = models; } @@ -1410,7 +1426,70 @@ } } throw new UnknownTypeException (node); - } + } + + public boolean canReorder(Object parent) throws UnknownTypeException { + UnknownTypeException uex = null; + TreeModel model = classNameToModel.get ( + parent.getClass ().getName () + ); + if (model != null) { + if (model instanceof ReorderableTreeModel) { + try { + return ((ReorderableTreeModel) model).canReorder (parent); + } catch (UnknownTypeException e) { + uex = e; + } + } + } + int i, k = models.length; + boolean isIndexed = false; + for (i = 0; i < k; i++) { + if (models[i] instanceof ReorderableTreeModel) { + try { + boolean cr = ((ReorderableTreeModel) models [i]).canReorder (parent); + //classNameToModel.put (parent.getClass ().getName (), models [i]); + return cr; + } catch (UnknownTypeException e) { + uex = e; + } + isIndexed = true; + } + } + if (!isIndexed) { + return false; + } + if (uex != null) { + throw uex; + } else { + throw new UnknownTypeException (parent); + } + } + + public void reorder(Object parent, int[] perm) throws UnknownTypeException { + TreeModel model = (TreeModel) classNameToModel.get ( + parent.getClass ().getName () + ); + if (model instanceof ReorderableTreeModel) { + try { + ((ReorderableTreeModel) model).reorder(parent, perm); + return ; + } catch (UnknownTypeException e) { + } + } + int i, k = models.length; + for (i = 0; i < k; i++) { + if (models[i] instanceof ReorderableTreeModel) { + try { + ((ReorderableTreeModel) models[i]).reorder(parent, perm); + //classNameToModel.put (parent.getClass ().getName (), models [i]); + return ; + } catch (UnknownTypeException e) { + } + } + } + throw new UnknownTypeException (parent); + } /** * Registers given listener. @@ -3236,10 +3315,10 @@ * @see Models#createCompoundModel * @author Jan Jancura */ - public static final class CompoundModel implements TreeModel, + public static final class CompoundModel implements ReorderableTreeModel, ExtendedNodeModel, CheckNodeModel, DnDNodeModel, NodeActionsProvider, TableModel, TreeExpansionModel { - private TreeModel treeModel; + private ReorderableTreeModel treeModel; private ExtendedNodeModel nodeModel; private CheckNodeModel cnodeModel; private DnDNodeModel dndNodeModel; @@ -3270,7 +3349,7 @@ * @param nodeActionsProvider a columns modeol to delegate on */ private CompoundModel ( - TreeModel treeModel, + ReorderableTreeModel treeModel, TreeExpansionModel treeExpansionModel, ExtendedNodeModel nodeModel, NodeActionsProvider nodeActionsProvider, @@ -3394,6 +3473,15 @@ return treeModel.isLeaf (node); } + // ReorderableTreeModel ............................................................... + + public boolean canReorder(Object parent) throws UnknownTypeException { + return treeModel.canReorder(parent); + } + + public void reorder(Object parent, int[] perm) throws UnknownTypeException { + treeModel.reorder(parent, perm); + } // NodeModel ............................................................... diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModel.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModel.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModel.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.viewmodel; + +/** + * Data model for tree that supports reordering + * of child nodes. The created {@link org.openide.nodes.Children} will + * implement {@link org.openide.nodes.Index} if {@link #canReorder(java.lang.Object)} + * returns true. + *

+ * When used together with {@link DnDNodeModel}, children can be reordered + * by Drag and Drop. + * + * @author Martin Entlicher + * @since 1.25 + */ +public interface ReorderableTreeModel extends TreeModel { + + /** + * Provide if this model implementation can reorder children nodes. + * @param parent The parent node of children that are test for reorder + * @return true if this model can handle reordering of children, + * false otherwise + * @throws UnknownTypeException if this model implementation is not + * able to decide the reorder capability for given node type + */ + public boolean canReorder(Object parent) throws UnknownTypeException; + + /** + * Reorder children nodes with a given permutation. + * @param parent The parent node of children that are being reordered + * @param perm permutation with the length of current child nodes. The permutation + * lists the new positions of the original nodes, that is, for nodes + * [A,B,C,D] and permutation [0,3,1,2], the final + * order would be [A,C,D,B]. + * @throws IllegalArgumentException if the permutation is not valid + * @throws UnknownTypeException if this model implementation is not + * able to perform the reorder for given node type + */ + public void reorder(Object parent, int[] perm) throws UnknownTypeException; + +} diff --git a/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModelFilter.java b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModelFilter.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/src/org/netbeans/spi/viewmodel/ReorderableTreeModelFilter.java @@ -0,0 +1,78 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.viewmodel; + +/** + * Filters an original tree data model that supports reordering + * of child nodes. The created {@link org.openide.nodes.Children} will + * implement {@link org.openide.nodes.Index} if + * {@link #canReorder(org.netbeans.spi.viewmodel.ReorderableTreeModel, java.lang.Object)} + * returns true. + * + * @author Martin Entlicher + * @since 1.25 + */ +public interface ReorderableTreeModelFilter extends TreeModelFilter { + + /** + * Provide if this filter implementation can reorder children nodes. + * @param original The original ReorderableTreeModel + * @param parent The parent node of children that are test for reorder + * @return true if this model can handle reordering of children, + * false otherwise + * @throws UnknownTypeException if this model implementation is not + * able to decide the reorder capability for given node type + */ + public boolean canReorder(ReorderableTreeModel original, Object parent) throws UnknownTypeException; + + /** + * Reorder children nodes with a given permutation. + * @param parent The parent node of children that are being reordered + * @param perm permutation with the length of current child nodes. The permutation + * lists the new positions of the original nodes, that is, for nodes + * [A,B,C,D] and permutation [0,3,1,2], the final + * order would be [A,C,D,B]. + * @throws IllegalArgumentException if the permutation is not valid + * @throws UnknownTypeException if this model implementation is not + * able to perform the reorder for given node type + */ + public void reorder(ReorderableTreeModel original, Object parent, int[] perm) throws UnknownTypeException; + +} diff --git a/spi.viewmodel/test/unit/src/org/netbeans/modules/viewmodel/ReorderableTreeModelTest.java b/spi.viewmodel/test/unit/src/org/netbeans/modules/viewmodel/ReorderableTreeModelTest.java new file mode 100644 --- /dev/null +++ b/spi.viewmodel/test/unit/src/org/netbeans/modules/viewmodel/ReorderableTreeModelTest.java @@ -0,0 +1,199 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.viewmodel; + +import java.util.ArrayList; +import java.util.Arrays; +import org.netbeans.junit.NbTestCase; +import org.netbeans.spi.viewmodel.Model; +import org.netbeans.spi.viewmodel.ModelEvent; +import org.netbeans.spi.viewmodel.ModelListener; +import org.netbeans.spi.viewmodel.Models; +import org.netbeans.spi.viewmodel.NodeModel; +import org.netbeans.spi.viewmodel.ReorderableTreeModel; +import org.netbeans.spi.viewmodel.TreeModel; +import org.netbeans.spi.viewmodel.UnknownTypeException; +import org.openide.nodes.Index; +import org.openide.nodes.Node; +import org.openide.util.RequestProcessor; + +/** + * Tests that reorderable model produces node with Index implementation + * + * @author Martin Entlicher + */ +public class ReorderableTreeModelTest extends NbTestCase { + + private Node root; + + public ReorderableTreeModelTest (String s) { + super (s); + } + + private void setUpModel() { + Model m = new ReorderableModelImpl(); + + ArrayList l = new ArrayList (); + l.add(m); + Models.CompoundModel mcm = Models.createCompoundModel(l); + OutlineTable tt = BasicTest.createView(mcm); + + RequestProcessor rp = tt.currentTreeModelRoot.getRootNode().getRequestProcessor(); + BasicTest.waitFinished (rp); + + root = tt.getExplorerManager ().getRootContext (); + } + + public void testChildrenReorder() { + setUpModel(); + + Index indexImpl = root.getLookup().lookup(Index.class); + assertNull("Root must not provide Index, root is not reordeable!", indexImpl); + + Node[] ch1 = root.getChildren().getNodes(); + assertEquals(2, ch1.length); + + indexImpl = ch1[1].getLookup().lookup(Index.class); + assertNull(ch1[1]+ " must not provide Index, it is not reordeable!", indexImpl); + indexImpl = ch1[0].getLookup().lookup(Index.class); + assertNotNull(ch1[0]+ " must provide Index, it is reordeable!", indexImpl); + + indexImpl.reorder(new int[] { 2, 0, 1, 4, 3 }); + // => "3", "1", "2", "5", "4" + String[] reorderedNames = new String[] { "2", "3", "1", "5", "4" }; + Node[] reorderedNodes = ch1[0].getChildren().getNodes(); + assertEquals(reorderedNames.length, reorderedNodes.length); + String nodes = "Nodes = "+Arrays.toString(reorderedNodes); + for (int i = 0; i < reorderedNodes.length; i++) { + assertEquals(nodes, reorderedNames[i], reorderedNodes[i].getDisplayName()); + } + } + + private static final class ReorderableModelImpl implements ReorderableTreeModel, NodeModel { + + private static final String CAN_REORDER = "canReorder"; + private static final String CAN_NOT_REORDER = "canNotReorder"; + + private final String[] childrenReordered = new String[] { "1", "2", "3", "4", "5" }; + + public boolean canReorder(Object parent) throws UnknownTypeException { + return /*ROOT == parent ||*/ CAN_REORDER.equals(parent); + } + + public void reorder(Object parent, int[] perm) throws UnknownTypeException { + //System.err.println("reorder("+parent+", "+Arrays.toString(perm)+")"); + //Thread.dumpStack(); + if (!(/*ROOT == parent ||*/ CAN_REORDER.equals(parent))) { + throw new IllegalStateException("reorder called on "+parent); + } + if (perm.length != childrenReordered.length) { + throw new IllegalArgumentException("Permutation of length "+perm.length+", but have "+childrenReordered.length+" children."); + } + checkPermutation(perm); + String[] ch = childrenReordered.clone(); + for (int i = 0; i < ch.length; i++) { + //System.err.println("ch["+perm[i]+"] = "+ch[i]); + childrenReordered[perm[i]] = ch[i]; + } + } + + private static void checkPermutation(int[] permutation) throws IllegalArgumentException { + int max = permutation.length; + int[] check = new int[max]; + for (int i = 0; i < max; i++) { + int p = permutation[i]; + if (p >= max) { + throw new IllegalArgumentException("Permutation "+Arrays.toString(permutation)+" is not a valid permutation, it contains element "+p+", which is bigger than the length of the permutation."); + } + if (p < 0) { + throw new IllegalArgumentException("Permutation "+Arrays.toString(permutation)+" is not a valid permutation, it contains element "+p+", which is negative."); + } + if (check[p] != 0) { + throw new IllegalArgumentException("Permutation "+Arrays.toString(permutation)+" is not a valid permutation, it contains element "+p+" twice or more times."); + } + check[p] = 1; + } + } + + public Object getRoot() { + return ROOT; + } + + public Object[] getChildren(Object parent, int from, int to) throws UnknownTypeException { + if (ROOT == parent) { + return new String[] { CAN_REORDER, CAN_NOT_REORDER }; + } else if (CAN_REORDER.equals(parent)) { + return childrenReordered; + } else if (CAN_NOT_REORDER.equals(parent)) { + return new String[] { "a", "b", "c", "d", "e" }; + } else { + return new Object[] {}; + } + } + + public boolean isLeaf(Object node) throws UnknownTypeException { + return ((String) node).length() == 1; + } + + public int getChildrenCount(Object node) throws UnknownTypeException { + return Integer.MAX_VALUE; + } + + public void addModelListener(ModelListener l) { + } + + public void removeModelListener(ModelListener l) { + } + + public String getDisplayName(Object node) throws UnknownTypeException { + return (String) node; + } + + public String getIconBase(Object node) throws UnknownTypeException { + return null; + } + + public String getShortDescription(Object node) throws UnknownTypeException { + return node+" of "+getClass().getSimpleName(); + } + + } + +}