Committing tree speed up code based on
* avoiding creation of images
* avoiding creation of table elements
* cloning when possible
* delaying rendering costs
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2430 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index 38fec29..e7ddd75 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -112,14 +112,14 @@
}
static native boolean shouldTreeDelegateFocusToElement(Element elem) /*-{
- var name = elem.nodeName;
- return ((name == "SELECT") ||
- (name == "INPUT") ||
- (name == "TEXTAREA") ||
- (name == "OPTION") ||
- (name == "BUTTON") ||
- (name == "LABEL"));
- }-*/;
+ var name = elem.nodeName;
+ return ((name == "SELECT") ||
+ (name == "INPUT") ||
+ (name == "TEXTAREA") ||
+ (name == "OPTION") ||
+ (name == "BUTTON") ||
+ (name == "LABEL"));
+ }-*/;
/**
* Map of TreeItem.widget -> TreeItem.
@@ -140,15 +140,20 @@
* a duplicate key down.
*/
private int lastEventType;
+ private Image leafImage;
+ private Image openImage;
+ private Image closedImage;
+
+ private String indentValue;
/**
* Constructs an empty tree.
*/
public Tree() {
if (LocaleInfo.getCurrentLocale().isRTL()) {
- init(GWT.<TreeImagesRTL>create(TreeImagesRTL.class));
+ init(GWT.<TreeImagesRTL> create(TreeImagesRTL.class), false);
} else {
- init(GWT.<TreeImages>create(TreeImages.class));
+ init(GWT.<TreeImages> create(TreeImages.class), false);
}
}
@@ -158,7 +163,19 @@
* @param images a bundle that provides tree specific images
*/
public Tree(TreeImages images) {
- init(images);
+ init(images, true);
+ }
+
+ /**
+ * Constructs a tree that uses the specified image bundle for images. If this
+ * tree does not use leaf images, the width of the TreeImage's leaf image will
+ * control the leaf indent.
+ *
+ * @param images a bundle that provides tree specific images
+ * @param useLeafImages use leaf images from bundle
+ */
+ public Tree(TreeImages images, boolean useLeafImages) {
+ init(images, useLeafImages);
}
/**
@@ -425,24 +442,24 @@
break;
}
case KeyboardListener.KEY_LEFT: {
-
+
if (LocaleInfo.getCurrentLocale().isRTL()) {
maybeExpandTreeItem();
} else {
maybeCollapseTreeItem();
}
-
+
DOM.eventPreventDefault(event);
break;
}
case KeyboardListener.KEY_RIGHT: {
-
+
if (LocaleInfo.getCurrentLocale().isRTL()) {
maybeCollapseTreeItem();
} else {
maybeExpandTreeItem();
}
-
+
DOM.eventPreventDefault(event);
break;
}
@@ -681,9 +698,9 @@
void maybeUpdateSelection(TreeItem itemThatChangedState, boolean isItemOpening) {
/**
- * If we just closed the item, let's check to see if this item is the parent of
- * the currently selected item. If so, we should make this item the currently selected
- * selected item.
+ * If we just closed the item, let's check to see if this item is the parent
+ * of the currently selected item. If so, we should make this item the
+ * currently selected selected item.
*/
if (!isItemOpening) {
TreeItem tempItem = curSelection;
@@ -696,6 +713,7 @@
}
}
}
+
void orphan(Widget widget) {
// Validation should already be done.
assert (widget.getParent() == this);
@@ -708,9 +726,42 @@
}
/**
+ * Called only from {@link TreeItem}: Shows the closed image on that tree
+ * item.
+ *
+ * @param treeItem the tree item
+ */
+ void showClosedImage(TreeItem treeItem) {
+ showImage(treeItem, closedImage);
+ }
+
+ /**
+ * Called only from {@link TreeItem}: Shows the leaf image on a tree item.
+ *
+ * @param treeItem the tree item
+ */
+ void showLeafImage(TreeItem treeItem) {
+ if (leafImage != null) {
+ showImage(treeItem, leafImage);
+ } else {
+ DOM.setStyleAttribute(treeItem.getElement(), "paddingLeft", indentValue);
+ }
+ }
+
+ /**
+ * Called only from {@link TreeItem}: Shows the open image on a tree item.
+ *
+ * @param treeItem the tree item
+ */
+ void showOpenImage(TreeItem treeItem) {
+ showImage(treeItem, openImage);
+ }
+
+ /**
* Collects parents going up the element tree, terminated at the tree root.
*/
- private void collectElementChain(ArrayList<Element> chain, Element hRoot, Element hElem) {
+ private void collectElementChain(ArrayList<Element> chain, Element hRoot,
+ Element hElem) {
if ((hElem == null) || (hElem == hRoot)) {
return;
}
@@ -725,7 +776,8 @@
TreeItem item = findItemByChain(chain, 0, root);
if (item != null) {
- if (DOM.isOrHasChild(item.getImageElement(), hElem)) {
+ if (item.getChildCount() > 0
+ && DOM.isOrHasChild(item.getImageElement(), hElem)) {
item.setState(!item.getState(), true);
return true;
} else if (DOM.isOrHasChild(item.getElement(), hElem)) {
@@ -744,7 +796,8 @@
return findDeepestOpenChild(item.getChild(item.getChildCount() - 1));
}
- private TreeItem findItemByChain(ArrayList<Element> chain, int idx, TreeItem root) {
+ private TreeItem findItemByChain(ArrayList<Element> chain, int idx,
+ TreeItem root) {
if (idx == chain.size()) {
return root;
}
@@ -765,9 +818,9 @@
}
/**
- * Get the top parent above this {@link TreeItem} that is in closed state. In
+ * Get the top parent above this {@link TreeItem} that is in closed state. In
* other words, get the parent that is guaranteed to be visible.
- *
+ *
* @param item
* @return the closed parent, or null if all parents are opened
*/
@@ -783,13 +836,14 @@
return topClosedParent;
}
- private void init(TreeImages images) {
- this.images = images;
+ private void init(TreeImages images, boolean useLeafImages) {
+ setImages(images, useLeafImages);
setElement(DOM.createDiv());
DOM.setStyleAttribute(getElement(), "position", "relative");
-
- // Fix rendering problem with relatively-positioned elements and their children by
+
+ // Fix rendering problem with relatively-positioned elements and their
+ // children by
// forcing the element that is positioned relatively to 'have layout'
DOM.setStyleAttribute(getElement(), "zoom", "1");
@@ -848,6 +902,7 @@
DOM.removeChild(Tree.this.getElement(), item.getElement());
}
};
+ root.initChildren();
root.setTree(this);
setStyleName("gwt-Tree");
@@ -855,7 +910,7 @@
Accessibility.setRole(getElement(), Accessibility.ROLE_TREE);
Accessibility.setRole(focusable, Accessibility.ROLE_TREEITEM);
}
-
+
private void maybeCollapseTreeItem() {
TreeItem topClosedParent = getTopClosedParent(curSelection);
@@ -924,14 +979,15 @@
// Scroll it into view.
DOM.scrollIntoView(focusable);
- // Update ARIA attributes to reflect the information from the newly-selected item.
- updateAriaAttributes();
-
- // Ensure Focus is set, as focus may have been previously delegated by
- // tree.
- setFocus(true);
- }
+ // Update ARIA attributes to reflect the information from the
+ // newly-selected item.
+ updateAriaAttributes();
+
+ // Ensure Focus is set, as focus may have been previously delegated by
+ // tree.
+ setFocus(true);
}
+ }
/**
* Moves to the next item, going into children as if dig is enabled.
@@ -947,7 +1003,7 @@
moveSelectionDown(topClosedParent, false);
return;
}
-
+
TreeItem parent = sel.getParentItem();
if (parent == null) {
parent = root;
@@ -975,7 +1031,7 @@
onSelection(topClosedParent, true, true);
return;
}
-
+
TreeItem parent = sel.getParentItem();
if (parent == null) {
parent = root;
@@ -1014,11 +1070,37 @@
}
}
+ private void setImages(TreeImages images, boolean useLeafImages) {
+ if (useLeafImages) {
+ leafImage = images.treeLeaf().createImage();
+ } else {
+ Image image = images.treeLeaf().createImage();
+ DOM.setStyleAttribute(image.getElement(), "visibility", "hidden");
+ RootPanel.get().add(image);
+ int size = image.getWidth() + TreeItem.IMAGE_PAD;
+ image.removeFromParent();
+ indentValue = (size) + "px";
+ }
+
+ openImage = images.treeOpen().createImage();
+ closedImage = images.treeClosed().createImage();
+ }
+
+ private void showImage(TreeItem treeItem, Image image) {
+ Element element = treeItem.getImageHolderElement();
+ Element child = DOM.getFirstChild(element);
+ if (child != null) {
+ DOM.removeChild(element, child);
+ }
+ DOM.appendChild(element, DOM.clone(image.getElement(), true));
+ }
+
private void updateAriaAttributes() {
Element curSelectionContentElem = curSelection.getContentElem();
- // Set the 'aria-level' state. To do this, we need to compute the level of the
+ // Set the 'aria-level' state. To do this, we need to compute the level of
+ // the
// currently selected item.
// We initialize itemLevel to -1 because the level value is zero-based.
@@ -1038,7 +1120,8 @@
String.valueOf(curSelectionLevel + 1));
// Set the 'aria-setsize' and 'aria-posinset' states. To do this, we need to
- // compute the the number of siblings that the currently selected item has, and
+ // compute the the number of siblings that the currently selected item has,
+ // and
// the item's position among its siblings.
TreeItem curSelectionParent = curSelection.getParentItem();
@@ -1046,35 +1129,42 @@
curSelectionParent = root;
}
- Accessibility.setState(curSelectionContentElem, Accessibility.STATE_SETSIZE,
+ Accessibility.setState(curSelectionContentElem,
+ Accessibility.STATE_SETSIZE,
String.valueOf(curSelectionParent.getChildCount()));
int curSelectionIndex = curSelectionParent.getChildIndex(curSelection);
- Accessibility.setState(curSelectionContentElem, Accessibility.STATE_POSINSET,
- String.valueOf(curSelectionIndex + 1));
+ Accessibility.setState(curSelectionContentElem,
+ Accessibility.STATE_POSINSET, String.valueOf(curSelectionIndex + 1));
- // Set the 'aria-expanded' state. This depends on the state of the currently selected item.
+ // Set the 'aria-expanded' state. This depends on the state of the currently
+ // selected item.
// If the item has no children, we remove the 'aria-expanded' state.
if (curSelection.getChildCount() == 0) {
- Accessibility.removeState(curSelectionContentElem, Accessibility.STATE_EXPANDED);
+ Accessibility.removeState(curSelectionContentElem,
+ Accessibility.STATE_EXPANDED);
} else {
if (curSelection.getState()) {
- Accessibility.setState(curSelectionContentElem, Accessibility.STATE_EXPANDED, "true");
+ Accessibility.setState(curSelectionContentElem,
+ Accessibility.STATE_EXPANDED, "true");
} else {
- Accessibility.setState(curSelectionContentElem, Accessibility.STATE_EXPANDED, "false");
+ Accessibility.setState(curSelectionContentElem,
+ Accessibility.STATE_EXPANDED, "false");
}
}
// Make sure that 'aria-selected' is true.
- Accessibility.setState(curSelectionContentElem, Accessibility.STATE_SELECTED, "true");
+ Accessibility.setState(curSelectionContentElem,
+ Accessibility.STATE_SELECTED, "true");
- // Update the 'aria-activedescendant' state for the focusable element to match the id
+ // Update the 'aria-activedescendant' state for the focusable element to
+ // match the id
// of the currently selected item
Accessibility.setState(focusable, Accessibility.STATE_ACTIVEDESCENDANT,
DOM.getElementAttribute(curSelectionContentElem, "id"));
}
- }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/client/ui/TreeItem.java b/user/src/com/google/gwt/user/client/ui/TreeItem.java
index 4fe5f4f..ff44440 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeItem.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeItem.java
@@ -26,22 +26,24 @@
/**
* An item that can be contained within a
* {@link com.google.gwt.user.client.ui.Tree}.
- *
+ *
* Each tree item is assigned a unique DOM id in order to support ARIA. See
* {@link com.google.gwt.user.client.ui.Accessibility} for more information.
- *
+ *
* <p>
* <h3>Example</h3>
* {@example com.google.gwt.examples.TreeExample}
* </p>
*/
public class TreeItem extends UIObject implements HasHTML {
+
/**
* An {@link WidgetAnimation} used to open the child elements. If a
* {@link TreeItem} is in the process of opening, it will immediately be
* opened and the new {@link TreeItem} will use this animation.
*/
private static class TreeItemAnimation extends WidgetAnimation {
+
/**
* The {@link TreeItem} currently being affected.
*/
@@ -92,10 +94,12 @@
public void onUpdate(double progress) {
int scrollHeight = DOM.getElementPropertyInt(curItem.childSpanElem,
"scrollHeight");
+
int height = (int) (progress * scrollHeight);
if (!opening) {
height = scrollHeight - height;
}
+
DOM.setStyleAttribute(curItem.childSpanElem, "height", height + "px");
// We need to set the width explicitly of the item might be cropped
@@ -125,62 +129,74 @@
}
}
+ // By not overwriting the default tree padding and spacing, we traditionally
+ // added 7 pixels between our image and content.
+ // <2>|<1>image<1>|<2>|<1>content
+ // So to preserve the current spacing we must add a 7 pixel pad when no image
+ // is supplied.
+ static final int IMAGE_PAD = 7;
+
/**
* The static animation used to open {@link TreeItem}s.
*/
- private static TreeItemAnimation itemAnimation;
+ private static TreeItemAnimation itemAnimation = new TreeItemAnimation();
- private ArrayList<TreeItem> children = new ArrayList<TreeItem>();
- private Element itemTable, contentElem, childSpanElem;
- private final Image statusImage = new Image();
+ /**
+ * The structured table to hold images.
+ */
+
+ private static Element BASE_INTERNAL_ELEM;
+ /**
+ * The base tree item element that will be cloned.
+ */
+ private static Element BASE_BARE_ELEM;
+ /**
+ * Static constructor to set up clonable elements.
+ */
+ static {
+ // Create the base table element that will be cloned.
+ BASE_INTERNAL_ELEM = DOM.createTable();
+ setStyleName(BASE_INTERNAL_ELEM, "gwt-TreeItem");
+ Element contentElem = DOM.createSpan();
+ Element tbody = DOM.createTBody(), tr = DOM.createTR();
+ Element tdImg = DOM.createTD(), tdContent = DOM.createTD();
+ DOM.appendChild(BASE_INTERNAL_ELEM, tbody);
+ DOM.appendChild(tbody, tr);
+ DOM.appendChild(tr, tdImg);
+ DOM.appendChild(tr, tdContent);
+ DOM.setStyleAttribute(tdImg, "verticalAlign", "middle");
+ DOM.setStyleAttribute(tdContent, "verticalAlign", "middle");
+ DOM.appendChild(tdContent, contentElem);
+ DOM.setStyleAttribute(contentElem, "display", "inline");
+ DOM.setStyleAttribute(BASE_INTERNAL_ELEM, "whiteSpace", "nowrap");
+
+ // Create the base element that will be cloned
+ BASE_BARE_ELEM = DOM.createDiv();
+
+ // Simulates padding from table element.
+ DOM.setStyleAttribute(BASE_BARE_ELEM, "padding", "3px");
+ DOM.appendChild(BASE_BARE_ELEM, contentElem);
+ Accessibility.setRole(contentElem, Accessibility.ROLE_TREEITEM);
+ }
+ private ArrayList<TreeItem> children;
+ private Element contentElem, childSpanElem, imageHolder;
private boolean open;
private TreeItem parent;
private boolean selected;
+
private Object userObject;
+
private Tree tree;
+
private Widget widget;
/**
* Creates an empty tree item.
*/
public TreeItem() {
- setElement(DOM.createDiv());
- itemTable = DOM.createTable();
- contentElem = DOM.createSpan();
- childSpanElem = DOM.createDiv();
-
- // Uses the following Element hierarchy:
- // <div (handle)>
- // <table (itemElem)>
- // <tr>
- // <td><img (imgElem)/></td>
- // <td><span (contents)/></td>
- // </tr>
- // </table>
- // <div (childSpanElem)> children </div>
- // </div>
-
- Element tbody = DOM.createTBody(), tr = DOM.createTR();
- Element tdImg = DOM.createTD(), tdContent = DOM.createTD();
- DOM.appendChild(itemTable, tbody);
- DOM.appendChild(tbody, tr);
- DOM.appendChild(tr, tdImg);
- DOM.appendChild(tr, tdContent);
- DOM.setStyleAttribute(tdImg, "verticalAlign", "middle");
- DOM.setStyleAttribute(tdContent, "verticalAlign", "middle");
-
- DOM.appendChild(getElement(), itemTable);
- DOM.appendChild(getElement(), childSpanElem);
- DOM.appendChild(tdImg, statusImage.getElement());
- DOM.appendChild(tdContent, contentElem);
-
- DOM.setStyleAttribute(contentElem, "display", "inline");
- DOM.setStyleAttribute(getElement(), "whiteSpace", "nowrap");
- DOM.setStyleAttribute(childSpanElem, "whiteSpace", "nowrap");
- DOM.setStyleAttribute(childSpanElem, "padding", "0px");
- setStyleName(contentElem, "gwt-TreeItem", true);
-
- Accessibility.setRole(contentElem, Accessibility.ROLE_TREEITEM);
+ Element elem = DOM.clone(BASE_BARE_ELEM, true);
+ setElement(elem);
+ contentElem = DOM.getFirstChild(elem);
DOM.setElementAttribute(contentElem, "id", DOM.createUniqueId());
}
@@ -218,7 +234,7 @@
/**
* Adds another item as a child to this one.
- *
+ *
* @param item the item to be added
*/
public void addItem(TreeItem item) {
@@ -227,17 +243,21 @@
item.remove();
}
+ if (children == null) {
+ initChildren();
+ }
+
// Logical attach.
item.setParentItem(this);
children.add(item);
// Physical attach.
if (LocaleInfo.getCurrentLocale().isRTL()) {
- DOM.setStyleAttribute(item.getElement(), "marginRight", "16px");
+ DOM.setStyleAttribute(item.getElement(), "marginRight", "16px");
} else {
- DOM.setStyleAttribute(item.getElement(), "marginLeft", "16px");
+ DOM.setStyleAttribute(item.getElement(), "marginLeft", "16px");
}
-
+
DOM.appendChild(childSpanElem, item.getElement());
// Adopt.
@@ -268,7 +288,7 @@
*/
public TreeItem getChild(int index) {
- if ((index < 0) || (index >= children.size())) {
+ if ((index < 0) || (index >= getChildCount())) {
return null;
}
@@ -282,6 +302,9 @@
*/
public int getChildCount() {
+ if (children == null) {
+ return 0;
+ }
return children.size();
}
@@ -293,6 +316,9 @@
*/
public int getChildIndex(TreeItem child) {
+ if (children == null) {
+ return -1;
+ }
return children.indexOf(child);
}
@@ -380,7 +406,7 @@
public void removeItem(TreeItem item) {
// Validate.
- if (!children.contains(item)) {
+ if (children == null || !children.contains(item)) {
return;
}
@@ -424,7 +450,7 @@
return;
}
this.selected = selected;
- setStyleName(contentElem, "gwt-TreeItem-selected", selected);
+ setStyleName(getContentElem(), "gwt-TreeItem-selected", selected);
}
/**
@@ -444,7 +470,7 @@
* fired
*/
public void setState(boolean open, boolean fireEvents) {
- if (open && children.size() == 0) {
+ if (open && getChildCount() == 0) {
return;
}
@@ -532,7 +558,6 @@
/**
* <b>Affected Elements:</b>
* <ul>
- * <li>-image = The status image.</li>
* <li>-content = The text or {@link Widget} next to the image.</li>
* <li>-child# = The child at the specified index.</li>
* </ul>
@@ -542,18 +567,24 @@
@Override
protected void onEnsureDebugId(String baseID) {
super.onEnsureDebugId(baseID);
- statusImage.ensureDebugId(baseID + "-image");
ensureDebugId(contentElem, baseID, "content");
+ if (imageHolder != null) {
+ // The image itself may or may not exist.
+ ensureDebugId(imageHolder, baseID, "image");
+ }
- int childCount = 0;
- for (TreeItem child : children) {
- child.ensureDebugId(baseID + "-child" + childCount);
- childCount++;
+ if (children != null) {
+ int childCount = 0;
+ for (TreeItem child : children) {
+ child.ensureDebugId(baseID + "-child" + childCount);
+ childCount++;
+ }
}
}
void addTreeItems(List<TreeItem> accum) {
- for (int i = 0; i < children.size(); i++) {
+ int size = getChildCount();
+ for (int i = 0; i < size; i++) {
TreeItem item = children.get(i);
accum.add(item);
item.addTreeItems(accum);
@@ -568,12 +599,24 @@
return contentElem;
}
- int getContentHeight() {
- return DOM.getElementPropertyInt(itemTable, "offsetHeight");
+ Element getImageElement() {
+ return DOM.getFirstChild(getImageHolderElement());
}
- Element getImageElement() {
- return statusImage.getElement();
+ Element getImageHolderElement() {
+ if (imageHolder == null) {
+ convertToFullNode();
+ }
+ return imageHolder;
+ }
+
+ void initChildren() {
+ convertToFullNode();
+ childSpanElem = DOM.createDiv();
+ DOM.appendChild(getElement(), childSpanElem);
+ DOM.setStyleAttribute(childSpanElem, "whiteSpace", "nowrap");
+ DOM.setStyleAttribute(childSpanElem, "overflow", "hidden");
+ children = new ArrayList<TreeItem>();
}
void setParentItem(TreeItem parent) {
@@ -598,7 +641,7 @@
}
tree = newTree;
- for (int i = 0, n = children.size(); i < n; ++i) {
+ for (int i = 0, n = getChildCount(); i < n; ++i) {
children.get(i).setTree(newTree);
}
updateState(false, true);
@@ -613,23 +656,21 @@
void updateState(boolean animate, boolean updateTreeSelection) {
// If the tree hasn't been set, there is no visual state to update.
- if (tree == null) {
+ // If the tree is not attached, then update will be called on attach.
+ if (tree == null || tree.isAttached() == false) {
return;
}
- TreeImages images = tree.getImages();
-
- if (children.size() == 0) {
- UIObject.setVisible(childSpanElem, false);
- images.treeLeaf().applyTo(statusImage);
+ if (getChildCount() == 0) {
+ if (childSpanElem != null) {
+ UIObject.setVisible(childSpanElem, false);
+ }
+ tree.showLeafImage(this);
return;
}
// We must use 'display' rather than 'visibility' here,
// or the children will always take up space.
- if (itemAnimation == null) {
- itemAnimation = new TreeItemAnimation();
- }
if (animate && (tree != null) && (tree.isAttached())) {
itemAnimation.setItemState(this, tree.isAnimationEnabled());
} else {
@@ -638,14 +679,15 @@
// Change the status image
if (open) {
- images.treeOpen().applyTo(statusImage);
+ tree.showOpenImage(this);
} else {
- images.treeClosed().applyTo(statusImage);
+ tree.showClosedImage(this);
}
// We may need to update the tree's selection in response to a tree state change. For
// example, if the tree's currently selected item is a descendant of an item whose
// branch was just collapsed, then the item itself should become the newly-selected item.
+ // itself should become the newly-selected item.
if (updateTreeSelection) {
tree.maybeUpdateSelection(this, this.open);
}
@@ -656,9 +698,26 @@
tree.maybeUpdateSelection(this, this.open);
}
+ private void convertToFullNode() {
+ if (imageHolder == null) {
+ // Extract the Elements from the object
+ Element itemTable = DOM.clone(BASE_INTERNAL_ELEM, true);
+ DOM.appendChild(getElement(), itemTable);
+ Element tr = DOM.getFirstChild(DOM.getFirstChild(itemTable));
+ Element tdImg = DOM.getFirstChild(tr);
+ Element tdContent = DOM.getNextSibling(tdImg);
+
+ // Undoes padding from table element.
+ DOM.setStyleAttribute(getElement(), "padding", "0px");
+ DOM.setStyleAttribute(getElement(), "paddingLeft", "0px");
+ DOM.appendChild(tdContent, contentElem);
+ imageHolder = tdImg;
+ }
+ }
+
private void updateStateRecursiveHelper() {
updateState(false, false);
- for (int i = 0, n = children.size(); i < n; ++i) {
+ for (int i = 0, n = getChildCount(); i < n; ++i) {
children.get(i).updateStateRecursiveHelper();
}
}
diff --git a/user/test/com/google/gwt/user/client/ui/TreeTest.java b/user/test/com/google/gwt/user/client/ui/TreeTest.java
index 6f08a37..d263d9f 100644
--- a/user/test/com/google/gwt/user/client/ui/TreeTest.java
+++ b/user/test/com/google/gwt/user/client/ui/TreeTest.java
@@ -88,10 +88,13 @@
bottom1.getElement());
UIObjectTest.assertDebugId("myTree-root-child3-child2",
bottom2.getElement());
-
+
// Check tree item sub elements
- UIObjectTest.assertDebugId("myTree-root-child0-content", top0.getContentElem());
- UIObjectTest.assertDebugId("myTree-root-child0-image", top0.getImageElement());
+ UIObjectTest.assertDebugId("myTree-root-child0-content",
+ top0.getContentElem());
+
+ UIObjectTest.assertDebugId("myTree-root-child3-image",
+ top3.getImageHolderElement());
}
public void testInsertSameItemRepeatedly() {