diff -r 2956292dd8d7 javafx-ui-common/src/javafx/scene/Node.java --- a/javafx-ui-common/src/javafx/scene/Node.java Thu Jul 19 09:57:16 2012 -0700 +++ b/javafx-ui-common/src/javafx/scene/Node.java Thu Jul 19 18:04:37 2012 -0700 @@ -2096,8 +2096,9 @@ @Override protected void invalidated() { - if (getParent() != null) { - getParent().requestLayout(); + final Parent parent = getParent(); + if (parent != null) { + parent.managedChildChanged(); } } diff -r 2956292dd8d7 javafx-ui-common/src/javafx/scene/Parent.java --- a/javafx-ui-common/src/javafx/scene/Parent.java Thu Jul 19 09:57:16 2012 -0700 +++ b/javafx-ui-common/src/javafx/scene/Parent.java Thu Jul 19 18:04:37 2012 -0700 @@ -34,7 +34,6 @@ import com.sun.javafx.jmx.MXNodeAlgorithm; import com.sun.javafx.jmx.MXNodeAlgorithmContext; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener.Change; @@ -71,11 +70,10 @@ * child nodes, marking branches dirty for layout and rendering, picking, * bounds calculations, and executing the layout pass on each pulse. *

- * There are three direct concrete Parent subclasses + * There are two direct concrete Parent subclasses *

* */ @@ -91,7 +89,7 @@ * Threshold when it's worth to populate list of removed children. */ private static final int REMOVED_CHILDREN_THRESHOLD = 20; - + /** * Do not populate list of removed children when its number exceeds threshold, * but mark whole parent dirty. @@ -212,7 +210,7 @@ //accumulates all removed nodes between pulses, for dirty area calculation. private List removed; - + /** * A ObservableList of child {@code Node}s. *

@@ -382,8 +380,9 @@ protected void onChanged(Change c) { // proceed with updating the scene graph if (childrenModified) { + unmodifiableManagedChildren = null; boolean relayout = false; - + while (c.next()) { int from = c.getFrom(); int to = c.getTo(); @@ -413,7 +412,7 @@ relayout = true; } } - + // update the parent and scene for each new node for (int i = from; i < to; ++i) { Node node = children.get(i); @@ -461,8 +460,8 @@ // its siblings. Thus, it is only necessary to reapply css to // the Node just added and not to this parent and all of its // children. So the following call to impl_reapplyCSS was moved - // to Node.parentProperty. The orginal comment and code were - // purpopsely left here as documentation should there be any + // to Node.parentProperty. The original comment and code were + // purposely left here as documentation should there be any // question about how the code used to work and why the change // was made. // @@ -505,6 +504,24 @@ }; /** + * A constant reference to an unmodifiable view of the children, such that every time + * we ask for an unmodifiable list of children, we don't actually create a new + * collection and return it. The memory overhead is pretty lightweight compared + * to all the garbage we would otherwise generate. + */ + private final ObservableList unmodifiableChildren = + FXCollections.unmodifiableObservableList(children); + + /** + * A cached reference to the unmodifiable managed children of this Parent. This is + * created whenever first asked for, and thrown away whenever children are added + * or removed or when their managed state changes. This could be written + * differently, such that this list is essentially a filtered copy of the + * main children, but that additional overhead might not be worth it. + */ + private List unmodifiableManagedChildren = null; + + /** * Gets the list of children of this {@code Parent}. * *

@@ -520,6 +537,13 @@ * An {@link IllegalStateException} is thrown if this restriction is * violated. * + *

+ * Note to subclasses: if you override this method, you must return from + * your implementation the result of calling this super method. The actual + * list instance returned from any getChildren() implementation must be + * the list owned and managed by this Parent. The only typical purpose + * for overriding this method is to promote the method to be public. + * * @return the list of children of this {@code Parent}. */ protected ObservableList getChildren() { @@ -534,7 +558,7 @@ */ @ReturnsUnmodifiableCollection public ObservableList getChildrenUnmodifiable() { - return FXCollections.unmodifiableObservableList(children); + return unmodifiableChildren; } /** @@ -543,14 +567,28 @@ * @param the type of the children nodes * @return list of all managed children in this parent */ + @ReturnsUnmodifiableCollection protected List getManagedChildren() { - List managed = new ArrayList(); - for (E e : (ObservableList)getChildren()) { - if (e != null && e.isManaged()) { - managed.add(e); + if (unmodifiableManagedChildren == null) { + unmodifiableManagedChildren = new ArrayList(); + for (int i=0, max=children.size(); i)unmodifiableManagedChildren; + } + + /** + * Called by Node whenever its managed state may have changed, this + * method will cause the view of managed children to be updated + * such that it properly includes or excludes this child. + */ + final void managedChildChanged() { + requestLayout(); + unmodifiableManagedChildren = null; } // implementation of Node.toFront function @@ -593,73 +631,37 @@ } } - private void computeDirtyScene(Scene old) { - for (Node node : getChildren()) { + @Override void sceneChanged(final Scene old) { + // Give all of the children the new scene + final Scene scene = getScene(); + for (int i=0, max=children.size(); i 0) { - return children.get(0); - } else { - return null; - } - } - - Node getLastChild() { - if (!children.isEmpty()) { - return children.get(children.size() - 1); - } else { - return null; - } - } - - Node getNextChild(Node child) { - Node previous = null; - for (Node node : children) { - if (child == previous) { - return node; - } - previous = node; - } - return null; - } - - Node getPreviousChild(Node child) { - Node previous = null; - for (int i = (children.size()-1); i >= 0; i--) { - Node node = children.get(i); - if (child == previous) { - return node; - } - previous = node; - } - return null; - } - @Override void setDerivedDepthTest(boolean value) { super.setDerivedDepthTest(value); - ObservableList myChildren = getChildren(); - for (int i = 0; i < myChildren.size(); i++) { - Node node = myChildren.get(i); + for (int i=0, max=children.size(); i= 0; i--) { - Node picked = children.get(i).impl_pickNode(pickRay); + for (int i = children.size()-1; i >= 0; i--) { + Node picked = children.get(i).impl_pickNode(pickRay); - if (picked != null) { - return picked; - } + if (picked != null) { + return picked; } + } return null; } @@ -704,9 +706,9 @@ @Override public Node lookup(String selector) { Node n = super.lookup(selector); if (n == null) { - int size = children.size(); - for (int i = 0; i < size; ++i) { - n = children.get(i).lookup(selector); + for (int i=0, max=children.size(); i lookupAll(Selector selector, List results) { results = super.lookupAll(selector, results); - int size = children.size(); - for (int i = 0; i < size; ++i) { - results = children.get(i).lookupAll(selector, results); + for (int i=0, max=children.size(); i impl_traversalEngine; - /** * @treatAsPrivate implementation detail * @deprecated This is an internal API that is not intended for use and will be removed in the next version @@ -774,25 +775,18 @@ * Indicates that this Node and its subnodes requires a layout pass on * the next pulse. */ - private ReadOnlyBooleanWrapper needsLayout; + private ReadOnlyBooleanWrapper needsLayout = new ReadOnlyBooleanWrapper(this, "needsLayout", true); protected final void setNeedsLayout(boolean value) { - needsLayoutPropertyImpl().set(value); + needsLayout.set(value); } public final boolean isNeedsLayout() { - return needsLayout == null ? true : needsLayout.get(); + return needsLayout.get(); } public final ReadOnlyBooleanProperty needsLayoutProperty() { - return needsLayoutPropertyImpl().getReadOnlyProperty(); - } - - private ReadOnlyBooleanWrapper needsLayoutPropertyImpl() { - if (needsLayout == null) { - needsLayout = new ReadOnlyBooleanWrapper(this, "needsLayout", true); - } - return needsLayout; + return needsLayout.getReadOnlyProperty(); } /** @@ -831,14 +825,18 @@ setNeedsLayout(true); if (isLayoutRoot()) { - if (getScene() != null) { + final Scene scene = getScene(); + if (scene != null) { if (logger.isLoggable(PlatformLogger.FINER)) { logger.finer(this.toString()+" layoutRoot added to scene dirty layout list"); } - getScene().addToDirtyLayoutList(this); + scene.addToDirtyLayoutList(this); } - } else if (getParent() != null) { - getParent().requestLayout(); + } else { + final Parent parent = getParent(); + if (parent != null) { + parent.requestLayout(); + } } } else { clearSizeCache(); @@ -855,8 +853,9 @@ minWidthCache = -1; minHeightCache = -1; if (!isLayoutRoot()) { - if (getParent() != null) { - getParent().clearSizeCache(); + final Parent parent = getParent(); + if (parent != null) { + parent.clearSizeCache(); } } } @@ -866,7 +865,7 @@ if (prefWidthCache == -1) { prefWidthCache = computePrefWidth(-1); sizeCacheClear = false; - } + } return prefWidthCache; } else { return computePrefWidth(height); @@ -878,7 +877,7 @@ if (prefHeightCache == -1) { prefHeightCache = computePrefHeight(-1); sizeCacheClear = false; - } + } return prefHeightCache; } else { return computePrefHeight(width); @@ -923,8 +922,8 @@ protected double computePrefWidth(double height) { double minX = 0; double maxX = 0; - for (int i = 0; i < getChildren().size(); i++) { - Node node = getChildren().get(i); + for (int i=0, max=children.size(); i _children_ = getChildren(); - final int count = _children_.size(); - for (int i=0; i getStylesheets() { return stylesheets; } - /** * This method recurses up the parent chain until parent is null. As the * stack unwinds, if the Parent has stylesheets, they are added to the @@ -1145,10 +1140,8 @@ // Let the super implementation handle CSS for this node super.impl_processCSS(flag); // For each child, process CSS - final List kids = this.getChildren(); - final int max = kids.size(); - for (int c=0; c _children_ = getChildren(); - final int count = _children_.size(); - for (int i=0; i _children_ = getChildren(); - final int count = _children_.size(); - for (int i=0; i