]> source.dussan.org Git - vaadin-framework.git/commitdiff
Test cases and fix for #2425/#2289 - Removing a Tab from TabSheet or Accordion should...
authorArtur Signell <artur.signell@itmill.com>
Sun, 11 Jan 2009 19:52:56 +0000 (19:52 +0000)
committerArtur Signell <artur.signell@itmill.com>
Sun, 11 Jan 2009 19:52:56 +0000 (19:52 +0000)
svn changeset:6496/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetBase.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheetPanel.java
src/com/itmill/toolkit/tests/components/TestBase.java [new file with mode: 0644]
src/com/itmill/toolkit/tests/components/accordion/RemoveTabs.java [new file with mode: 0644]
src/com/itmill/toolkit/tests/components/tabsheet/RemoveTabs.java [new file with mode: 0644]

index a97787218f184561e3854e0d41f50c1f88bab4c3..aeec3bf1b085ff2fb826ff369b01528e048a5be7 100644 (file)
@@ -1,6 +1,5 @@
 package com.itmill.toolkit.terminal.gwt.client.ui;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -27,8 +26,6 @@ public class IAccordion extends ITabsheetBase implements
 
     public static final String CLASSNAME = "i-accordion";
 
-    private ArrayList<StackItem> stack = new ArrayList<StackItem>();
-
     private Set<Paintable> paintables = new HashSet<Paintable>();
 
     private String height;
@@ -65,7 +62,7 @@ public class IAccordion extends ITabsheetBase implements
          * the content area is
          */
         if (selectedUIDLItemIndex >= 0) {
-            StackItem selectedItem = stack.get(selectedUIDLItemIndex);
+            StackItem selectedItem = getStackItem(selectedUIDLItemIndex);
             UIDL selectedTabUIDL = lazyUpdateMap.remove(selectedItem);
             open(selectedUIDLItemIndex);
 
@@ -95,17 +92,17 @@ public class IAccordion extends ITabsheetBase implements
             boolean hidden) {
         StackItem item;
         int itemIndex;
-        if (stack.size() <= index) {
+        if (getWidgetCount() <= index) {
             // Create stackItem and render caption
             item = new StackItem(tabUidl);
-            if (stack.size() == 0) {
+            if (getWidgetCount() == 0) {
                 item.addStyleDependentName("first");
             }
-            stack.add(item);
-            itemIndex = stack.size() - 1;
+            itemIndex = getWidgetCount();
             add(item, getElement());
         } else {
-            item = stack.get(index);
+            item = getStackItem(index);
+            item = moveStackItemIfNeeded(item, index, tabUidl);
             itemIndex = index;
             item.updateCaption(tabUidl);
         }
@@ -121,8 +118,72 @@ public class IAccordion extends ITabsheetBase implements
         }
     }
 
+    /**
+     * This method tries to find out if a tab has been rendered with a different
+     * index previously. If this is the case it re-orders the children so the
+     * same StackItem is used for rendering this time. E.g. if the first tab has
+     * been removed all tabs which contain cached content must be moved 1 step
+     * up to preserve the cached content.
+     * 
+     * @param item
+     * @param newIndex
+     * @param tabUidl
+     * @return
+     */
+    private StackItem moveStackItemIfNeeded(StackItem item, int newIndex,
+            UIDL tabUidl) {
+        UIDL tabContentUIDL = null;
+        Paintable tabContent = null;
+        if (tabUidl.getChildCount() > 0) {
+            tabContentUIDL = tabUidl.getChildUIDL(0);
+            tabContent = client.getPaintable(tabContentUIDL);
+        }
+
+        Widget itemWidget = item.getComponent();
+        if (tabContent != null) {
+            if (tabContent != itemWidget) {
+                /*
+                 * This is not the same widget as before, find out if it has
+                 * been moved
+                 */
+                int oldIndex = -1;
+                StackItem oldItem = null;
+                for (int i = 0; i < getWidgetCount(); i++) {
+                    Widget w = getWidget(i);
+                    oldItem = (StackItem) w;
+                    if (tabContent == oldItem.getComponent()) {
+                        oldIndex = i;
+                        break;
+                    }
+                }
+
+                if (oldIndex != -1 && oldIndex > newIndex) {
+                    /*
+                     * The tab has previously been rendered in another position
+                     * so we must move the cached content to correct position.
+                     * We move only items with oldIndex > newIndex to prevent
+                     * moving items already rendered in this update. If for
+                     * instance tabs 1,2,3 are removed and added as 3,2,1 we
+                     * cannot re-use "1" when we get to the third tab.
+                     */
+                    insert(oldItem, getElement(), newIndex, true);
+                    return oldItem;
+                }
+            }
+        } else {
+            // Tab which has never been loaded. Must assure we use an empty
+            // StackItem
+            Widget oldWidget = item.getComponent();
+            if (oldWidget != null) {
+                item = new StackItem(tabUidl);
+                insert(item, getElement(), newIndex, true);
+            }
+        }
+        return item;
+    }
+
     private void open(int itemIndex) {
-        StackItem item = stack.get(itemIndex);
+        StackItem item = (StackItem) getWidget(itemIndex);
         boolean alreadyOpen = false;
         if (openTab != null) {
             if (openTab.isOpen()) {
@@ -157,7 +218,7 @@ public class IAccordion extends ITabsheetBase implements
 
     @Override
     protected void selectTab(final int index, final UIDL contentUidl) {
-        StackItem item = stack.get(index);
+        StackItem item = getStackItem(index);
         if (index != activeTabIndex) {
             open(index);
             iLayout();
@@ -169,7 +230,7 @@ public class IAccordion extends ITabsheetBase implements
     }
 
     public void onSelectTab(StackItem item) {
-        final int index = stack.indexOf(item);
+        final int index = getWidgetIndex(item);
         if (index != activeTabIndex && !disabled && !readonly
                 && !disabledTabKeys.contains(tabKeys.get(index))) {
             addStyleDependentName("loading");
@@ -236,8 +297,8 @@ public class IAccordion extends ITabsheetBase implements
         // HEIGHT
         if (!isDynamicHeight()) {
             int usedPixels = 0;
-            for (Iterator iterator = stack.iterator(); iterator.hasNext();) {
-                StackItem item = (StackItem) iterator.next();
+            for (Widget w : getChildren()) {
+                StackItem item = (StackItem) w;
                 if (item == openTab) {
                     usedPixels += item.getCaptionHeight();
                 } else {
@@ -271,7 +332,8 @@ public class IAccordion extends ITabsheetBase implements
 
         if (isDynamicWidth()) {
             int maxWidth = 40;
-            for (StackItem si : stack) {
+            for (Widget w : getChildren()) {
+                StackItem si = (StackItem) w;
                 int captionWidth = si.getCaptionWidth();
                 if (captionWidth > maxWidth) {
                     maxWidth = captionWidth;
@@ -308,6 +370,13 @@ public class IAccordion extends ITabsheetBase implements
             }
         }
 
+        public Widget getComponent() {
+            if (getWidgetCount() < 2) {
+                return null;
+            }
+            return getWidget(1);
+        }
+
         @Override
         public void setVisible(boolean visible) {
             super.setVisible(visible);
@@ -480,7 +549,6 @@ public class IAccordion extends ITabsheetBase implements
 
     @Override
     protected void clearPaintables() {
-        stack.clear();
         clear();
     }
 
@@ -506,7 +574,8 @@ public class IAccordion extends ITabsheetBase implements
     }
 
     public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        for (StackItem item : stack) {
+        for (Widget w : getChildren()) {
+            StackItem item = (StackItem) w;
             if (item.getPaintable() == oldComponent) {
                 item.replacePaintable((Paintable) newComponent);
                 return;
@@ -515,8 +584,8 @@ public class IAccordion extends ITabsheetBase implements
     }
 
     public void updateCaption(Paintable component, UIDL uidl) {
-        for (Iterator iterator = stack.iterator(); iterator.hasNext();) {
-            StackItem si = (StackItem) iterator.next();
+        for (Widget w : getChildren()) {
+            StackItem si = (StackItem) w;
             if (si.getPaintable() == component) {
                 boolean visible = si.isVisible();
                 si.updateCaption(uidl);
@@ -567,13 +636,25 @@ public class IAccordion extends ITabsheetBase implements
 
     @Override
     protected int getTabCount() {
-        return stack.size();
+        return getWidgetCount();
     }
 
     @Override
     protected void removeTab(int index) {
-        StackItem item = stack.get(index);
+        StackItem item = getStackItem(index);
         remove(item);
     }
 
+    @Override
+    protected Paintable getTab(int index) {
+        if (index < getWidgetCount()) {
+            return (Paintable) (getStackItem(index)).getPaintable();
+        }
+
+        return null;
+    }
+
+    private StackItem getStackItem(int index) {
+        return (StackItem) getWidget(index);
+    }
 }
index 3c963feed3b579e39d66aa1f8a3c39679cd902df..590d4d7259c2daa7f01b21bd173d7508f3281f09 100644 (file)
@@ -16,7 +16,6 @@ import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.ClickListener;
 import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.Widget;
 import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
 import com.itmill.toolkit.terminal.gwt.client.ICaption;
@@ -417,25 +416,63 @@ public class ITabsheet extends ITabsheetBase {
          */
         c.setWidth(c.getRequiredWidth() + "px");
         captions.put("" + index, c);
+
+        UIDL tabContentUIDL = null;
+        Paintable tabContent = null;
+        if (tabUidl.getChildCount() > 0) {
+            tabContentUIDL = tabUidl.getChildUIDL(0);
+            tabContent = client.getPaintable(tabContentUIDL);
+        }
+
+        if (tabContent != null) {
+            /* This is a tab with content information */
+
+            int oldIndex = tp.getWidgetIndex((Widget) tabContent);
+            if (oldIndex != -1 && oldIndex != index) {
+                /*
+                 * The tab has previously been rendered in another position so
+                 * we must move the cached content to correct position
+                 */
+                tp.insert((Widget) tabContent, index);
+            }
+        } else {
+            /* A tab whose content has not yet been loaded */
+
+            /*
+             * Make sure there is a corresponding empty tab in tp. The same
+             * operation as the moving above but for not-loaded tabs.
+             */
+            if (index < tp.getWidgetCount()) {
+                Widget oldWidget = tp.getWidget(index);
+                if (!(oldWidget instanceof PlaceHolder)) {
+                    tp.insert(new PlaceHolder(), index);
+                }
+            }
+
+        }
+
         if (selected) {
-            renderContent(tabUidl.getChildUIDL(0));
+            renderContent(tabContentUIDL);
             tb.selectTab(index);
         } else {
-            if (tabUidl.getChildCount() > 0) {
+            if (tabContentUIDL != null) {
                 // updating a drawn child on hidden tab
-                Paintable paintable = client.getPaintable(tabUidl
-                        .getChildUIDL(0));
-
-                if (tp.getWidgetIndex((Widget) paintable) < 0) {
-                    tp.insert((Widget) paintable, index);
+                if (tp.getWidgetIndex((Widget) tabContent) < 0) {
+                    tp.insert((Widget) tabContent, index);
                 }
-                paintable.updateFromUIDL(tabUidl.getChildUIDL(0), client);
+                tabContent.updateFromUIDL(tabContentUIDL, client);
             } else if (tp.getWidgetCount() <= index) {
-                tp.add(new Label(""));
+                tp.add(new PlaceHolder());
             }
         }
     }
 
+    public class PlaceHolder extends ILabel {
+        public PlaceHolder() {
+            super("");
+        }
+    }
+
     @Override
     protected void selectTab(int index, final UIDL contentUidl) {
         if (index != activeTabIndex) {
@@ -709,6 +746,14 @@ public class ITabsheet extends ITabsheetBase {
         return tb.getWidgetCount();
     }
 
+    @Override
+    protected Paintable getTab(int index) {
+        if (tp.getWidgetCount() > index) {
+            return (Paintable) tp.getWidget(index);
+        }
+        return null;
+    }
+
     @Override
     protected void removeTab(int index) {
         tb.removeTab(index);
index d6cb53457744cc942d84bc92329ad4ba92cc2e2e..8117ef615153eab0794e827b373a8ea307326dad 100644 (file)
@@ -45,6 +45,8 @@ abstract class ITabsheetBase extends ComplexPanel implements Container {
 
         // Render content
         final UIDL tabs = uidl.getChildUIDL(0);
+
+        // Paintables in the TabSheet before update
         ArrayList oldPaintables = new ArrayList();
         for (Iterator iterator = getPaintableIterator(); iterator.hasNext();) {
             oldPaintables.add(iterator.next());
@@ -70,10 +72,6 @@ abstract class ITabsheetBase extends ComplexPanel implements Container {
             if (selected) {
                 activeTabIndex = index;
             }
-            if (tab.getChildCount() > 0) {
-                Paintable p = client.getPaintable(tab.getChildUIDL(0));
-                oldPaintables.remove(p);
-            }
             renderTab(tab, index, selected, hidden);
             index++;
         }
@@ -83,6 +81,12 @@ abstract class ITabsheetBase extends ComplexPanel implements Container {
             removeTab(index);
         }
 
+        for (int i = 0; i < getTabCount(); i++) {
+            Paintable p = getTab(i);
+            oldPaintables.remove(p);
+        }
+
+        // Perform unregister for any paintables removed during update
         for (Iterator iterator = oldPaintables.iterator(); iterator.hasNext();) {
             Object oldPaintable = iterator.next();
             if (oldPaintable instanceof Paintable) {
@@ -126,6 +130,12 @@ abstract class ITabsheetBase extends ComplexPanel implements Container {
      */
     protected abstract int getTabCount();
 
+    /**
+     * Implement in extending classes. This method should return the Paintable
+     * corresponding to the given index.
+     */
+    protected abstract Paintable getTab(int index);
+
     /**
      * Implement in extending classes. This method should remove the rendered
      * tab with the specified index.
index a21d1b7d98c354c2e7e92e3e3eb08dd78691bcc6..e9dc44ee3c34ee86b6499e29ab60c072fb9ceef0 100644 (file)
@@ -72,20 +72,25 @@ public class ITabsheetPanel extends ComplexPanel {
      */\r
     public void insert(Widget w, int beforeIndex) {\r
         Element el = createContainerElement();\r
-        super.insert(w, el, beforeIndex, false);\r
         DOM.insertChild(getElement(), el, beforeIndex);\r
+        super.insert(w, el, beforeIndex, false);\r
     }\r
 \r
     @Override\r
     public boolean remove(Widget w) {\r
-        final int index = getWidgetIndex(w);\r
+        Element child = w.getElement();\r
+        Element parent = null;\r
+        if (child != null) {\r
+            parent = DOM.getParent(child);\r
+        }\r
         final boolean removed = super.remove(w);\r
         if (removed) {\r
             if (visibleWidget == w) {\r
                 visibleWidget = null;\r
             }\r
-            Element child = DOM.getChild(getElement(), index);\r
-            DOM.removeChild(getElement(), child);\r
+            if (parent != null) {\r
+                DOM.removeChild(getElement(), parent);\r
+            }\r
         }\r
         return removed;\r
     }\r
diff --git a/src/com/itmill/toolkit/tests/components/TestBase.java b/src/com/itmill/toolkit/tests/components/TestBase.java
new file mode 100644 (file)
index 0000000..0cc1a0f
--- /dev/null
@@ -0,0 +1,45 @@
+package com.itmill.toolkit.tests.components;\r
+\r
+import com.itmill.toolkit.Application;\r
+import com.itmill.toolkit.ui.Label;\r
+import com.itmill.toolkit.ui.Layout;\r
+import com.itmill.toolkit.ui.SplitPanel;\r
+import com.itmill.toolkit.ui.VerticalLayout;\r
+import com.itmill.toolkit.ui.Window;\r
+\r
+public abstract class TestBase extends Application {\r
+\r
+    @Override\r
+    public final void init() {\r
+        window = new Window(getClass().getName());\r
+        setMainWindow(window);\r
+        window.getLayout().setSizeFull();\r
+\r
+        Label label = new Label(getDescription());\r
+        label.setWidth("100%");\r
+        window.getLayout().addComponent(label);\r
+\r
+        layout = new VerticalLayout();\r
+        window.getLayout().addComponent(layout);\r
+        ((VerticalLayout) window.getLayout()).setExpandRatio(layout, 1);\r
+\r
+        setup();\r
+    }\r
+\r
+    private Window window;\r
+    private SplitPanel splitPanel;\r
+    private Layout layout;\r
+\r
+    public TestBase() {\r
+\r
+    }\r
+\r
+    protected Layout getLayout() {\r
+        return layout;\r
+    }\r
+\r
+    protected abstract String getDescription();\r
+\r
+    protected abstract void setup();\r
+\r
+}\r
diff --git a/src/com/itmill/toolkit/tests/components/accordion/RemoveTabs.java b/src/com/itmill/toolkit/tests/components/accordion/RemoveTabs.java
new file mode 100644 (file)
index 0000000..7ee5e07
--- /dev/null
@@ -0,0 +1,125 @@
+package com.itmill.toolkit.tests.components.accordion;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import com.itmill.toolkit.tests.components.TestBase;\r
+import com.itmill.toolkit.ui.AbstractComponentContainer;\r
+import com.itmill.toolkit.ui.Accordion;\r
+import com.itmill.toolkit.ui.Button;\r
+import com.itmill.toolkit.ui.Component;\r
+import com.itmill.toolkit.ui.Label;\r
+import com.itmill.toolkit.ui.Button.ClickEvent;\r
+\r
+public class RemoveTabs extends TestBase {\r
+\r
+    private Accordion accordion;\r
+\r
+    protected Component[] tab = new Component[5];\r
+\r
+    private Button closeCurrent;\r
+    private Button closeFirst;\r
+    private Button closeLast;\r
+    private Button reorderTabs;\r
+\r
+    @Override\r
+    protected String getDescription() {\r
+        return "Tests the removal of individual tabs from an Accordion. No matter what is done in this test the tab caption \"Tab X\" should always match the content \"Tab X\". Use \"remove first\" and \"remove active\" buttons to remove the first or the active tab. The \"reorder\" button reverses the order by adding and removing all components.";\r
+    }\r
+\r
+    @Override\r
+    protected void setup() {\r
+        accordion = new Accordion();\r
+        for (int i = 1; i <= tab.length; i++) {\r
+            tab[i - 1] = new Label("This is the contents of tab " + i);\r
+            tab[i - 1].setCaption("Tab " + i);\r
+\r
+            accordion.addComponent(tab[i - 1]);\r
+        }\r
+\r
+        getLayout().addComponent(accordion);\r
+\r
+        closeCurrent = new Button("Close current tab");\r
+        closeCurrent.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeCurrentTab();\r
+\r
+            }\r
+        });\r
+\r
+        closeFirst = new Button("close first tab");\r
+        closeFirst.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeFirstTab();\r
+\r
+            }\r
+        });\r
+\r
+        closeLast = new Button("close last tab");\r
+        closeLast.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeLastTab();\r
+\r
+            }\r
+        });\r
+\r
+        reorderTabs = new Button("reorder");\r
+        reorderTabs.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                reorder();\r
+\r
+            }\r
+        });\r
+\r
+        getLayout().addComponent(closeFirst);\r
+        getLayout().addComponent(closeLast);\r
+        getLayout().addComponent(closeCurrent);\r
+        getLayout().addComponent(reorderTabs);\r
+\r
+    }\r
+\r
+    private void closeCurrentTab() {\r
+        Component c = accordion.getSelectedTab();\r
+        if (c != null) {\r
+            accordion.removeComponent(c);\r
+        }\r
+    }\r
+\r
+    private void closeFirstTab() {\r
+        accordion.removeComponent((Component) accordion.getComponentIterator()\r
+                .next());\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private void closeLastTab() {\r
+        Iterator i = accordion.getComponentIterator();\r
+        Component last = null;\r
+        while (i.hasNext()) {\r
+            last = (Component) i.next();\r
+\r
+        }\r
+        accordion.removeComponent(last);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private void reorder() {\r
+        AbstractComponentContainer container = accordion;\r
+\r
+        if (container != null) {\r
+            List<Component> c = new ArrayList<Component>();\r
+            Iterator<Component> i = container.getComponentIterator();\r
+            while (i.hasNext()) {\r
+                Component comp = i.next();\r
+                c.add(comp);\r
+            }\r
+            container.removeAllComponents();\r
+\r
+            for (int j = c.size() - 1; j >= 0; j--) {\r
+                container.addComponent(c.get(j));\r
+            }\r
+\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/com/itmill/toolkit/tests/components/tabsheet/RemoveTabs.java b/src/com/itmill/toolkit/tests/components/tabsheet/RemoveTabs.java
new file mode 100644 (file)
index 0000000..bbae6ca
--- /dev/null
@@ -0,0 +1,124 @@
+package com.itmill.toolkit.tests.components.tabsheet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import com.itmill.toolkit.tests.components.TestBase;\r
+import com.itmill.toolkit.ui.AbstractComponentContainer;\r
+import com.itmill.toolkit.ui.Button;\r
+import com.itmill.toolkit.ui.Component;\r
+import com.itmill.toolkit.ui.Label;\r
+import com.itmill.toolkit.ui.TabSheet;\r
+import com.itmill.toolkit.ui.Button.ClickEvent;\r
+\r
+public class RemoveTabs extends TestBase {\r
+\r
+    protected TabSheet tabsheet;\r
+\r
+    protected Component[] tab = new Component[5];\r
+\r
+    private Button closeCurrent;\r
+    private Button closeFirst;\r
+    private Button closeLast;\r
+    private Button reorderTabs;\r
+\r
+    @Override\r
+    protected String getDescription() {\r
+        return "Tests the removal of individual tabs from a Tabsheet. No matter what is done in this test the tab caption \"Tab X\" should always match the content \"Tab X\". Use \"remove first\" and \"remove active\" buttons to remove the first or the active tab. The \"reorder\" button reverses the order by adding and removing all components.";\r
+    }\r
+\r
+    @Override\r
+    protected void setup() {\r
+        tabsheet = new TabSheet();\r
+        for (int i = 1; i <= tab.length; i++) {\r
+            tab[i - 1] = new Label("This is the contents of tab " + i);\r
+            tab[i - 1].setCaption("Tab " + i);\r
+\r
+            tabsheet.addComponent(tab[i - 1]);\r
+        }\r
+\r
+        getLayout().addComponent(tabsheet);\r
+\r
+        closeCurrent = new Button("Close current tab");\r
+        closeCurrent.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeCurrentTab();\r
+\r
+            }\r
+        });\r
+\r
+        closeFirst = new Button("close first tab");\r
+        closeFirst.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeFirstTab();\r
+\r
+            }\r
+        });\r
+\r
+        closeLast = new Button("close last tab");\r
+        closeLast.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                closeLastTab();\r
+\r
+            }\r
+        });\r
+\r
+        reorderTabs = new Button("reorder");\r
+        reorderTabs.addListener(new Button.ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                reorder();\r
+\r
+            }\r
+        });\r
+\r
+        getLayout().addComponent(closeFirst);\r
+        getLayout().addComponent(closeLast);\r
+        getLayout().addComponent(closeCurrent);\r
+        getLayout().addComponent(reorderTabs);\r
+\r
+    }\r
+\r
+    private void closeCurrentTab() {\r
+        Component c = tabsheet.getSelectedTab();\r
+        if (c != null) {\r
+            tabsheet.removeComponent(c);\r
+        }\r
+    }\r
+\r
+    private void closeFirstTab() {\r
+        tabsheet.removeComponent((Component) tabsheet.getComponentIterator()\r
+                .next());\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private void closeLastTab() {\r
+        Iterator i = tabsheet.getComponentIterator();\r
+        Component last = null;\r
+        while (i.hasNext()) {\r
+            last = (Component) i.next();\r
+\r
+        }\r
+        tabsheet.removeComponent(last);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private void reorder() {\r
+        AbstractComponentContainer container = tabsheet;\r
+\r
+        if (container != null) {\r
+            List<Component> c = new ArrayList<Component>();\r
+            Iterator<Component> i = container.getComponentIterator();\r
+            while (i.hasNext()) {\r
+                Component comp = i.next();\r
+                c.add(comp);\r
+            }\r
+            container.removeAllComponents();\r
+\r
+            for (int j = c.size() - 1; j >= 0; j--) {\r
+                container.addComponent(c.get(j));\r
+            }\r
+\r
+        }\r
+    }\r
+}\r