Revision: 8917
Author: [email protected]
Date: Fri Oct 1 09:41:26 2010
Log: Fixes some bugs in CellBrowser. CellBrowser#setChildState() was
exited early too aggressively, which could put CellBrowser in an invalid
state if you mix leaf and non-leaf nodes. CellBrowser was overriding
onFocus() to open children, but it isn't focusable if keyboard selection is
disabled. We now override a package protected method that is triggered on
focus or mousedown. Also, we would apply the keyboard selected style to the
0th row if keyboard selection is disabled. This bug has been fixed. I
wrote tests for the mixed leaf/non leaf node cases, and I manually verified
that the CellBrowser behaves correctly whether or not keyboard selection is
enabled.
Review at http://gwt-code-reviews.appspot.com/942801
Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=8917
Modified:
/trunk/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
/trunk/user/src/com/google/gwt/user/cellview/client/CellList.java
/trunk/user/test/com/google/gwt/user/cellview/client/CellBrowserTest.java
=======================================
--- /trunk/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
Thu Sep 23 15:11:20 2010
+++ /trunk/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
Fri Oct 1 09:41:26 2010
@@ -1,12 +1,12 @@
/*
* Copyright 2010 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may
not
* use this file except in compliance with the License. You may obtain a
copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -63,7 +63,7 @@
/**
* A "browsable" view of a tree in which only a single node per level may
be
* open at one time.
- *
+ *
* <p>
* This widget will <em>only</em> work in standards mode, which requires
that
* the HTML page in which it is run have an explicit <!DOCTYPE>
@@ -180,11 +180,11 @@
}
/**
- * A custom version of cell list used by the browser.
- *
+ * A custom version of cell list used by the browser. Visible for
testing.
+ *
* @param <T> the data type of list items
*/
- private class BrowserCellList<T> extends CellList<T> {
+ class BrowserCellList<T> extends CellList<T> {
/**
* The level of this list view.
@@ -192,14 +192,19 @@
private final int level;
/**
- * The key of the currently open item.
+ * The key of the currently focused item.
*/
- private Object openKey;
+ private Object focusedKey;
/**
- * The value of the currently open item.
+ * The value of the currently focused item.
*/
- private T openValue;
+ private T focusedValue;
+
+ /**
+ * Indicates whether or not the focused value is open.
+ */
+ private boolean isFocusedOpen;
public BrowserCellList(final Cell<T> cell, int level,
ProvidesKey<T> keyProvider) {
@@ -238,18 +243,6 @@
}
}
}
-
- @Override
- protected void onFocus() {
- super.onFocus();
-
- // Open the selected row.
- int selectedRow = getKeyboardSelectedRow();
- if (isRowWithinBounds(selectedRow)) {
- T value = getDisplayedItem(selectedRow);
- setChildState(this, value, true, true, true);
- }
- }
@Override
protected void renderRowValues(SafeHtmlBuilder sb, List<T> values,
@@ -261,8 +254,7 @@
String openItem = " " + style.cellBrowserOpenItem();
String evenItem = style.cellBrowserEvenItem();
String oddItem = style.cellBrowserOddItem();
- int keyboardSelectedRow = Math.max(0, getKeyboardSelectedRow()
- + getPageStart());
+ int keyboardSelectedRow = getKeyboardSelectedRow() + getPageStart();
int length = values.size();
int end = start + length;
for (int i = start; i < end; i++) {
@@ -270,7 +262,8 @@
Object key = getValueKey(value);
boolean isSelected = selectionModel == null ? false
: selectionModel.isSelected(value);
- boolean isOpen = (openKey == null) ? false : openKey.equals(key);
+ boolean isOpen = (focusedKey == null || !isFocusedOpen) ? false
+ : focusedKey.equals(key);
StringBuilder classesBuilder = new StringBuilder();
classesBuilder.append(i % 2 == 0 ? evenItem : oddItem);
if (isOpen) {
@@ -313,6 +306,15 @@
}
}
}
+
+ @Override
+ void doKeyboardSelection(Event event, T value, int indexOnPage) {
+ super.doKeyboardSelection(event, value, indexOnPage);
+
+ // Open the selected row. If keyboard selection updates the selection
+ // model, this is a no-op.
+ setChildState(this, value, true, true, true);
+ }
/**
* Navigate to a deeper node.
@@ -351,126 +353,13 @@
}
}
}
-
- /**
- * An implementation of {...@link CellList.Resources} that delegates to
- * {...@link CellBrowser.Resources}.
- */
- private static class CellListResourcesImpl implements CellList.Resources
{
-
- private final CellBrowser.Resources delegate;
- private final CellListStyleImpl style;
-
- public CellListResourcesImpl(CellBrowser.Resources delegate) {
- this.delegate = delegate;
- this.style = new CellListStyleImpl(delegate.cellBrowserStyle());
- }
-
- public ImageResource cellListSelectedBackground() {
- return delegate.cellBrowserSelectedBackground();
- }
-
- public CellList.Style cellListStyle() {
- return style;
- }
- }
-
- /**
- * An implementation of {...@link CellList.Style} that delegates to
- * {...@link CellBrowser.Style}.
- */
- private static class CellListStyleImpl implements CellList.Style {
-
- private final CellBrowser.Style delegate;
-
- public CellListStyleImpl(CellBrowser.Style delegate) {
- this.delegate = delegate;
- }
-
- public String cellListEvenItem() {
- return delegate.cellBrowserEvenItem();
- }
-
- public String cellListKeyboardSelectedItem() {
- return delegate.cellBrowserKeyboardSelectedItem();
- }
-
- public String cellListOddItem() {
- return delegate.cellBrowserOddItem();
- }
-
- public String cellListSelectedItem() {
- return delegate.cellBrowserSelectedItem();
- }
-
- public String cellListWidget() {
- // Do not apply any style to the list itself.
- return null;
- }
-
- public boolean ensureInjected() {
- return delegate.ensureInjected();
- }
-
- public String getName() {
- return delegate.getName();
- }
-
- public String getText() {
- return delegate.getText();
- }
- }
-
- /**
- * The animation used to scroll to the newly added list view.
- */
- private class ScrollAnimation extends Animation {
-
- /**
- * The starting scroll position.
- */
- private int startScrollLeft;
-
- /**
- * The ending scroll position.
- */
- private int targetScrollLeft;
-
- @Override
- protected void onComplete() {
- getElement().setScrollLeft(targetScrollLeft);
- }
-
- @Override
- protected void onUpdate(double progress) {
- int diff = targetScrollLeft - startScrollLeft;
- getElement().setScrollLeft(startScrollLeft + (int) (diff *
progress));
- }
-
- void scrollToEnd() {
- Element elem = getElement();
- targetScrollLeft = elem.getScrollWidth() - elem.getClientWidth();
- if (LocaleInfo.getCurrentLocale().isRTL()) {
- targetScrollLeft *= -1;
- }
-
- if (isAnimationEnabled()) {
- // Animate the scrolling.
- startScrollLeft = elem.getScrollLeft();
- run(250);
- } else {
- // Scroll instantly.
- onComplete();
- }
- }
- }
/**
* A node in the tree.
- *
+ *
* @param <C> the data type of the children of the node
*/
- private class TreeNodeImpl<C> implements TreeNode {
+ class TreeNodeImpl<C> implements TreeNode {
private final BrowserCellList<C> display;
private NodeInfo<C> nodeInfo;
private final Object value;
@@ -479,11 +368,10 @@
/**
* Construct a new {...@link TreeNodeImpl}.
- *
+ *
* @param nodeInfo the nodeInfo for the children nodes
* @param value the value of the node
* @param display the display associated with the node
- * @param cell the {...@link Cell} used to render the data
* @param widget the widget that wraps the display
*/
public TreeNodeImpl(final NodeInfo<C> nodeInfo, Object value,
@@ -496,12 +384,12 @@
// Trim to the current level if the open node disappears.
valueChangeHandler = display.addValueChangeHandler(new
ValueChangeHandler<List<C>>() {
public void onValueChange(ValueChangeEvent<List<C>> event) {
- Object openKey = display.openKey;
- if (openKey != null) {
+ Object focusedKey = display.focusedKey;
+ if (focusedKey != null) {
boolean stillExists = false;
List<C> displayValues = event.getValue();
for (C displayValue : displayValues) {
- if (openKey.equals(display.getValueKey(displayValue))) {
+ if (focusedKey.equals(display.getValueKey(displayValue))) {
stillExists = true;
break;
}
@@ -549,8 +437,9 @@
public boolean isChildOpen(int index) {
assertNotDestroyed();
checkChildBounds(index);
- return (display.openKey == null) ? false
- :
display.openKey.equals(display.getValueKey(getChildValue(index)));
+ return (display.focusedKey == null || !display.isFocusedOpen)
+ ? false
+ :
display.focusedKey.equals(display.getValueKey(getChildValue(index)));
}
public boolean isDestroyed() {
@@ -567,6 +456,20 @@
return setChildState(display, getChildValue(index), open, fireEvents,
true);
}
+
+ /**
+ * @return the key of the value that is focused in this node's display.
+ */
+ Object getFocusedKey() {
+ return display.focusedKey;
+ }
+
+ /**
+ * @return true if the focused value is open, false if not
+ */
+ boolean isFocusedOpen() {
+ return display.isFocusedOpen;
+ }
/**
* Assert that the node has not been destroyed.
@@ -579,7 +482,7 @@
/**
* Check the child bounds.
- *
+ *
* @param index the index of the child
* @throws IndexOutOfBoundsException if the child is not in range
*/
@@ -602,13 +505,127 @@
/**
* Get the index of the open item.
- *
+ *
* @return the index of the open item, or -1 if not found
*/
private int getOpenIndex() {
- return display.indexOf(display.openValue);
+ return display.isFocusedOpen ? display.indexOf(display.focusedValue)
+ : null;
}
}
+
+ /**
+ * An implementation of {...@link CellList.Resources} that delegates to
+ * {...@link CellBrowser.Resources}.
+ */
+ private static class CellListResourcesImpl implements CellList.Resources
{
+
+ private final CellBrowser.Resources delegate;
+ private final CellListStyleImpl style;
+
+ public CellListResourcesImpl(CellBrowser.Resources delegate) {
+ this.delegate = delegate;
+ this.style = new CellListStyleImpl(delegate.cellBrowserStyle());
+ }
+
+ public ImageResource cellListSelectedBackground() {
+ return delegate.cellBrowserSelectedBackground();
+ }
+
+ public CellList.Style cellListStyle() {
+ return style;
+ }
+ }
+
+ /**
+ * An implementation of {...@link CellList.Style} that delegates to
+ * {...@link CellBrowser.Style}.
+ */
+ private static class CellListStyleImpl implements CellList.Style {
+
+ private final CellBrowser.Style delegate;
+
+ public CellListStyleImpl(CellBrowser.Style delegate) {
+ this.delegate = delegate;
+ }
+
+ public String cellListEvenItem() {
+ return delegate.cellBrowserEvenItem();
+ }
+
+ public String cellListKeyboardSelectedItem() {
+ return delegate.cellBrowserKeyboardSelectedItem();
+ }
+
+ public String cellListOddItem() {
+ return delegate.cellBrowserOddItem();
+ }
+
+ public String cellListSelectedItem() {
+ return delegate.cellBrowserSelectedItem();
+ }
+
+ public String cellListWidget() {
+ // Do not apply any style to the list itself.
+ return null;
+ }
+
+ public boolean ensureInjected() {
+ return delegate.ensureInjected();
+ }
+
+ public String getName() {
+ return delegate.getName();
+ }
+
+ public String getText() {
+ return delegate.getText();
+ }
+ }
+
+ /**
+ * The animation used to scroll to the newly added list view.
+ */
+ private class ScrollAnimation extends Animation {
+
+ /**
+ * The starting scroll position.
+ */
+ private int startScrollLeft;
+
+ /**
+ * The ending scroll position.
+ */
+ private int targetScrollLeft;
+
+ @Override
+ protected void onComplete() {
+ getElement().setScrollLeft(targetScrollLeft);
+ }
+
+ @Override
+ protected void onUpdate(double progress) {
+ int diff = targetScrollLeft - startScrollLeft;
+ getElement().setScrollLeft(startScrollLeft + (int) (diff *
progress));
+ }
+
+ void scrollToEnd() {
+ Element elem = getElement();
+ targetScrollLeft = elem.getScrollWidth() - elem.getClientWidth();
+ if (LocaleInfo.getCurrentLocale().isRTL()) {
+ targetScrollLeft *= -1;
+ }
+
+ if (isAnimationEnabled()) {
+ // Animate the scrolling.
+ startScrollLeft = elem.getScrollLeft();
+ run(250);
+ } else {
+ // Scroll instantly.
+ onComplete();
+ }
+ }
+ }
private static Resources DEFAULT_RESOURCES;
@@ -625,6 +642,11 @@
}
return DEFAULT_RESOURCES;
}
+
+ /**
+ * The visible {...@link TreeNodeImpl}s. Visible for testing.
+ */
+ final List<TreeNodeImpl<?>> treeNodes = new ArrayList<TreeNodeImpl<?>>();
/**
* The animation used for scrolling.
@@ -676,14 +698,9 @@
*/
private final Style style;
- /**
- * The visible {...@link TreeNodeImpl}s.
- */
- private final List<TreeNodeImpl<?>> treeNodes = new
ArrayList<TreeNodeImpl<?>>();
-
/**
* Construct a new {...@link CellBrowser}.
- *
+ *
* @param <T> the type of data in the root node
* @param viewModel the {...@link TreeViewModel} that backs the tree
* @param rootValue the hidden root value of the tree
@@ -694,7 +711,7 @@
/**
* Construct a new {...@link CellBrowser} with the specified {...@link
Resources}.
- *
+ *
* @param <T> the type of data in the root node
* @param viewModel the {...@link TreeViewModel} that backs the tree
* @param rootValue the hidden root value of the tree
@@ -745,7 +762,7 @@
/**
* Get the default width of new columns.
- *
+ *
* @return the default width in pixels
*/
public int getDefaultColumnWidth() {
@@ -754,7 +771,7 @@
/**
* Get the minimum width of columns.
- *
+ *
* @return the minimum width in pixels
*/
public int getMinimumColumnWidth() {
@@ -791,7 +808,7 @@
/**
* Set the default width of new columns.
- *
+ *
* @param width the default width in pixels
*/
public void setDefaultColumnWidth(int width) {
@@ -808,7 +825,7 @@
/**
* Set the minimum width of columns.
- *
+ *
* @param minWidth the minimum width in pixels
*/
public void setMinimumColumnWidth(int minWidth) {
@@ -816,12 +833,8 @@
}
/**
- *
- *
- *
- *
* Create a pager to control the list view.
- *
+ *
* @param <C> the item type in the list view
* @param display the list view to add paging too
* @return the pager
@@ -850,7 +863,7 @@
/**
* Create a new {...@link TreeNodeImpl} and append it to the end of the
* LayoutPanel.
- *
+ *
* @param <C> the data type of the children
* @param nodeInfo the info about the node
* @param value the value of the open node
@@ -901,7 +914,7 @@
/**
* Create a {...@link HasData} that will display items. The {...@link HasData}
must
* extend {...@link Widget}.
- *
+ *
* @param <C> the item type in the list view
* @param nodeInfo the node info with child data
* @param level the level of the list
@@ -917,7 +930,7 @@
/**
* Get the HTML representation of an image.
- *
+ *
* @param res the {...@link ImageResource} to render as HTML
* @return the rendered HTML
*/
@@ -931,7 +944,7 @@
/**
* Get the {...@link SplitLayoutPanel} used to lay out the views.
- *
+ *
* @return the {...@link SplitLayoutPanel}
*/
private SplitLayoutPanel getSplitLayoutPanel() {
@@ -940,8 +953,8 @@
/**
* Set the open state of a tree node.
- *
- * @param cell the Cell that changed state.
+ *
+ * @param cellList the CellList that changed state.
* @param value the value to open
* @param open true to open, false to close
* @param fireEvents true to fireEvents
@@ -949,11 +962,6 @@
*/
private <C> TreeNode setChildState(BrowserCellList<C> cellList, C value,
boolean open, boolean fireEvents, boolean redraw) {
-
- // Early exit if the node is a leaf.
- if (isLeaf(value)) {
- return null;
- }
// Get the key of the value to open.
Object newKey = cellList.getValueKey(value);
@@ -962,56 +970,63 @@
if (newKey == null) {
// Early exit if opening but the specified node has no key.
return null;
- } else if (newKey.equals(cellList.openKey)) {
+ } else if (newKey.equals(cellList.focusedKey)) {
// Early exit if opening but the specified node is already open.
- return treeNodes.get(cellList.level + 1);
+ return cellList.isFocusedOpen ? treeNodes.get(cellList.level + 1)
+ : null;
}
// Close the currently open node.
- if (cellList.openKey != null) {
- setChildState(cellList, cellList.openValue, false, fireEvents,
false);
- }
-
- // Get the child node info.
- NodeInfo<?> childNodeInfo = getNodeInfo(value);
- if (childNodeInfo == null) {
- return null;
+ if (cellList.focusedKey != null) {
+ setChildState(cellList, cellList.focusedValue, false, fireEvents,
false);
}
// Update the cell so it renders the styles correctly.
- cellList.openValue = value;
- cellList.openKey = cellList.getValueKey(value);
+ cellList.focusedValue = value;
+ cellList.focusedKey = cellList.getValueKey(value);
// Add the child node.
- appendTreeNode(childNodeInfo, value);
+ NodeInfo<?> childNodeInfo = isLeaf(value) ? null :
getNodeInfo(value);
+ if (childNodeInfo != null) {
+ cellList.isFocusedOpen = true;
+ appendTreeNode(childNodeInfo, value);
+ } else {
+ cellList.isFocusedOpen = false;
+ }
// Refresh the display to update the styles for this node.
if (redraw) {
treeNodes.get(cellList.level).display.redraw();
}
- if (fireEvents) {
- OpenEvent.fire(this, treeNodes.get(cellList.level + 1));
- }
- return treeNodes.get(cellList.level + 1);
+ if (cellList.isFocusedOpen) {
+ TreeNodeImpl<?> node = treeNodes.get(cellList.level + 1);
+ if (fireEvents) {
+ OpenEvent.fire(this, node);
+ }
+ return node.isDestroyed() ? null : node;
+ }
+ return null;
} else {
// Early exit if closing and the specified node or all nodes are
closed.
- if (cellList.openKey == null || !cellList.openKey.equals(newKey)) {
+ if (cellList.focusedKey == null |
| !cellList.focusedKey.equals(newKey)) {
return null;
}
// Close the node.
- TreeNode closedNode = treeNodes.get(cellList.level + 1);
+ TreeNode closedNode = cellList.isFocusedOpen
+ ? treeNodes.get(cellList.level + 1) : null;
trimToLevel(cellList.level);
- cellList.openKey = null;
- cellList.openValue = null;
+ cellList.focusedKey = null;
+ cellList.focusedValue = null;
+ cellList.isFocusedOpen = false;
// Refresh the display to update the styles for this node.
if (redraw) {
treeNodes.get(cellList.level).display.redraw();
}
- if (fireEvents) {
+ if (fireEvents && closedNode != null) {
CloseEvent.fire(this, closedNode);
}
}
@@ -1021,7 +1036,7 @@
/**
* Reduce the number of {...@link HasData}s down to the specified level.
- *
+ *
* @param level the level to trim to
*/
private void trimToLevel(int level) {
=======================================
--- /trunk/user/src/com/google/gwt/user/cellview/client/CellList.java Wed
Sep 29 08:06:29 2010
+++ /trunk/user/src/com/google/gwt/user/cellview/client/CellList.java Fri
Oct 1 09:41:26 2010
@@ -257,7 +257,15 @@
return cell.dependsOnSelection();
}
+ /**
+ * Called when a user action triggers selection.
+ *
+ * @param event the event that triggered selection
+ * @param value the value that was selected
+ * @param indexOnPage the index of the value on the page
+ */
protected void doSelection(Event event, T value, int indexOnPage) {
+ // TODO(jlabanca): Defer to a user provided SelectionManager.
SelectionModel<? super T> selectionModel = getSelectionModel();
if (selectionModel != null) {
selectionModel.setSelected(value, true);
@@ -363,9 +371,7 @@
// Focus on the cell.
if ("focus".equals(eventType) || isMouseDown) {
isFocused = true;
- if (getPresenter().getKeyboardSelectedRow() != indexOnPage) {
- getPresenter().setKeyboardSelectedRow(indexOnPage, false);
- }
+ doKeyboardSelection(event, value, indexOnPage);
}
// Fire the event to the cell if the list has not been refreshed.
@@ -461,6 +467,19 @@
protected void setSelected(Element elem, boolean selected) {
setStyleName(elem, style.cellListSelectedItem(), selected);
}
+
+ /**
+ * Called when the user selects a cell with the mouse or tab key.
+ *
+ * @param event the event
+ * @param value the value that is selected
+ * @param indexOnPage the index on the page
+ */
+ void doKeyboardSelection(Event event, T value, int indexOnPage) {
+ if (getPresenter().getKeyboardSelectedRow() != indexOnPage) {
+ getPresenter().setKeyboardSelectedRow(indexOnPage, false);
+ }
+ }
@Override
void setLoadingState(LoadingState state) {
=======================================
---
/trunk/user/test/com/google/gwt/user/cellview/client/CellBrowserTest.java
Tue Aug 24 17:28:21 2010
+++
/trunk/user/test/com/google/gwt/user/cellview/client/CellBrowserTest.java
Fri Oct 1 09:41:26 2010
@@ -1,12 +1,12 @@
/*
* Copyright 2010 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may
not
* use this file except in compliance with the License. You may obtain a
copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,20 +15,111 @@
*/
package com.google.gwt.user.cellview.client;
+import com.google.gwt.cell.client.NumberCell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.TreeViewModel;
/**
* Tests for {...@link CellBrowser}.
*/
public class CellBrowserTest extends AbstractCellTreeTestBase {
+
+ /**
+ * A {...@link TreeViewModel} used for testing. Every other top level node
is a
+ * leaf node. The 0th top level node has children.
+ */
+ protected class MixedTreeViewModel implements TreeViewModel {
+
+ public <T> NodeInfo<?> getNodeInfo(T value) {
+ if (value == null) {
+ // Get the children of root, which are Integers.
+ ListDataProvider<Number> provider = new ListDataProvider<Number>();
+ for (int i = 0; i < 10; i++) {
+ provider.getList().add(new Integer(i));
+ }
+ return new DefaultNodeInfo<Number>(provider, new NumberCell());
+ } else if (value instanceof Integer && !isLeaf(value)) {
+ // Get the children of odd Integers, which are Strings.
+ ListDataProvider<String> provider = new ListDataProvider<String>();
+ return new DefaultNodeInfo<String>(provider, new TextCell());
+ }
+ throw new IllegalArgumentException("Unexpected value: " + value);
+ }
+
+ public boolean isLeaf(Object value) {
+ if (value == null) {
+ // Root value is null.
+ return false;
+ } else if (value instanceof Integer) {
+ // Odd integers are leaf nodes
+ return ((Integer) value % 2) != 0;
+ }
+ return false;
+ }
+ }
public CellBrowserTest() {
super(true);
}
+
+ /**
+ * Verify that closing a leaf node sets the focused key to null.
+ */
+ public void testCloseLeafNode() {
+ CellBrowser browser = new CellBrowser(new MixedTreeViewModel(), null);
+ TreeNode rootNode = browser.getRootTreeNode();
+ assertEquals(1, browser.treeNodes.size());
+
+ // Open a leaf node.
+ rootNode.setChildOpen(1, true);
+ assertEquals(1, browser.treeNodes.size());
+ assertEquals(1, browser.treeNodes.get(0).getFocusedKey());
+ assertFalse(browser.treeNodes.get(0).isFocusedOpen());
+
+ // Close the leaf node.
+ rootNode.setChildOpen(1, false);
+ assertEquals(1, browser.treeNodes.size());
+ assertNull(browser.treeNodes.get(0).getFocusedKey());
+ assertFalse(browser.treeNodes.get(0).isFocusedOpen());
+ }
+
+ /**
+ * Verify that opening a leaf node closes other open nodes.
+ */
+ public void testOpenLeafNode() {
+ CellBrowser browser = new CellBrowser(new MixedTreeViewModel(), null);
+ TreeNode rootNode = browser.getRootTreeNode();
+ assertEquals(1, browser.treeNodes.size());
+
+ // Child 0 has children.
+ TreeNode child0 = rootNode.setChildOpen(0, true);
+ assertNotNull(child0);
+ assertFalse(child0.isDestroyed());
+ assertEquals(2, browser.treeNodes.size());
+ assertEquals(0, browser.treeNodes.get(0).getFocusedKey());
+ assertTrue(browser.treeNodes.get(0).isFocusedOpen());
+
+ // Child 1 is a leaf.
+ TreeNode child1 = rootNode.setChildOpen(1, true);
+ assertNull(child1);
+ assertTrue(child0.isDestroyed());
+ assertEquals(1, browser.treeNodes.size());
+ assertEquals(1, browser.treeNodes.get(0).getFocusedKey());
+ assertFalse(browser.treeNodes.get(0).isFocusedOpen());
+
+ // Child 2 has children.
+ TreeNode child2 = rootNode.setChildOpen(2, true);
+ assertNotNull(child2);
+ assertFalse(child2.isDestroyed());
+ assertEquals(2, browser.treeNodes.size());
+ assertEquals(2, browser.treeNodes.get(0).getFocusedKey());
+ assertTrue(browser.treeNodes.get(0).isFocusedOpen());
+ }
@Override
- protected <T> CellBrowser createAbstractCellTree(
- TreeViewModel model, T rootValue) {
+ protected <T> CellBrowser createAbstractCellTree(TreeViewModel model,
+ T rootValue) {
CellBrowser browser = new CellBrowser(model, rootValue);
browser.setHeight("500px");
return browser;
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors