Initial implementation of TabLayoutPanel.
http://gwt-code-reviews.appspot.com/78820
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6397 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java
new file mode 100644
index 0000000..78d1c2e
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.examples;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.TabLayoutPanel;
+
+public class TabLayoutPanelExample implements EntryPoint {
+
+ public void onModuleLoad() {
+ // Create a three-item tab panel, with the tab area 1.5em tall.
+ TabLayoutPanel p = new TabLayoutPanel(1.5, Unit.EM);
+ p.add(new HTML("this"), "[this]");
+ p.add(new HTML("that"), "[that]");
+ p.add(new HTML("the other"), "[the other]");
+
+ // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
+ // resize events on the window to ensure that its children are informed of
+ // possible size changes.
+ RootLayoutPanel rp = RootLayoutPanel.get();
+ rp.add(p);
+
+ // The RootLayoutPanel requires that its layout() method be explicitly
+ // called for the initial layout to take effect.
+ rp.layout();
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
index 4adccbc..66044be 100644
--- a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
@@ -45,6 +45,8 @@
* <h3>Example</h3>
* {@example com.google.gwt.examples.LayoutPanelExample}
* </p>
+ *
+ * TODO: implements IndexedPanel (I think)
*/
public class LayoutPanel extends ComplexPanel implements RequiresLayout,
RequiresResize, ProvidesResize {
@@ -71,18 +73,7 @@
* @param widget the widget to be added
*/
public void add(Widget widget) {
- // Detach new child.
- widget.removeFromParent();
-
- // Logical attach.
- getChildren().add(widget);
-
- // Physical attach.
- Layer layer = layout.attachChild(widget.getElement(), widget);
- widget.setLayoutData(layer);
-
- // Adopt.
- adopt(widget);
+ insert(widget, getWidgetCount());
}
/**
@@ -103,6 +94,41 @@
return (Layout.Layer) child.getLayoutData();
}
+ /**
+ * Inserts a widget before the specified index.
+ *
+ * <p>
+ * By default, each child will fill the panel. To build more interesting
+ * layouts, use {@link #getLayer(Widget)} to get the {@link Layout.Layer}
+ * associated with each child, and set its layout constraints as desired.
+ * </p>
+ *
+ * <p>
+ * Inserting a widget in this way has no effect on the DOM structure, but can
+ * be useful for other panels that wrap LayoutPanel to maintain insertion
+ * order.
+ * </p>
+ *
+ * @param widget the widget to be inserted
+ * @param beforeIndex the index before which it will be inserted
+ * @throws IndexOutOfBoundsException if <code>beforeIndex</code> is out of
+ * range
+ */
+ public void insert(Widget widget, int beforeIndex) {
+ // Detach new child.
+ widget.removeFromParent();
+
+ // Logical attach.
+ getChildren().insert(widget, beforeIndex);
+
+ // Physical attach.
+ Layer layer = layout.attachChild(widget.getElement(), widget);
+ widget.setLayoutData(layer);
+
+ // Adopt.
+ adopt(widget);
+ }
+
public void layout() {
layout.layout();
}
diff --git a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
new file mode 100644
index 0000000..fc05226
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.Style.Visibility;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.BeforeSelectionEvent;
+import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
+import com.google.gwt.event.logical.shared.HasBeforeSelectionHandlers;
+import com.google.gwt.event.logical.shared.HasSelectionHandlers;
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.layout.client.Layout.Alignment;
+import com.google.gwt.layout.client.Layout.Layer;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * A panel that represents a tabbed set of pages, each of which contains another
+ * widget. Its child widgets are shown as the user selects the various tabs
+ * associated with them. The tabs can contain arbitrary text, HTML, or widgets.
+ *
+ * <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>
+ * declaration.
+ * </p>
+ *
+ * <p>
+ * NOTE: This class is still very new, and its interface may change without
+ * warning. Use at your own risk.
+ * </p>
+ *
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.TabLayoutPanelExample}
+ * </p>
+ *
+ * TODO:
+ * - Aria, RTL, DebugId
+ * - Update style mechanism (gwt-Tab, etc. not really sufficient).
+ */
+public class TabLayoutPanel extends LayoutComposite implements HasWidgets,
+ RequiresResize, ProvidesResize, IndexedPanel,
+ HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {
+
+ private static class Tab extends SimplePanel {
+ private Element anchor;
+
+ public Tab(Widget child) {
+ super(Document.get().createSpanElement());
+ getElement().appendChild(anchor = Document.get().createAnchorElement());
+
+ setWidget(child);
+ setStyleName("gwt-Tab");
+ anchor.setClassName("gwt-TabInner");
+
+ // TODO: float:left may not be enough. If there are tabs of differeing
+ // heights, the shorter ones will top-align, rather than bottom-align,
+ // which is what we would want. display:inline-block fixes this, but
+ // needs lots of cross-browser hacks to work properly.
+ getElement().getStyle().setProperty("float", "left");
+ }
+
+ public HandlerRegistration addClickHandler(ClickHandler handler) {
+ return addDomHandler(handler, ClickEvent.getType());
+ }
+
+ public Widget asWidget() {
+ return this;
+ }
+
+ public void setSelected(boolean selected) {
+ if (selected) {
+ addStyleDependentName("selected");
+ } else {
+ removeStyleDependentName("selected");
+ }
+ }
+
+ @Override
+ protected com.google.gwt.user.client.Element getContainerElement() {
+ return anchor.cast();
+ }
+ }
+
+ private WidgetCollection children = new WidgetCollection(this);
+ private FlowPanel tabBar = new FlowPanel();
+ private ArrayList<Tab> tabs = new ArrayList<Tab>();
+ private final double tabBarSize;
+ private final Unit tabBarUnit;
+ private LayoutPanel panel;
+ private int selectedIndex = -1;
+
+ /**
+ * Creates an empty tab panel.
+ *
+ * @param tabBarSize the size of the tab bar
+ * @param tabBarUnit the unit in which the tab bar size is specified
+ */
+ public TabLayoutPanel(double tabBarSize, Unit tabBarUnit) {
+ this.tabBarSize = tabBarSize;
+ this.tabBarUnit = tabBarUnit;
+
+ panel = new LayoutPanel();
+ initWidget(panel);
+
+ panel.add(tabBar);
+ Layer layer = panel.getLayer(tabBar);
+ layer.setLeftRight(0, Unit.PX, 0, Unit.PX);
+ layer.setTopHeight(0, Unit.PX, tabBarSize, tabBarUnit);
+ panel.layout();
+
+ panel.getLayer(tabBar).setChildVerticalPosition(Alignment.END);
+
+ tabBar.setStyleName("gwt-TabLayoutPanelTabs");
+ setStyleName("gwt-TabLayoutPanel");
+ }
+
+ public void add(Widget w) {
+ insert(w, getWidgetCount());
+ }
+
+ /**
+ * Adds a widget to the panel. If the Widget is already attached, it will be
+ * moved to the right-most index.
+ *
+ * @param child the widget to be added
+ * @param tabText the text to be shown on its tab
+ */
+ public void add(Widget child, String text) {
+ insert(child, text, getWidgetCount());
+ }
+
+ /**
+ * Adds a widget to the panel. If the Widget is already attached, it will be
+ * moved to the right-most index.
+ *
+ * @param child the widget to be added
+ * @param tabText the text to be shown on its tab
+ * @param asHtml <code>true</code> to treat the specified text as HTML
+ */
+ public void add(Widget w, String text, boolean asHtml) {
+ insert(w, text, asHtml, getWidgetCount());
+ }
+
+ /**
+ * Adds a widget to the panel. If the Widget is already attached, it will be
+ * moved to the right-most index.
+ *
+ * @param child the widget to be added
+ * @param tab the widget to be placed in the associated tab
+ */
+ public void add(Widget child, Widget tab) {
+ insert(child, tab, getWidgetCount());
+ }
+
+ public HandlerRegistration addBeforeSelectionHandler(
+ BeforeSelectionHandler<Integer> handler) {
+ return addHandler(handler, BeforeSelectionEvent.getType());
+ }
+
+ public HandlerRegistration addSelectionHandler(
+ SelectionHandler<Integer> handler) {
+ return addHandler(handler, SelectionEvent.getType());
+ }
+
+ public void clear() {
+ Iterator<Widget> it = iterator();
+ while (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ }
+
+ /**
+ * Gets the index of the currently-selected tab.
+ *
+ * @return the selected index, or <code>-1</code> if none is selected.
+ */
+ public int getSelectedIndex() {
+ return selectedIndex;
+ }
+
+ /**
+ * Gets the widget in the tab at the given index.
+ *
+ * @param index the index of the tab to be retrieved
+ * @return the tab's widget
+ */
+ public Widget getTabWidget(int index) {
+ checkIndex(index);
+ return tabs.get(index).getWidget();
+ }
+
+ /**
+ * Gets the widget in the tab associated with the given child widget.
+ *
+ * @param child the child whose tab is to be retrieved
+ * @return the tab's widget
+ */
+ public Widget getTabWidget(Widget child) {
+ checkChild(child);
+ return getTabWidget(getWidgetIndex(child));
+ }
+
+ public Widget getWidget(int index) {
+ checkIndex(index);
+ return children.get(index);
+ }
+
+ public int getWidgetCount() {
+ return children.size();
+ }
+
+ public int getWidgetIndex(Widget child) {
+ return children.indexOf(child);
+ }
+
+ /**
+ * Inserts a widget into the panel. If the Widget is already attached, it will
+ * be moved to the requested index.
+ *
+ * @param child the widget to be added
+ * @param tab the widget to be placed in the associated tab
+ * @param beforeIndex the index before which it will be inserted
+ */
+ public void insert(Widget w, int beforeIndex) {
+ insert(w, "", beforeIndex);
+ }
+
+ /**
+ * Inserts a widget into the panel. If the Widget is already attached, it will be
+ * moved to the requested index.
+ *
+ * @param child the widget to be added
+ * @param tabText the text to be shown on its tab
+ * @param asHtml <code>true</code> to treat the specified text as HTML
+ * @param beforeIndex the index before which it will be inserted
+ */
+ public void insert(Widget w, String text, boolean asHtml, int beforeIndex) {
+ Widget contents;
+ if (asHtml) {
+ contents = new HTML(text);
+ } else {
+ contents = new Label(text);
+ }
+ insert(w, contents, beforeIndex);
+ }
+
+ /**
+ * Inserts a widget into the panel. If the Widget is already attached, it will be
+ * moved to the requested index.
+ *
+ * @param child the widget to be added
+ * @param tabText the text to be shown on its tab
+ * @param beforeIndex the index before which it will be inserted
+ */
+ public void insert(Widget child, String text, int beforeIndex) {
+ insert(child, text, false, beforeIndex);
+ }
+
+ /**
+ * Inserts a widget into the panel. If the Widget is already attached, it will be
+ * moved to the requested index.
+ *
+ * @param child the widget to be added
+ * @param tab the widget to be placed in the associated tab
+ * @param beforeIndex the index before which it will be inserted
+ */
+ public void insert(Widget child, Widget tab, int beforeIndex) {
+ insert(child, new Tab(tab), beforeIndex);
+ }
+
+ public Iterator<Widget> iterator() {
+ return children.iterator();
+ }
+
+ public boolean remove(int index) {
+ if ((index < 0) || (index >= getWidgetCount())) {
+ return false;
+ }
+
+ tabBar.remove(index);
+ panel.remove(children.get(index));
+
+ children.remove(index);
+ tabs.remove(index);
+
+ if (index == selectedIndex) {
+ // If the selected tab is being removed, select the first tab (if there
+ // is one).
+ selectedIndex = -1;
+ if (getWidgetCount() > 0) {
+ selectTab(0);
+ }
+ } else if (index < selectedIndex) {
+ // If the selectedIndex is greater than the one being removed, it needs
+ // to be adjusted.
+ --selectedIndex;
+ }
+ return true;
+ }
+
+ public boolean remove(Widget w) {
+ int index = children.indexOf(w);
+ if (index == -1) {
+ return false;
+ }
+
+ return remove(index);
+ }
+
+ /**
+ * Programmatically selects the specified tab.
+ *
+ * @param index the index of the tab to be selected
+ */
+ public void selectTab(int index) {
+ checkIndex(index);
+ if (index == selectedIndex) {
+ return;
+ }
+
+ // Fire the before selection event, giving the recipients a chance to
+ // cancel the selection.
+ BeforeSelectionEvent<Integer> event = BeforeSelectionEvent
+ .fire(this, index);
+ if ((event != null) && event.isCanceled()) {
+ return;
+ }
+
+ // Update the tabs being selected and unselected.
+ if (selectedIndex != -1) {
+ Layer layer = panel.getLayer(children.get(selectedIndex));
+ layer.getContainerElement().getStyle().setVisibility(Visibility.HIDDEN);
+ tabs.get(selectedIndex).setSelected(false);
+ }
+
+ Layer layer = panel.getLayer(children.get(index));
+ layer.getContainerElement().getStyle().setVisibility(Visibility.VISIBLE);
+ tabs.get(index).setSelected(true);
+ selectedIndex = index;
+
+ // Fire the selection event.
+ SelectionEvent.fire(this, index);
+ }
+
+ /**
+ * Programmatically selects the specified tab.
+ *
+ * @param child the child whose tab is to be selected
+ */
+ public void selectTab(Widget child) {
+ selectTab(getWidgetIndex(child));
+ }
+
+ /**
+ * Sets a tab's HTML contents.
+ *
+ * Use care when setting an object's HTML; it is an easy way to expose
+ * script-based security problems. Consider using
+ * {@link #setTabText(int, String)} whenever possible.
+ *
+ * @param index the index of the tab whose HTML is to be set
+ * @param html the tab's new HTML contents
+ */
+ public void setTabHTML(int index, String text) {
+ checkIndex(index);
+ tabs.get(index).setWidget(new HTML(text));
+ }
+
+ /**
+ * Sets a tab's text contents.
+ *
+ * @param index the index of the tab whose text is to be set
+ * @param text the object's new text
+ */
+ public void setTabText(int index, String text) {
+ checkIndex(index);
+ tabs.get(index).setWidget(new Label(text));
+ }
+
+ private void checkChild(Widget child) {
+ assert children.contains(child);
+ }
+
+ private void checkIndex(int index) {
+ assert (index >= 0) && (index < children.size()) : "Index out of bounds";
+ }
+
+ private void insert(final Widget child, Tab tab, int beforeIndex) {
+ assert (beforeIndex >= 0) && (beforeIndex <= getWidgetCount()) : "beforeIndex out of bounds";
+
+ // Check to see if the TabPanel already contains the Widget. If so,
+ // remove it and see if we need to shift the position to the left.
+ int idx = getWidgetIndex(child);
+ if (idx != -1) {
+ remove(child);
+ if (idx < beforeIndex) {
+ beforeIndex--;
+ }
+ }
+
+ children.insert(child, beforeIndex);
+ tabs.add(beforeIndex, tab);
+
+ tabBar.insert(tab.asWidget(), beforeIndex);
+ tab.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ selectTab(child);
+ }
+ });
+
+ panel.insert(child, beforeIndex);
+ layoutChild(child);
+
+ if (selectedIndex == -1) {
+ selectTab(0);
+ }
+ }
+
+ private void layoutChild(Widget child) {
+ Layer layer = panel.getLayer(child);
+ layer.setLeftRight(0, Unit.PX, 0, Unit.PX);
+ layer.setTopBottom(tabBarSize, tabBarUnit, 0, Unit.PX);
+ layer.getContainerElement().getStyle().setVisibility(Visibility.HIDDEN);
+ panel.layout();
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/TabLayoutPanelTest.java b/user/test/com/google/gwt/user/client/ui/TabLayoutPanelTest.java
new file mode 100644
index 0000000..344c4fd
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/TabLayoutPanelTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.logical.shared.BeforeSelectionEvent;
+import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import java.util.Iterator;
+
+/**
+ * Tests for {@link TabLayoutPanel}.
+ */
+public class TabLayoutPanelTest extends GWTTestCase {
+
+ static class Adder implements HasWidgetsTester.WidgetAdder {
+ public void addChild(HasWidgets container, Widget child) {
+ ((TabPanel) container).add(child, "foo");
+ }
+ }
+
+ private class TestSelectionHandler implements BeforeSelectionHandler<Integer>, SelectionHandler<Integer> {
+ private boolean onBeforeFired;
+
+ public void onBeforeSelection(BeforeSelectionEvent<Integer> event) {
+ onBeforeFired = true;
+ }
+
+ public void onSelection(SelectionEvent<Integer> event) {
+ assertTrue(onBeforeFired);
+ finishTest();
+ }
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.DebugTest";
+ }
+
+ public void testAttachDetachOrder() {
+ HasWidgetsTester.testAll(new TabPanel(), new Adder(), true);
+ }
+
+ public void testInsertMultipleTimes() {
+ TabLayoutPanel p = new TabLayoutPanel(2, Unit.EM);
+
+ TextBox tb = new TextBox();
+ p.add(tb, "Title");
+ p.add(tb, "Title");
+ p.add(tb, "Title3");
+
+ assertEquals(1, p.getWidgetCount());
+ assertEquals(0, p.getWidgetIndex(tb));
+ Iterator<Widget> i = p.iterator();
+ assertTrue(i.hasNext());
+ assertTrue(tb.equals(i.next()));
+ assertFalse(i.hasNext());
+
+ Label l = new Label();
+ p.add(l, "Title");
+ p.add(l, "Title");
+ p.add(l, "Title3");
+ assertEquals(2, p.getWidgetCount());
+ assertEquals(0, p.getWidgetIndex(tb));
+ assertEquals(1, p.getWidgetIndex(l));
+
+ p.insert(l, "Title", 0);
+ assertEquals(2, p.getWidgetCount());
+ assertEquals(0, p.getWidgetIndex(l));
+ assertEquals(1, p.getWidgetIndex(tb));
+
+ p.insert(l, "Title", 1);
+ assertEquals(2, p.getWidgetCount());
+ assertEquals(0, p.getWidgetIndex(l));
+ assertEquals(1, p.getWidgetIndex(tb));
+
+ p.insert(l, "Title", 2);
+ assertEquals(2, p.getWidgetCount());
+ assertEquals(0, p.getWidgetIndex(tb));
+ assertEquals(1, p.getWidgetIndex(l));
+ }
+
+ public void testInsertWithHTML() {
+ TabLayoutPanel p = new TabLayoutPanel(2, Unit.EM);
+ Label l = new Label();
+ p.add(l, "three");
+ p.insert(new HTML("<b>hello</b>"), "two", true, 0);
+ p.insert(new HTML("goodbye"), "one", false, 0);
+ assertEquals(3, p.getWidgetCount());
+ }
+
+ /**
+ * Tests to ensure that arbitrary widgets can be added/inserted effectively.
+ */
+ public void testInsertWithWidgets() {
+ TabLayoutPanel p = new TabLayoutPanel(2, Unit.EM);
+
+ TextBox wa = new TextBox();
+ CheckBox wb = new CheckBox();
+ VerticalPanel wc = new VerticalPanel();
+ wc.add(new Label("First"));
+ wc.add(new Label("Second"));
+
+ p.add(new Label("Content C"), wc);
+ p.insert(new Label("Content B"), wb, 0);
+ p.insert(new Label("Content A"), wa, 0);
+
+ // Call these to ensure we don't throw an exception.
+ assertNotNull(p.getTabWidget(0));
+ assertNotNull(p.getTabWidget(1));
+ assertNotNull(p.getTabWidget(2));
+ assertEquals(3, p.getWidgetCount());
+ }
+
+ public void testIterator() {
+ TabLayoutPanel p = new TabLayoutPanel(2, Unit.EM);
+ HTML foo = new HTML("foo");
+ HTML bar = new HTML("bar");
+ HTML baz = new HTML("baz");
+ p.add(foo, "foo");
+ p.add(bar, "bar");
+ p.add(baz, "baz");
+
+ // Iterate over the entire set and make sure it stops correctly.
+ Iterator<Widget> it = p.iterator();
+ assertTrue(it.hasNext());
+ assertTrue(it.next() == foo);
+ assertTrue(it.hasNext());
+ assertTrue(it.next() == bar);
+ assertTrue(it.hasNext());
+ assertTrue(it.next() == baz);
+ assertFalse(it.hasNext());
+
+ // Test removing using the iterator.
+ it = p.iterator();
+ it.next();
+ it.remove();
+ assertTrue(it.next() == bar);
+ assertTrue(p.getWidgetCount() == 2);
+ assertTrue(p.getWidget(0) == bar);
+ assertTrue(p.getWidget(1) == baz);
+ }
+
+ public void testSelectionEvents() {
+ TabLayoutPanel p = new TabLayoutPanel(2, Unit.EM);
+ RootPanel.get().add(p);
+
+ p.add(new Button("foo"), "foo");
+ p.add(new Button("bar"), "bar");
+
+ // Make sure selecting a tab fires both events in the right order.
+ TestSelectionHandler handler = new TestSelectionHandler();
+ p.addBeforeSelectionHandler(handler);
+ p.addSelectionHandler(handler);
+
+ delayTestFinish(1000);
+ p.selectTab(1);
+ }
+}