Revision: 9748
Author: jlaba...@google.com
Date: Thu Feb 17 05:39:09 2011
Log: Fixing insert/remove bugs in StackLayoutPanel. Insert always appends
to the end. Remove does not redraw the panel. Neither adjusted the
selectedIndex when inserting/removing at a lower index. This patch also
makes StackLayoutPanel implement AnimatedLayout so users can change the
default animation duration or force layout.
Issue: 4926, 5304
Review at http://gwt-code-reviews.appspot.com/1359803
Review by: rchan...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=9748
Modified:
/trunk/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
/trunk/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
=======================================
--- /trunk/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java Wed
Feb 16 10:10:39 2011
+++ /trunk/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java Thu
Feb 17 05:39:09 2011
@@ -30,6 +30,7 @@
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.AnimationCallback;
import com.google.gwt.safehtml.shared.SafeHtml;
import java.util.ArrayList;
@@ -95,7 +96,7 @@
* </pre>
*/
public class StackLayoutPanel extends ResizeComposite implements
HasWidgets,
- ProvidesResize, IndexedPanel.ForIsWidget,
+ ProvidesResize, IndexedPanel.ForIsWidget, AnimatedLayout,
HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {
private class Header extends Composite implements HasClickHandlers {
@@ -135,6 +136,7 @@
private static final int ANIMATION_TIME = 250;
+ private int animationDuration = ANIMATION_TIME;
private LayoutPanel layoutPanel;
private final Unit unit;
private final ArrayList<LayoutData> layoutData = new
ArrayList<LayoutData>();
@@ -231,12 +233,68 @@
SelectionHandler<Integer> handler) {
return addHandler(handler, SelectionEvent.getType());
}
+
+ public void animate(int duration) {
+ animate(duration, null);
+ }
+
+ public void animate(int duration, AnimationCallback callback) {
+ // Don't try to animate zero widgets.
+ if (layoutData.size() == 0) {
+ if (callback != null) {
+ callback.onAnimationComplete();
+ }
+ return;
+ }
+
+ double top = 0, bottom = 0;
+ int i = 0;
+ for (; i < layoutData.size(); ++i) {
+ LayoutData data = layoutData.get(i);
+ layoutPanel.setWidgetTopHeight(data.header, top, unit,
data.headerSize,
+ unit);
+
+ top += data.headerSize;
+
+ layoutPanel.setWidgetTopHeight(data.widget, top, unit, 0, unit);
+
+ if (i == selectedIndex) {
+ break;
+ }
+ }
+
+ for (int j = layoutData.size() - 1; j > i; --j) {
+ LayoutData data = layoutData.get(j);
+ layoutPanel.setWidgetBottomHeight(data.header, bottom, unit,
+ data.headerSize, unit);
+ layoutPanel.setWidgetBottomHeight(data.widget, bottom, unit, 0,
unit);
+ bottom += data.headerSize;
+ }
+
+ LayoutData data = layoutData.get(selectedIndex);
+ layoutPanel.setWidgetTopBottom(data.widget, top, unit, bottom, unit);
+
+ layoutPanel.animate(duration, callback);
+ }
public void clear() {
layoutPanel.clear();
layoutData.clear();
selectedIndex = -1;
}
+
+ public void forceLayout() {
+ layoutPanel.forceLayout();
+ }
+
+ /**
+ * Get the duration of the animated transition between children.
+ *
+ * @return the duration in milliseconds
+ */
+ public int getAnimationDuration() {
+ return animationDuration;
+ }
/**
* Gets the widget in the stack header at the given index.
@@ -421,6 +479,11 @@
if (layoutData.size() > 0) {
showWidget(layoutData.get(0).widget);
}
+ } else {
+ if (i <= selectedIndex) {
+ selectedIndex--;
+ }
+ animate(animationDuration);
}
return true;
}
@@ -428,6 +491,15 @@
return false;
}
+
+ /**
+ * Set the duration of the animated transition between children.
+ *
+ * @param duration the duration in milliseconds.
+ */
+ public void setAnimationDuration(int duration) {
+ this.animationDuration = duration;
+ }
/**
* Sets a stack header's HTML contents.
@@ -491,7 +563,7 @@
*/
public void showWidget(int index, boolean fireEvents) {
checkIndex(index);
- showWidget(index, ANIMATION_TIME, fireEvents);
+ showWidget(index, animationDuration, fireEvents);
}
/**
@@ -510,7 +582,7 @@
* @param fireEvents true to fire events, false not to
*/
public void showWidget(Widget child, boolean fireEvents) {
- showWidget(getWidgetIndex(child), ANIMATION_TIME, fireEvents);
+ showWidget(getWidgetIndex(child), animationDuration, fireEvents);
}
@Override
@@ -518,42 +590,6 @@
// When the widget becomes attached, update its layout.
animate(0);
}
-
- private void animate(int duration) {
- // Don't try to animate zero widgets.
- if (layoutData.size() == 0) {
- return;
- }
-
- double top = 0, bottom = 0;
- int i = 0;
- for (; i < layoutData.size(); ++i) {
- LayoutData data = layoutData.get(i);
- layoutPanel.setWidgetTopHeight(data.header, top, unit,
data.headerSize,
- unit);
-
- top += data.headerSize;
-
- layoutPanel.setWidgetTopHeight(data.widget, top, unit, 0, unit);
-
- if (i == selectedIndex) {
- break;
- }
- }
-
- for (int j = layoutData.size() - 1; j > i; --j) {
- LayoutData data = layoutData.get(j);
- layoutPanel.setWidgetBottomHeight(data.header, bottom, unit,
- data.headerSize, unit);
- layoutPanel.setWidgetBottomHeight(data.widget, bottom, unit, 0,
unit);
- bottom += data.headerSize;
- }
-
- LayoutData data = layoutData.get(selectedIndex);
- layoutPanel.setWidgetTopBottom(data.widget, top, unit, bottom, unit);
-
- layoutPanel.animate(duration);
- }
private void checkChild(Widget child) {
assert layoutPanel.getChildren().contains(child);
@@ -577,15 +613,15 @@
}
}
- beforeIndex *= 2;
- layoutPanel.insert(child, beforeIndex);
- layoutPanel.insert(header, beforeIndex);
+ int widgetIndex = beforeIndex * 2;
+ layoutPanel.insert(child, widgetIndex);
+ layoutPanel.insert(header, widgetIndex);
layoutPanel.setWidgetLeftRight(header, 0, Unit.PX, 0, Unit.PX);
layoutPanel.setWidgetLeftRight(child, 0, Unit.PX, 0, Unit.PX);
LayoutData data = new LayoutData(child, header, headerSize);
- layoutData.add(data);
+ layoutData.add(beforeIndex, data);
header.addStyleName(HEADER_STYLE);
child.addStyleName(CONTENT_STYLE);
@@ -612,12 +648,15 @@
// If there's no visible widget, display the first one. The layout
will
// be updated onLoad().
showWidget(0);
+ } else if (beforeIndex <= selectedIndex) {
+ // If we inserted an item before the selected index, increment it.
+ selectedIndex++;
}
// If the widget is already attached, we must call animate() to update
the
// layout (if it's not yet attached, then onLoad() will do this).
if (isAttached()) {
- animate(ANIMATION_TIME);
+ animate(animationDuration);
}
}
=======================================
---
/trunk/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
Wed Feb 16 10:10:39 2011
+++
/trunk/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
Thu Feb 17 05:39:09 2011
@@ -204,14 +204,27 @@
wc.add(new Label("First"));
wc.add(new Label("Second"));
- p.add(new Label("Content C"), wc, 1);
- p.insert(new Label("Content B"), wb, 1, 0);
- p.insert(new Label("Content A"), wa, 1, 0);
+ Label contentA = new Label("Content A");
+ Label contentB = new Label("Content B");
+ Label contentC = new Label("Content C");
+
+ p.add(contentC, wc, 1);
+ p.insert(contentB, wb, 1, 0);
+ p.showWidget(1);
+
+ // Insert before the visible widget.
+ p.insert(contentA, wa, 1, 0);
+
+ // Check that the visible widget index has been incremented.
+ assertEquals(2, p.getVisibleIndex());
// Call these to ensure we don't throw an exception.
- assertNotNull(p.getHeaderWidget(0));
- assertNotNull(p.getHeaderWidget(1));
- assertNotNull(p.getHeaderWidget(2));
+ assertEquals(wa, p.getHeaderWidget(0));
+ assertEquals(wb, p.getHeaderWidget(1));
+ assertEquals(wc, p.getHeaderWidget(2));
+ assertEquals(contentA, p.getWidget(0));
+ assertEquals(contentB, p.getWidget(1));
+ assertEquals(contentC, p.getWidget(2));
assertEquals(3, p.getWidgetCount());
}
@@ -243,6 +256,32 @@
assertTrue(p.getWidget(0) == bar);
assertTrue(p.getWidget(1) == baz);
}
+
+ public void testRemoveBeforeSelectedWidget() {
+ StackLayoutPanel p = new StackLayoutPanel(Unit.EM);
+ p.add(new Label("Content 0"), "Header 0", 1);
+ p.add(new Label("Content 1"), "Header 0", 1);
+ p.add(new Label("Content 2"), "Header 2", 1);
+ p.showWidget(2);
+ assertEquals(2, p.getVisibleIndex());
+
+ // Remove a widget before the selected index.
+ p.remove(1);
+ assertEquals(1, p.getVisibleIndex());
+ }
+
+ public void testRemoveSelectedWidget() {
+ StackLayoutPanel p = new StackLayoutPanel(Unit.EM);
+ p.add(new Label("Content 0"), "Header 0", 1);
+ p.add(new Label("Content 1"), "Header 0", 1);
+ p.add(new Label("Content 2"), "Header 2", 1);
+ p.showWidget(1);
+ assertEquals(1, p.getVisibleIndex());
+
+ // Remove the selected widget.
+ p.remove(1);
+ assertEquals(0, p.getVisibleIndex());
+ }
public void testSelectionEvents() {
StackLayoutPanel p = new StackLayoutPanel(Unit.EM);
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors