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
*
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