Updated Branches:
  refs/heads/master 55cd66005 -> 0f9349b62

WICKET-4593 bi-directional model second try, more tests for TabbedPanel


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/0f9349b6
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/0f9349b6
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/0f9349b6

Branch: refs/heads/master
Commit: 0f9349b629017299b37f5f4841569f16dce732bc
Parents: 55cd660
Author: svenmeier <[email protected]>
Authored: Mon Jul 16 19:50:37 2012 +0200
Committer: svenmeier <[email protected]>
Committed: Mon Jul 16 19:50:37 2012 +0200

----------------------------------------------------------------------
 .../extensions/markup/html/tabs/TabbedPanel.java   |  108 ++++++--
 .../markup/html/tabs/TabbedPanelTest.java          |  193 ++++++++++++++-
 2 files changed, 265 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/0f9349b6/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanel.java
----------------------------------------------------------------------
diff --git 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanel.java
 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanel.java
index 8fa9d50..c8b2b47 100644
--- 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanel.java
+++ 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanel.java
@@ -34,7 +34,7 @@ import org.apache.wicket.util.lang.Args;
 
 
 /**
- * TabbedPanel component represets a panel with tabs that are used to switch 
between different
+ * TabbedPanel component represents a panel with tabs that are used to switch 
between different
  * content panels inside the TabbedPanel panel.
  * <p>
  * <b>Note:</b> When the currently selected tab is replaced by changing the 
underlying list of tabs,
@@ -81,6 +81,9 @@ public class TabbedPanel<T extends ITab> extends Panel
 
        private final List<T> tabs;
 
+       /** the current tab */
+       private int currentTab = -1;
+
        private transient Boolean[] tabsVisibilityCache;
 
        /**
@@ -93,7 +96,22 @@ public class TabbedPanel<T extends ITab> extends Panel
         */
        public TabbedPanel(final String id, final List<T> tabs)
        {
-               super(id, new Model<Integer>(-1));
+               this(id, tabs, null);
+       }
+
+       /**
+        * Constructor
+        * 
+        * @param id
+        *            component id
+        * @param tabs
+        *            list of ITab objects used to represent tabs
+        * @param model
+        *            model holding the index of the selected tab
+        */
+       public TabbedPanel(final String id, final List<T> tabs, IModel<Integer> 
model)
+       {
+               super(id, model);
 
                this.tabs = Args.notNull(tabs, "tabs");
 
@@ -134,6 +152,25 @@ public class TabbedPanel<T extends ITab> extends Panel
                                return newTabContainer(iteration);
                        }
                });
+
+               add(newPanel());
+       }
+
+       /**
+        * Initialize the component's model.
+        * 
+        * @return a new model containing {@code -1} if the super 
implementation doesn't supply one
+        */
+       @Override
+       protected IModel<?> initModel()
+       {
+               IModel<?> model = super.initModel();
+               if (model == null)
+               {
+                       model = new Model<Integer>(-1);
+               }
+
+               return model;
        }
 
        /**
@@ -207,38 +244,32 @@ public class TabbedPanel<T extends ITab> extends Panel
        @Override
        protected void onBeforeRender()
        {
-               if (tabs.size() == 0)
-               {
-                       // force an empty container to be created every time if 
we have no tabs
-                       setSelectedTab(0);
-               }
-               else if ((getSelectedTab() == -1) || 
(isTabVisible(getSelectedTab()) == false))
+               int index = getSelectedTab();
+
+               if ((index == -1) || (isTabVisible(index) == false))
                {
-                       // find first visible selected tab
-                       int selected = 0;
+                       // find first visible tab
+                       index = -1;
                        for (int i = 0; i < tabs.size(); i++)
                        {
                                if (isTabVisible(i))
                                {
-                                       selected = i;
+                                       index = i;
                                        break;
                                }
                        }
 
-                       if (selected == tabs.size())
+                       if (index != -1)
                        {
                                /*
-                                * none of the tabs are selected...
-                                * 
-                                * we do not need to do anything special 
because the check in setSelectedTab() will
-                                * replace the current tab panel with an empty 
one
+                                * found a visible tab, so select it
                                 */
-                               selected = 0;
+                               setSelectedTab(index);
                        }
-
-                       setSelectedTab(selected);
                }
 
+               setCurrentTab(index);
+
                super.onBeforeRender();
        }
 
@@ -330,32 +361,50 @@ public class TabbedPanel<T extends ITab> extends Panel
         * @param index
         *            index of the tab to select
         * @return this for chaining
+        * @throws IndexOutOfBoundsException
+        *             if index is not {@code -1} or in the range of available 
tabs
         */
-       public TabbedPanel setSelectedTab(final int index)
+       public TabbedPanel<T> setSelectedTab(final int index)
        {
-               if ((index < 0) || ((index >= tabs.size()) && (index > 0)))
+               if ((index < 0) || (index >= tabs.size()))
                {
                        throw new IndexOutOfBoundsException();
                }
 
                setDefaultModelObject(index);
 
+               // force the tab's component to be aquired again if already the 
current tab
+               currentTab = -1;
+               setCurrentTab(index);
+
+               return this;
+       }
+
+       private void setCurrentTab(int index)
+       {
+               if (this.currentTab == index)
+               {
+                       // already current
+                       return;
+               }
+               this.currentTab = index;
+
                final Component component;
 
-               if ((tabs.size() == 0) || !isTabVisible(index))
+               if (currentTab == -1 || (tabs.size() == 0) || 
!isTabVisible(currentTab))
                {
-                       // no tabs or the currently selected tab is not visible
-                       component = new WebMarkupContainer(TAB_PANEL_ID);
+                       // no tabs or the current tab is not visible
+                       component = newPanel();
                }
                else
                {
                        // show panel from selected tab
-                       T tab = tabs.get(index);
+                       T tab = tabs.get(currentTab);
                        component = tab.getPanel(TAB_PANEL_ID);
                        if (component == null)
                        {
                                throw new 
WicketRuntimeException("ITab.getPanel() returned null. TabbedPanel [" +
-                                       getPath() + "] ITab index [" + index + 
"]");
+                                       getPath() + "] ITab index [" + 
currentTab + "]");
                        }
                }
 
@@ -365,12 +414,15 @@ public class TabbedPanel<T extends ITab> extends Panel
                                "ITab.getPanel() returned a panel with invalid 
id [" +
                                        component.getId() +
                                        "]. You must always return a panel with 
id equal to the provided panelId parameter. TabbedPanel [" +
-                                       getPath() + "] ITab index [" + index + 
"]");
+                                       getPath() + "] ITab index [" + 
currentTab + "]");
                }
 
                addOrReplace(component);
+       }
 
-               return this;
+       private WebMarkupContainer newPanel()
+       {
+               return new WebMarkupContainer(TAB_PANEL_ID);
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/0f9349b6/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanelTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanelTest.java
 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanelTest.java
index a220375..ab660bf 100644
--- 
a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanelTest.java
+++ 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/tabs/TabbedPanelTest.java
@@ -32,15 +32,22 @@ import org.junit.Test;
  */
 public class TabbedPanelTest extends WicketTestCase
 {
+       /**
+        */
        public class TestPage extends WebPage
        {
-               public TabbedPanel<ITab> tabbedPanel;
+               private static final long serialVersionUID = 1L;
 
+               protected TabbedPanel<ITab> tabbedPanel;
+
+               /**
+                */
                public TestPage()
                {
                        List<ITab> defaultTabs = new ArrayList<ITab>();
                        defaultTabs.add(new AbstractTab(Model.of("default 1"))
                        {
+                               private static final long serialVersionUID = 1L;
 
                                @Override
                                public WebMarkupContainer getPanel(String 
panelId)
@@ -50,6 +57,7 @@ public class TabbedPanelTest extends WicketTestCase
                        });
                        defaultTabs.add(new AbstractTab(Model.of("default 2"))
                        {
+                               private static final long serialVersionUID = 1L;
 
                                @Override
                                public WebMarkupContainer getPanel(String 
panelId)
@@ -68,8 +76,16 @@ public class TabbedPanelTest extends WicketTestCase
                return new TabbedPanel<ITab>("tabpanel", defaultTabs);
        }
 
+       /**
+        */
        public static class TestPanel extends Panel
        {
+               private static final long serialVersionUID = 1L;
+
+               /**
+                * @param id
+                * @param panelTestId
+                */
                public TestPanel(String id, String panelTestId)
                {
                        super(id);
@@ -77,6 +93,11 @@ public class TabbedPanelTest extends WicketTestCase
                }
        }
 
+       /**
+        * No tabs thus no tab component rendered.
+        * 
+        * @throws Exception
+        */
        @Test
        public void renderNoTabs() throws Exception
        {
@@ -84,15 +105,20 @@ public class TabbedPanelTest extends WicketTestCase
                page.tabbedPanel.getTabs().clear();
                tester.startPage(page);
 
-               tester.assertContainsNot("<span wicket:id=\"title\">default 
1</span></a>");
+               tester.assertContainsNot("<span wicket:id=\"title\">default 
1</span>");
                tester.assertContainsNot("<span wicket:id=\"label\">default 
1</span>");
-               tester.assertContainsNot("<span wicket:id=\"title\">default 
2</span></a>");
+               tester.assertContainsNot("<span wicket:id=\"title\">default 
2</span>");
                tester.assertContainsNot("<span wicket:id=\"label\">default 
2</span>");
                tester.assertContains("<!-- no panel -->");
 
-               assertEquals(Integer.valueOf(0), 
page.tabbedPanel.getDefaultModelObject());
+               assertEquals(Integer.valueOf(-1), 
page.tabbedPanel.getDefaultModelObject());
        }
 
+       /**
+        * Switching between tabsS.
+        * 
+        * @throws Exception
+        */
        @Test
        public void renderDefaultTabsOnly() throws Exception
        {
@@ -109,12 +135,19 @@ public class TabbedPanelTest extends WicketTestCase
                assertEquals(Integer.valueOf(1), 
page.tabbedPanel.getDefaultModelObject());
        }
 
+       /**
+        * Additional tabs are rendered.
+        * 
+        * @throws Exception
+        */
        @Test
        public void renderAdditionalTabs() throws Exception
        {
                TestPage page = tester.startPage(new TestPage());
                page.tabbedPanel.getTabs().add(new AbstractTab(Model.of("added 
1"))
                {
+                       private static final long serialVersionUID = 1L;
+
                        @Override
                        public WebMarkupContainer getPanel(String panelId)
                        {
@@ -122,23 +155,167 @@ public class TabbedPanelTest extends WicketTestCase
                        }
                });
                // the additional tab isn't rendered yet
-               tester.assertContainsNot("<span wicket:id=\"title\">added 
1</span></a>");
+               tester.assertContainsNot("<span wicket:id=\"title\">added 
1</span>");
                tester.assertContainsNot("<span wicket:id=\"label\">added 
1</span>");
 
                assertEquals(Integer.valueOf(0), 
page.tabbedPanel.getDefaultModelObject());
 
                // now its title is visible, but the contents not
                tester.clickLink("tabpanel:tabs-container:tabs:1:link");
-               tester.assertContains("<span wicket:id=\"title\">added 
1</span></a>");
+               tester.assertContains("<span wicket:id=\"title\">added 
1</span>");
                tester.assertContainsNot("<span wicket:id=\"label\">added 
1</span>");
 
                assertEquals(Integer.valueOf(1), 
page.tabbedPanel.getDefaultModelObject());
 
                // now the entire panel should be there
                tester.clickLink("tabpanel:tabs-container:tabs:2:link");
-               tester.assertContains("<span wicket:id=\"title\">added 
1</span></a>");
+               tester.assertContains("<span wicket:id=\"title\">added 
1</span>");
                tester.assertContains("<span wicket:id=\"label\">added 
1</span>");
 
                assertEquals(Integer.valueOf(2), 
page.tabbedPanel.getDefaultModelObject());
        }
-}
+
+       /**
+        * Changing model switches tab.
+        * 
+        * @throws Exception
+        */
+       @Test
+       public void renderModelChange() throws Exception
+       {
+               TestPage page = new TestPage();
+
+               tester.startPage(page);
+               tester.assertContains("<span wicket:id=\"label\">default 
1</span>");
+
+               page.tabbedPanel.setDefaultModelObject(Integer.valueOf(1));
+               tester.startPage(page);
+
+               tester.assertContains("<span wicket:id=\"label\">default 
2</span>");
+       }
+
+       /**
+        * Tab's component is aquired once only.
+        * 
+        * @throws Exception
+        */
+       @Test
+       public void tabComponentAquiredOnChangeOnly() throws Exception
+       {
+
+               final int[] count = new int[1];
+
+               TestPage page = new TestPage();
+               page.tabbedPanel.getTabs().clear();
+               page.tabbedPanel.getTabs().add(new AbstractTab(Model.of("added 
1"))
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       public WebMarkupContainer getPanel(String panelId)
+                       {
+                               count[0]++;
+
+                               return new TestPanel(panelId, "added 1");
+                       }
+               });
+
+               assertEquals(0, count[0]);
+               tester.startPage(page);
+               assertEquals(1, count[0]);
+               tester.startPage(page);
+               assertEquals(1, count[0]);
+
+               page.tabbedPanel.setSelectedTab(0);
+
+               assertEquals(2, count[0]);
+               tester.startPage(page);
+               assertEquals(2, count[0]);
+       }
+
+       /**
+        * An invisible tab gets replaced by another one.
+        * 
+        * @throws Exception
+        */
+       @Test
+       public void invisibleTabGetsReplaced() throws Exception
+       {
+               final boolean[] visible = { true, true };
+
+               TestPage page = new TestPage();
+               page.tabbedPanel.getTabs().clear();
+               page.tabbedPanel.getTabs().add(new AbstractTab(Model.of("added 
1"))
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       public WebMarkupContainer getPanel(String panelId)
+                       {
+                               return new TestPanel(panelId, "added 1");
+                       }
+
+                       @Override
+                       public boolean isVisible()
+                       {
+                               return visible[0];
+                       }
+               });
+               page.tabbedPanel.getTabs().add(new AbstractTab(Model.of("added 
2"))
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       public WebMarkupContainer getPanel(String panelId)
+                       {
+                               return new TestPanel(panelId, "added 2");
+                       }
+
+                       @Override
+                       public boolean isVisible()
+                       {
+                               return visible[1];
+                       }
+               });
+
+               page.tabbedPanel.setSelectedTab(1);
+
+               tester.startPage(page);
+
+               assertEquals(Integer.valueOf(1), 
page.tabbedPanel.getDefaultModelObject());
+               tester.assertContains("<span wicket:id=\"title\">added 
1</span>");
+               tester.assertContains("<span wicket:id=\"title\">added 
2</span>");
+               tester.assertContains("<span wicket:id=\"label\">added 
2</span>");
+
+               visible[1] = false;
+
+               tester.startPage(page);
+
+               // now first tab is selected
+               assertEquals(Integer.valueOf(0), 
page.tabbedPanel.getDefaultModelObject());
+
+               tester.assertContains("<span wicket:id=\"title\">added 
1</span>");
+               tester.assertContainsNot("<span wicket:id=\"title\">added 
2</span>");
+               tester.assertContains("<span wicket:id=\"label\">added 
1</span>");
+
+               visible[0] = false;
+
+               tester.startPage(page);
+
+               // first tab stays selected since no other is visible
+               assertEquals(Integer.valueOf(0), 
page.tabbedPanel.getDefaultModelObject());
+               tester.assertContainsNot("<span wicket:id=\"title\">added 
1</span>");
+               tester.assertContainsNot("<span wicket:id=\"title\">added 
2</span>");
+               tester.assertContains("<!-- no panel -->");
+
+               visible[1] = true;
+
+               tester.startPage(page);
+
+               // second selected again
+               assertEquals(Integer.valueOf(1), 
page.tabbedPanel.getDefaultModelObject());
+               tester.assertContainsNot("<span wicket:id=\"title\">added 
1</span>");
+               tester.assertContains("<span wicket:id=\"title\">added 
2</span>");
+               tester.assertContains("<span wicket:id=\"label\">added 
2</span>");
+       }
+}
\ No newline at end of file

Reply via email to