diff -r 04d674b90c8a openide.nodes/apichanges.xml --- a/openide.nodes/apichanges.xml Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/apichanges.xml Thu Sep 09 08:57:18 2010 +0200 @@ -49,6 +49,24 @@ Nodes API + + + A mechanism to lazily update node's children. + + + + + +

+ Children have + a new createLazy(Callable<Children> factory) method, that can be used + to provide a lazy children implementation. Callable.call() is called + just when node's children are really needed. +

+
+ + +
New constructor of IndexedNode diff -r 04d674b90c8a openide.nodes/manifest.mf --- a/openide.nodes/manifest.mf Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/manifest.mf Thu Sep 09 08:57:18 2010 +0200 @@ -2,5 +2,5 @@ OpenIDE-Module: org.openide.nodes OpenIDE-Module-Localizing-Bundle: org/openide/nodes/Bundle.properties AutoUpdate-Essential-Module: true -OpenIDE-Module-Specification-Version: 7.17 +OpenIDE-Module-Specification-Version: 7.18 diff -r 04d674b90c8a openide.nodes/src/org/openide/nodes/Children.java --- a/openide.nodes/src/org/openide/nodes/Children.java Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/src/org/openide/nodes/Children.java Thu Sep 09 08:57:18 2010 +0200 @@ -58,6 +58,7 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; @@ -312,6 +313,19 @@ new SynchChildren (factory); } + /** + * Create a lazy children implementation. + * @param factory The {@link Callable} whose call() method + * is called just when node's children are really needed. + * @return Provides lazy children implementation that can be passed + * to {@link Node} constructor and thus allows the client code to decide + * what children the node should have when {@link Callable#call()} is called. + * @since 7.18 + */ + public static Children createLazy(Callable factory) { + return new LazyChildren(factory); + } + /** Get the parent node of these children. * @return the node attached to this children object, or null if there is none yet */ @@ -1793,6 +1807,74 @@ } } + /** + * Lazy children implementation + */ + static class LazyChildren extends Children { + + private Callable factory; + private Children original; + private final Object originalLock= new Object(); + + LazyChildren(Callable factory) { + this.factory = factory; + } + + Children getOriginal() { + synchronized (originalLock) { + if (original == null) { + try { + original = factory.call(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + return original; + } + } + + @Override + public boolean add(Node[] nodes) { + return getOriginal().add(nodes); + } + + @Override + public boolean remove(Node[] nodes) { + return getOriginal().remove(nodes); + } + + @Override + protected void addNotify() { + getOriginal().addNotify(); + } + + @Override + protected void removeNotify() { + getOriginal().removeNotify(); + } + + @Override + EntrySupport entrySupport() { + return getOriginal().entrySupport(); + } + + @Override + public Node findChild(String name) { + return getOriginal().findChild(name); + } + + + /* + void postInitializeEntrySupport(EntrySupport es) { + if (getNodesEntry() == null) { + nodesEntry = createNodesEntry(); + } + es.setEntries(Collections.singleton(getNodesEntry())); + } + */ + + } + /* static void printNodes (Node[] n) { for (int i = 0; i < n.length; i++) { diff -r 04d674b90c8a openide.nodes/src/org/openide/nodes/FilterNode.java --- a/openide.nodes/src/org/openide/nodes/FilterNode.java Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/src/org/openide/nodes/FilterNode.java Thu Sep 09 08:57:18 2010 +0200 @@ -1075,6 +1075,8 @@ } ); } + } else { + super.updateChildren(); } } diff -r 04d674b90c8a openide.nodes/src/org/openide/nodes/Node.java --- a/openide.nodes/src/org/openide/nodes/Node.java Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/src/org/openide/nodes/Node.java Thu Sep 09 08:57:18 2010 +0200 @@ -465,6 +465,12 @@ * whether children are of the right subclass */ void updateChildren() { + Children ch = hierarchy; + if (ch instanceof Children.LazyChildren) { + // Replace the children with the ones provided lazily: + ch = ((Children.LazyChildren) ch).getOriginal(); + setChildren(ch); + } } /** Allows to change Children of the node. Call to this method aquires diff -r 04d674b90c8a openide.nodes/test/unit/src/org/openide/nodes/SetChildrenTest.java --- a/openide.nodes/test/unit/src/org/openide/nodes/SetChildrenTest.java Mon Sep 06 11:55:18 2010 +0200 +++ b/openide.nodes/test/unit/src/org/openide/nodes/SetChildrenTest.java Thu Sep 09 08:57:18 2010 +0200 @@ -46,6 +46,7 @@ import java.beans.*; import java.util.*; +import java.util.concurrent.Callable; import org.netbeans.junit.*; @@ -261,6 +262,19 @@ GoldenEvent.assertEvents ( nl.getEvents(), goldenEvents, PropertyChangeEvent.class ); } + + /** Test whether Children are retrieved lazily + */ + public void testUpdateChildren() { + UpdateChildrenFactory uchf = new UpdateChildrenFactory(); + AbstractNode n = new AbstractNode(Children.createLazy(uchf)); + assertNull(uchf.newChildren); + assertSame("Children not updated", uchf.newChildrenToReturn, n.getChildren()); + + uchf = new UpdateChildrenFactory(); + n = new AbstractNode(Children.createLazy(uchf)); + assertFalse("Children not updated, the node should not be leaf", n.isLeaf()); + } /** Tests property changes on old and new nodes @@ -290,6 +304,21 @@ } } + private static class UpdateChildrenFactory implements Callable { + + Children newChildrenToReturn = new Children.Array(); + Children newChildren; + + @Override + public Children call() throws Exception { + if (newChildren == null) { + newChildren = newChildrenToReturn; + } + return newChildren; + } + + } + /** Useful class for testing events. */