You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2012/07/16 19:51:01 UTC

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

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 <sv...@apache.org>
Authored: Mon Jul 16 19:50:37 2012 +0200
Committer: svenmeier <sv...@apache.org>
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