You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jd...@apache.org on 2009/12/30 23:34:47 UTC

svn commit: r894726 - in /wicket/trunk: wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/ wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ wicket-extensions/s...

Author: jdonnerstag
Date: Wed Dec 30 22:34:46 2009
New Revision: 894726

URL: http://svn.apache.org/viewvc?rev=894726&view=rev
Log:
fixed and added test case: DataTable generates two <thead wicket:id="topToolbars">
Issue: WICKET-2620

Added:
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/Contact.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactGenerator.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactsDatabase.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.html
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage_ExpectedResult.html
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTableTest.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DatabaseLocator.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DetachableContactModel.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/RepeaterApplication.java
    wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/SortableContactDataProvider.java
Modified:
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackDefaultDataTable.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackHeadersToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxNavigationToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/AbstractToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.html
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DefaultDataTable.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/HeadersToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigationToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigatorLabel.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NoRecordsToolbar.java
    wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/FilterToolbar.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/util/lang/PropertyResolver.java

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackDefaultDataTable.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackDefaultDataTable.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackDefaultDataTable.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackDefaultDataTable.java Wed Dec 30 22:34:46 2009
@@ -89,9 +89,9 @@
 		super(id, columns, dataProvider, rowsPerPage);
 		setOutputMarkupId(true);
 		setVersioned(false);
-		addTopToolbar(new AjaxNavigationToolbar(this));
-		addTopToolbar(new AjaxFallbackHeadersToolbar(this, dataProvider));
-		addBottomToolbar(new NoRecordsToolbar(this));
+		addTopToolbar(new AjaxNavigationToolbar("navigationToolbar", this));
+		addTopToolbar(new AjaxFallbackHeadersToolbar("headerToolbar", this, dataProvider));
+		addBottomToolbar(new NoRecordsToolbar("noRecordsToolbar", this));
 	}
 
 	@Override

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackHeadersToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackHeadersToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackHeadersToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxFallbackHeadersToolbar.java Wed Dec 30 22:34:46 2009
@@ -43,9 +43,10 @@
 	 * @param table
 	 * @param stateLocator
 	 */
-	public AjaxFallbackHeadersToolbar(DataTable<?> table, ISortStateLocator stateLocator)
+	public AjaxFallbackHeadersToolbar(final String id, DataTable<?> table,
+		ISortStateLocator stateLocator)
 	{
-		super(table, stateLocator);
+		super(id, table, stateLocator);
 		table.setOutputMarkupId(true);
 	}
 

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxNavigationToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxNavigationToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxNavigationToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/repeater/data/table/AjaxNavigationToolbar.java Wed Dec 30 22:34:46 2009
@@ -41,12 +41,11 @@
 	 * @param table
 	 *            data table this toolbar will be attached to
 	 */
-	public AjaxNavigationToolbar(final DataTable<?> table)
+	public AjaxNavigationToolbar(final String id, final DataTable<?> table)
 	{
-		super(table);
+		super(id, table);
 	}
 
-
 	/**
 	 * Factory method used to create the paging navigator that will be used by the datatable.
 	 * 

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/AbstractToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/AbstractToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/AbstractToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/AbstractToolbar.java Wed Dec 30 22:34:46 2009
@@ -41,9 +41,9 @@
 	 * @param table
 	 *            data table this toolbar will be attached to
 	 */
-	public AbstractToolbar(IModel<?> model, DataTable<?> table)
+	public AbstractToolbar(String id, IModel<?> model, DataTable<?> table)
 	{
-		super(DataTable.TOOLBAR_COMPONENT_ID, model);
+		super(id, model);
 		this.table = table;
 	}
 
@@ -53,9 +53,9 @@
 	 * @param table
 	 *            data table this toolbar will be attached to
 	 */
-	public AbstractToolbar(DataTable<?> table)
+	public AbstractToolbar(String id, DataTable<?> table)
 	{
-		super(DataTable.TOOLBAR_COMPONENT_ID);
+		super(id);
 		this.table = table;
 	}
 

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.html?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.html (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.html Wed Dec 30 22:34:46 2009
@@ -17,11 +17,11 @@
 -->
 <wicket:panel>
 
-<thead wicket:id="topToolbars">
-	<wicket:container wicket:id="toolbar"></wicket:container>
+<thead>
+	<wicket:container wicket:id="topToolbars"></wicket:container>
 </thead>
-<tfoot wicket:id="bottomToolbars">
-	<wicket:container wicket:id="toolbar"></wicket:container>
+<tfoot>
+	<wicket:container wicket:id="bottomToolbars"></wicket:container>
 </tfoot>
 <tbody wicket:id="body">
 	<tr wicket:id="rows">

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java Wed Dec 30 22:34:46 2009
@@ -22,6 +22,7 @@
 import org.apache.wicket.behavior.SimpleAttributeModifier;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.DataGridView;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.IMarkupFragment;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.list.AbstractItem;
 import org.apache.wicket.markup.html.navigation.paging.IPageable;
@@ -104,11 +105,6 @@
 		}
 	}
 
-	/**
-	 * The component id that toolbars must be created with in order to be added to the data table
-	 */
-	public static final String TOOLBAR_COMPONENT_ID = "toolbar";
-
 	private static final long serialVersionUID = 1L;
 
 	private final DataGridView<T> datagrid;
@@ -325,16 +321,7 @@
 			throw new IllegalArgumentException("argument [toolbar] cannot be null");
 		}
 
-		if (!toolbar.getId().equals(TOOLBAR_COMPONENT_ID))
-		{
-			throw new IllegalArgumentException(
-				"Toolbar must have component id equal to AbstractDataTable.TOOLBAR_COMPONENT_ID");
-		}
-
-		// create a container item for the toolbar (required by repeating view)
-		WebMarkupContainer item = new ToolbarContainer(container.newChildId());
-		item.add(toolbar);
-		container.add(item);
+		container.add(toolbar);
 	}
 
 	/**
@@ -400,14 +387,15 @@
 	}
 
 	/**
-	 * Acts as a container item for a single toolbar.
+	 * Acts as a repeater item with its container generated id. It essentially only forwards the
+	 * request to its (single) child component.
 	 * 
 	 * TODO 1.5 optimization: this can probably be removed and items can be added directly to the
 	 * toolbarcontainer
 	 * 
 	 * @author igor.vaynberg
 	 */
-	private final class ToolbarContainer extends AbstractItem
+	private static final class ToolbarContainer extends AbstractItem
 	{
 		private static final long serialVersionUID = 1L;
 
@@ -427,6 +415,21 @@
 		{
 			return ((Component)iterator().next()).isVisible();
 		}
+
+		@Override
+		protected void onRender()
+		{
+			get(0).render();
+		}
+
+		/**
+		 * @see org.apache.wicket.MarkupContainer#getMarkup(org.apache.wicket.Component)
+		 */
+		@Override
+		public IMarkupFragment getMarkup(Component child)
+		{
+			return getMarkup();
+		}
 	}
 
 	/**
@@ -434,7 +437,7 @@
 	 * 
 	 * @author igor.vaynberg
 	 */
-	private class ToolbarsContainer extends RepeatingView
+	private static class ToolbarsContainer extends RepeatingView
 	{
 		private static final long serialVersionUID = 1L;
 
@@ -447,8 +450,5 @@
 		{
 			super(id);
 		}
-
-
 	}
-
 }

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DefaultDataTable.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DefaultDataTable.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DefaultDataTable.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DefaultDataTable.java Wed Dec 30 22:34:46 2009
@@ -79,9 +79,9 @@
 	{
 		super(id, columns, dataProvider, rowsPerPage);
 
-		addTopToolbar(new NavigationToolbar(this));
-		addTopToolbar(new HeadersToolbar(this, dataProvider));
-		addBottomToolbar(new NoRecordsToolbar(this));
+		addTopToolbar(new NavigationToolbar("navigationToolbar", this));
+		addTopToolbar(new HeadersToolbar("headersToolbar", this, dataProvider));
+		addBottomToolbar(new NoRecordsToolbar("noRecordsToolbar", this));
 	}
 
 	@Override

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/HeadersToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/HeadersToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/HeadersToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/HeadersToolbar.java Wed Dec 30 22:34:46 2009
@@ -44,9 +44,10 @@
 	 * @param stateLocator
 	 *            locator for the ISortState implementation used by sortable headers
 	 */
-	public HeadersToolbar(final DataTable<?> table, final ISortStateLocator stateLocator)
+	public HeadersToolbar(final String id, final DataTable<?> table,
+		final ISortStateLocator stateLocator)
 	{
-		super(table);
+		super(id, table);
 
 		RepeatingView headers = new RepeatingView("headers");
 		add(headers);

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigationToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigationToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigationToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigationToolbar.java Wed Dec 30 22:34:46 2009
@@ -40,9 +40,9 @@
 	 * @param table
 	 *            data table this toolbar will be attached to
 	 */
-	public NavigationToolbar(final DataTable<?> table)
+	public NavigationToolbar(final String id, final DataTable<?> table)
 	{
-		super(table);
+		super(id, table);
 		this.table = table;
 
 		WebMarkupContainer span = new WebMarkupContainer("span");

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigatorLabel.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigatorLabel.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigatorLabel.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NavigatorLabel.java Wed Dec 30 22:34:46 2009
@@ -200,5 +200,17 @@
 			}
 			return (table.getCurrentPage() * table.getRowsPerPage()) + 1;
 		}
+
+		/**
+		 * @return "y" in "Showing x to y of z"
+		 */
+		public int getTo()
+		{
+			if (getOf() == 0)
+			{
+				return 0;
+			}
+			return Math.min(getOf(), getFrom() + table.getRowsPerPage() - 1);
+		}
 	}
 }

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NoRecordsToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NoRecordsToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NoRecordsToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/NoRecordsToolbar.java Wed Dec 30 22:34:46 2009
@@ -47,9 +47,9 @@
 	 * @param table
 	 *            data table this toolbar will be attached to
 	 */
-	public NoRecordsToolbar(final DataTable<?> table)
+	public NoRecordsToolbar(final String id, final DataTable<?> table)
 	{
-		this(table, DEFAULT_MESSAGE_MODEL);
+		this(id, table, DEFAULT_MESSAGE_MODEL);
 	}
 
 	/**
@@ -58,9 +58,9 @@
 	 * @param messageModel
 	 *            model that will be used to display the "no records found" message
 	 */
-	public NoRecordsToolbar(final DataTable<?> table, IModel<String> messageModel)
+	public NoRecordsToolbar(final String id, final DataTable<?> table, IModel<String> messageModel)
 	{
-		super(table);
+		super(id, table);
 		WebMarkupContainer td = new WebMarkupContainer("td");
 		add(td);
 

Modified: wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/FilterToolbar.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/FilterToolbar.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/FilterToolbar.java (original)
+++ wicket/trunk/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/filter/FilterToolbar.java Wed Dec 30 22:34:46 2009
@@ -34,7 +34,6 @@
 public class FilterToolbar extends AbstractToolbar
 {
 	private static final long serialVersionUID = 1L;
-	private static final String FILTER_COMPONENT_ID = "filter";
 
 	/**
 	 * Constructor
@@ -46,10 +45,10 @@
 	 * @param stateLocator
 	 *            locator responsible for finding object used to store filter's state
 	 */
-	public FilterToolbar(final DataTable<?> table, final FilterForm form,
+	public FilterToolbar(String id, final DataTable<?> table, final FilterForm form,
 		final IFilterStateLocator stateLocator)
 	{
-		super(table);
+		super(id, table);
 
 		if (table == null)
 		{
@@ -78,22 +77,22 @@
 			if (col instanceof IFilteredColumn)
 			{
 				IFilteredColumn<?> filteredCol = (IFilteredColumn<?>)col;
-				filter = filteredCol.getFilter(FILTER_COMPONENT_ID, form);
+				filter = filteredCol.getFilter(id, form);
 			}
 
 			if (filter == null)
 			{
-				filter = new NoFilter(FILTER_COMPONENT_ID);
+				filter = new NoFilter(id);
 			}
 			else
 			{
-				if (!filter.getId().equals(FILTER_COMPONENT_ID))
+				if (!filter.getId().equals(id))
 				{
 					throw new IllegalStateException(
 						"filter component returned  with an invalid component id. invalid component id [" +
 							filter.getId() +
 							"] required component id [" +
-							FILTER_COMPONENT_ID +
+							id +
 							"] generating column [" + col.toString() + "] ");
 				}
 			}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/Contact.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/Contact.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/Contact.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/Contact.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.IClusterable;
+
+/**
+ * domain object for demonstrations.
+ * 
+ * @author igor
+ */
+public class Contact implements IClusterable
+{
+	private static final long serialVersionUID = 1L;
+
+	private long id;
+
+	private String firstName;
+
+	private String lastName;
+
+	private String homePhone;
+
+	private String cellPhone;
+
+	/**
+	 * Constructor
+	 */
+	public Contact()
+	{
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString()
+	{
+		return "[Contact id=" + id + " firstName=" + firstName + " lastName=" + lastName +
+			" homePhone=" + homePhone + " cellPhone=" + cellPhone + "]";
+	}
+
+	/**
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (obj == this)
+		{
+			return true;
+		}
+		if (obj == null)
+		{
+			return false;
+		}
+		if (obj instanceof Contact)
+		{
+			Contact other = (Contact)obj;
+			return other.getFirstName().equals(getFirstName()) &&
+				other.getLastName().equals(getLastName()) &&
+				other.getHomePhone().equals(getHomePhone()) &&
+				other.getCellPhone().equals(getCellPhone());
+
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * @param id
+	 */
+	public void setId(long id)
+	{
+		this.id = id;
+	}
+
+	/**
+	 * @return id
+	 */
+	public long getId()
+	{
+		return id;
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param firstName
+	 * @param lastName
+	 */
+	public Contact(String firstName, String lastName)
+	{
+		this.firstName = firstName;
+		this.lastName = lastName;
+	}
+
+	/**
+	 * @return cellPhone
+	 */
+	public String getCellPhone()
+	{
+		return cellPhone;
+	}
+
+	/**
+	 * @param cellPhone
+	 */
+	public void setCellPhone(String cellPhone)
+	{
+		this.cellPhone = cellPhone;
+	}
+
+	/**
+	 * @return firstName
+	 */
+	public String getFirstName()
+	{
+		return firstName;
+	}
+
+	/**
+	 * @param firstName
+	 */
+	public void setFirstName(String firstName)
+	{
+		this.firstName = firstName;
+	}
+
+	/**
+	 * @return homePhone
+	 */
+	public String getHomePhone()
+	{
+		return homePhone;
+	}
+
+	/**
+	 * @param homePhone
+	 */
+	public void setHomePhone(String homePhone)
+	{
+		this.homePhone = homePhone;
+	}
+
+	/**
+	 * @return lastName
+	 */
+	public String getLastName()
+	{
+		return lastName;
+	}
+
+	/**
+	 * @param lastName
+	 */
+	public void setLastName(String lastName)
+	{
+		this.lastName = lastName;
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactGenerator.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactGenerator.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactGenerator.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactGenerator.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.Collection;
+
+/**
+ * generates random contacts
+ * 
+ * @author igor
+ * 
+ */
+public class ContactGenerator
+{
+	private static ContactGenerator instance = new ContactGenerator();
+	private static long nextId = 1;
+
+	/**
+	 * @return static instance of generator
+	 */
+	public static ContactGenerator getInstance()
+	{
+		return instance;
+	}
+
+	private final String[] firstNames = { "Jacob", "Emily", "Michael", "Sarah", "Matthew",
+			"Brianna", "Nicholas", "Samantha", "Christopher", "Hailey", "Abner", "Abby", "Joshua",
+			"Douglas", "Jack", "Keith", "Gerald", "Samuel", "Willie", "Larry", "Jose", "Timothy",
+			"Sandra", "Kathleen", "Pamela", "Virginia", "Debra", "Maria", "Linda" };
+	private final String[] lastNames = { "Smiith", "Johnson", "Williams", "Jones", "Brown",
+			"Donahue", "Bailey", "Rose", "Allen", "Black", "Davis", "Clark", "Hall", "Lee",
+			"Baker", "Gonzalez", "Nelson", "Moore", "Wilson", "Graham", "Fisher", "Cruz", "Ortiz",
+			"Gomez", "Murray" };
+
+	private ContactGenerator()
+	{
+
+	}
+
+	/**
+	 * @return unique id
+	 */
+	public synchronized long generateId()
+	{
+		return nextId++;
+	}
+
+	/**
+	 * generates a new contact
+	 * 
+	 * @return generated contact
+	 */
+	public Contact generate()
+	{
+		Contact contact = new Contact(randomString(firstNames), randomString(lastNames));
+		contact.setId(generateId());
+		contact.setHomePhone(generatePhoneNumber());
+		contact.setCellPhone(generatePhoneNumber());
+		return contact;
+	}
+
+	/**
+	 * generats <code>count</code> number contacts and puts them into <code>collection</code>
+	 * collection
+	 * 
+	 * @param collection
+	 * @param count
+	 */
+	public void generate(Collection<Contact> collection, int count)
+	{
+		for (int i = 0; i < count; i++)
+		{
+			collection.add(generate());
+		}
+	}
+
+	private String generatePhoneNumber()
+	{
+		return new StringBuffer().append(rint(2, 9))
+			.append(rint(0, 9))
+			.append(rint(0, 9))
+			.append("-555-")
+			.append(rint(1, 9))
+			.append(rint(0, 9))
+			.append(rint(0, 9))
+			.append(rint(0, 9))
+			.toString();
+	}
+
+	private int rint(int min, int max)
+	{
+		return (int)(Math.random() * (max - min) + min);
+	}
+
+	private String randomString(String[] choices)
+	{
+		return choices[rint(0, choices.length)];
+	}
+
+
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactsDatabase.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactsDatabase.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactsDatabase.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/ContactsDatabase.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * simple database for contacts
+ * 
+ * @author igor
+ * 
+ */
+public class ContactsDatabase
+{
+	private final Map<Long, Contact> map = Collections.synchronizedMap(new HashMap<Long, Contact>());
+	private final List<Contact> fnameIdx = Collections.synchronizedList(new ArrayList<Contact>());
+	private final List<Contact> lnameIdx = Collections.synchronizedList(new ArrayList<Contact>());
+	private final List<Contact> fnameDescIdx = Collections.synchronizedList(new ArrayList<Contact>());
+	private final List<Contact> lnameDescIdx = Collections.synchronizedList(new ArrayList<Contact>());
+
+	/**
+	 * Constructor
+	 * 
+	 * @param count
+	 *            number of contacts to generate at startup
+	 */
+	public ContactsDatabase(int count)
+	{
+		for (int i = 0; i < count; i++)
+		{
+			add(ContactGenerator.getInstance().generate());
+		}
+		updateIndecies();
+	}
+
+	/**
+	 * find contact by id
+	 * 
+	 * @param id
+	 * @return contact
+	 */
+	public Contact get(long id)
+	{
+		Contact c = map.get(id);
+		if (c == null)
+		{
+			throw new RuntimeException("contact with id [" + id + "] not found in the database");
+		}
+		return c;
+	}
+
+	protected void add(final Contact contact)
+	{
+		map.put(contact.getId(), contact);
+		fnameIdx.add(contact);
+		lnameIdx.add(contact);
+		fnameDescIdx.add(contact);
+		lnameDescIdx.add(contact);
+	}
+
+	/**
+	 * select contacts and apply sort
+	 * 
+	 * @param first
+	 * @param count
+	 * @param sortProperty
+	 * @param sortAsc
+	 * @return list of contacts
+	 */
+	public List<Contact> find(int first, int count, String sortProperty, boolean sortAsc)
+	{
+		List<Contact> sublist = getIndex(sortProperty, sortAsc).subList(first, first + count);
+		return sublist;
+	}
+
+	protected List<Contact> getIndex(String prop, boolean asc)
+	{
+		if (prop == null)
+		{
+			return fnameIdx;
+		}
+		if (prop.equals("firstName"))
+		{
+			return (asc) ? fnameIdx : fnameDescIdx;
+		}
+		else if (prop.equals("lastName"))
+		{
+			return (asc) ? lnameIdx : lnameDescIdx;
+		}
+		throw new RuntimeException("uknown sort option [" + prop +
+			"]. valid options: [firstName] , [lastName]");
+	}
+
+	/**
+	 * @return number of contacts in the database
+	 */
+	public int getCount()
+	{
+		return fnameIdx.size();
+	}
+
+	/**
+	 * add contact to the database
+	 * 
+	 * @param contact
+	 */
+	public void save(final Contact contact)
+	{
+		if (contact.getId() == 0)
+		{
+			contact.setId(ContactGenerator.getInstance().generateId());
+			add(contact);
+			updateIndecies();
+		}
+		else
+		{
+			throw new IllegalArgumentException("contact [" + contact.getFirstName() +
+				"] is already persistent");
+		}
+	}
+
+	/**
+	 * delete contact from the database
+	 * 
+	 * @param contact
+	 */
+	public void delete(final Contact contact)
+	{
+		Contact c = map.remove(contact.getId());
+
+		fnameIdx.remove(contact);
+		lnameIdx.remove(contact);
+		fnameDescIdx.remove(contact);
+		lnameDescIdx.remove(contact);
+
+		contact.setId(0);
+	}
+
+	private void updateIndecies()
+	{
+		Collections.sort(fnameIdx, new Comparator<Contact>()
+		{
+			public int compare(Contact arg0, Contact arg1)
+			{
+				return (arg0).getFirstName().compareTo((arg1).getFirstName());
+			}
+		});
+
+		Collections.sort(lnameIdx, new Comparator<Contact>()
+		{
+			public int compare(Contact arg0, Contact arg1)
+			{
+				return (arg0).getLastName().compareTo((arg1).getLastName());
+			}
+		});
+
+		Collections.sort(fnameDescIdx, new Comparator<Contact>()
+		{
+			public int compare(Contact arg0, Contact arg1)
+			{
+				return (arg1).getFirstName().compareTo((arg0).getFirstName());
+			}
+		});
+
+		Collections.sort(lnameDescIdx, new Comparator<Contact>()
+		{
+			public int compare(Contact arg0, Contact arg1)
+			{
+				return (arg1).getLastName().compareTo((arg0).getLastName());
+			}
+		});
+
+	}
+
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.html?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.html (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.html Wed Dec 30 22:34:46 2009
@@ -0,0 +1,5 @@
+<html xmlns:wicket>
+<body>
+  <table class="dataview" cellspacing="0" wicket:id="table">[table]</table>
+</body>
+</html>

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+
+/**
+ * demo page for the datatable component
+ * 
+ * @see org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable
+ * @author igor
+ * 
+ */
+public class DataTablePage extends WebPage
+{
+	/**
+	 * constructor
+	 */
+	public DataTablePage()
+	{
+		List<IColumn<?>> columns = new ArrayList<IColumn<?>>();
+
+		columns.add(new AbstractColumn<Contact>(new Model<String>("Actions"))
+		{
+			private static final long serialVersionUID = 1L;
+
+			public void populateItem(Item<ICellPopulator<Contact>> cellItem, String componentId,
+				IModel<Contact> rowModel)
+			{
+				cellItem.add(new WebMarkupContainer(componentId, rowModel));
+			}
+		});
+
+		columns.add(new PropertyColumn<String>(new Model<String>("ID"), "id")
+		{
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public String getCssClass()
+			{
+				return "numeric";
+			}
+		});
+
+		columns.add(new PropertyColumn<String>(new Model<String>("First Name"), "firstName",
+			"firstName"));
+
+		columns.add(new PropertyColumn<String>(new Model<String>("Last Name"), "lastName",
+			"lastName")
+		{
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public String getCssClass()
+			{
+				return "last-name";
+			}
+		});
+
+		columns.add(new PropertyColumn<String>(new Model<String>("Home Phone"), "homePhone"));
+		columns.add(new PropertyColumn<String>(new Model<String>("Cell Phone"), "cellPhone"));
+
+		add(new DefaultDataTable("table", columns, new SortableContactDataProvider(), 8));
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage_ExpectedResult.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage_ExpectedResult.html?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage_ExpectedResult.html (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTablePage_ExpectedResult.html Wed Dec 30 22:34:46 2009
@@ -0,0 +1,75 @@
+<html xmlns:wicket>
+<body>
+  <table class="dataview" cellspacing="0" wicket:id="table"><wicket:panel>
+<thead>
+	<wicket:container wicket:id="topToolbars"><wicket:panel>
+	<tr class="navigation">
+		<td wicket:id="span" colspan="6">
+			<x/>
+			<x/></td><x/></tr><x/></wicket:panel></wicket:container><wicket:container wicket:id="topToolbars"><wicket:panel>
+	<tr class="headers">
+			<th wicket:id="header"><x/></th>
+			<th wicket:id="header" class="numeric"><x/></th>
+			<th wicket:id="header" class="wicket_orderUp"><wicket:border><x/></wicket:border></th>
+			<th wicket:id="header" class="wicket_orderNone last-name"><wicket:border><x/></wicket:border></th>
+			<th wicket:id="header"><x/></th>
+			<th wicket:id="header"><x/></th><x/></tr><x/></wicket:panel></wicket:container><x/></thead>
+<tfoot><x/></tfoot>
+<tbody wicket:id="body">
+	<tr wicket:id="rows" class="even">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="odd">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="even">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="odd">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="even">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="odd">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="even">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><tr wicket:id="rows" class="odd">
+		<td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="numeric">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells" class="last-name">
+			<x/></td><td wicket:id="cells">
+			<x/></td><td wicket:id="cells">
+			<x/></td><x/></tr><x/></tbody><x/></wicket:panel></table><x/></body><x/></html>

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTableTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTableTest.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTableTest.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTableTest.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import junit.framework.TestCase;
+
+import org.apache.wicket.util.diff.DiffUtil;
+import org.apache.wicket.util.tester.WicketTester;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ */
+public class DataTableTest extends TestCase
+{
+	/** Log for reporting. */
+	private static final Logger log = LoggerFactory.getLogger(DataTableTest.class);
+
+	/**
+	 * @throws Exception
+	 */
+	public void test_1() throws Exception
+	{
+		WicketTester tester = new WicketTester(new RepeaterApplication());
+		tester.startPage(DataTablePage.class);
+		tester.assertRenderedPage(DataTablePage.class);
+
+		String document = tester.getServletResponse().getDocument();
+		int index = document.indexOf("<thead");
+		assertTrue("Expected at least on <thead>", index != -1);
+		index = document.indexOf("<thead", index + 1);
+		assertTrue("There must be only one <thead>", index == -1);
+
+		index = document.indexOf("<tbody");
+		assertTrue("Expected at least on <tbody>", index != -1);
+		index = document.indexOf("<tbody", index + 1);
+		assertTrue("There must be only one <tbody>", index == -1);
+
+		log.error(document);
+		log.error("==============================================");
+		log.error("==============================================");
+		log.error(removeFillers(document));
+
+		String doc = removeFillers(document);
+		DiffUtil.validatePage(doc, getClass(), "DataTablePage_ExpectedResult.html", true);
+	}
+
+	private String removeFillers(String doc)
+	{
+		doc = doc.replaceAll("(?s)<span .*?>.*?</span>", "<x/>");
+		doc = doc.replaceAll("(?s)<div .*?>.*?</div>", "<x/>");
+		doc = doc.replaceAll("(?s)<a .*?>.*?</a>", "<x/>");
+		doc = doc.replaceAll("(?s)>\\s*?[\\n\\r]+\\s*?</", "><x/></");
+		doc = doc.replaceAll("(?s)[\\n\\r]+\\s*?([\\n\\r]+)", "\r\n");
+		doc = doc.replaceAll("(<x/>)+", "<x/>");
+
+		return doc;
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DatabaseLocator.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DatabaseLocator.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DatabaseLocator.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DatabaseLocator.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.RequestCycle;
+
+/**
+ * service locator class for contacts database
+ * 
+ * @author igor
+ * 
+ */
+public class DatabaseLocator
+{
+	/**
+	 * @return contacts database
+	 */
+	public static ContactsDatabase getDatabase()
+	{
+		RepeaterApplication app = (RepeaterApplication)RequestCycle.get().getApplication();
+		return app.getContactsDB();
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DetachableContactModel.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DetachableContactModel.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DetachableContactModel.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DetachableContactModel.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.model.LoadableDetachableModel;
+
+/**
+ * detachable model for an instance of contact
+ * 
+ * @author igor
+ * 
+ */
+public class DetachableContactModel extends LoadableDetachableModel<Contact>
+{
+	private static final long serialVersionUID = 1L;
+
+	private final long id;
+
+	protected ContactsDatabase getContactsDB()
+	{
+		return DatabaseLocator.getDatabase();
+	}
+
+	/**
+	 * @param c
+	 */
+	public DetachableContactModel(Contact c)
+	{
+		this(c.getId());
+	}
+
+	/**
+	 * @param id
+	 */
+	public DetachableContactModel(long id)
+	{
+		if (id == 0)
+		{
+			throw new IllegalArgumentException();
+		}
+		this.id = id;
+	}
+
+	/**
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode()
+	{
+		return Long.valueOf(id).hashCode();
+	}
+
+	/**
+	 * used for dataview with ReuseIfModelsEqualStrategy item reuse strategy
+	 * 
+	 * @see org.apache.wicket.markup.repeater.ReuseIfModelsEqualStrategy
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(final Object obj)
+	{
+		if (obj == this)
+		{
+			return true;
+		}
+		else if (obj == null)
+		{
+			return false;
+		}
+		else if (obj instanceof DetachableContactModel)
+		{
+			DetachableContactModel other = (DetachableContactModel)obj;
+			return other.id == id;
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.apache.wicket.model.LoadableDetachableModel#load()
+	 */
+	@Override
+	protected Contact load()
+	{
+		// loads contact from the database
+		return getContactsDB().get(id);
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/RepeaterApplication.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/RepeaterApplication.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/RepeaterApplication.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/RepeaterApplication.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.markup.html.ServerAndClientTimeFilter;
+import org.apache.wicket.protocol.http.WebApplication;
+
+/**
+ * application class for repeater examples application
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ * 
+ */
+public class RepeaterApplication extends WebApplication
+{
+	private final ContactsDatabase contactsDB = new ContactsDatabase(50);
+
+	/**
+	 * Constructor.
+	 */
+	public RepeaterApplication()
+	{
+	}
+
+	/**
+	 * @see org.apache.wicket.protocol.http.WebApplication#init()
+	 */
+	@Override
+	protected void init()
+	{
+		getDebugSettings().setDevelopmentUtilitiesEnabled(true);
+		getRequestCycleSettings().addResponseFilter(new ServerAndClientTimeFilter());
+	}
+
+	/**
+	 * @return contacts database
+	 */
+	public ContactsDatabase getContactsDB()
+	{
+		return contactsDB;
+	}
+
+	/**
+	 * @see org.apache.wicket.Application#getHomePage()
+	 */
+	@Override
+	public Class<? extends Page> getHomePage()
+	{
+		return DataTablePage.class;
+	}
+}

Added: wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/SortableContactDataProvider.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/SortableContactDataProvider.java?rev=894726&view=auto
==============================================================================
--- wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/SortableContactDataProvider.java (added)
+++ wicket/trunk/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/repeater/data/table/SortableContactDataProvider.java Wed Dec 30 22:34:46 2009
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.Iterator;
+
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.IModel;
+
+
+/**
+ * implementation of IDataProvider for contacts that keeps track of sort information
+ * 
+ * @author igor
+ * 
+ */
+public class SortableContactDataProvider extends SortableDataProvider<Contact>
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * constructor
+	 */
+	public SortableContactDataProvider()
+	{
+		// set default sort
+		setSort("firstName", true);
+	}
+
+	protected ContactsDatabase getContactsDB()
+	{
+		return DatabaseLocator.getDatabase();
+	}
+
+	/**
+	 * @see org.apache.wicket.markup.repeater.data.IDataProvider#iterator(int, int)
+	 */
+	public Iterator<Contact> iterator(int first, int count)
+	{
+		SortParam sp = getSort();
+		return getContactsDB().find(first, count, sp.getProperty(), sp.isAscending()).iterator();
+	}
+
+	/**
+	 * @see org.apache.wicket.markup.repeater.data.IDataProvider#size()
+	 */
+	public int size()
+	{
+		return getContactsDB().getCount();
+	}
+
+	/**
+	 * @see org.apache.wicket.markup.repeater.data.IDataProvider#model(java.lang.Object)
+	 */
+	public IModel<Contact> model(Contact object)
+	{
+		return new DetachableContactModel(object);
+	}
+
+}

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/util/lang/PropertyResolver.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/lang/PropertyResolver.java?rev=894726&r1=894725&r2=894726&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/util/lang/PropertyResolver.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/util/lang/PropertyResolver.java Wed Dec 30 22:34:46 2009
@@ -439,9 +439,7 @@
 							else
 							{
 								// We do not look for a public FIELD because
-								// that is
-								// not good
-								// programming with beans patterns
+								// that is not good programming with beans patterns
 								throw new WicketRuntimeException(
 									"No get method defined for class: " + clz + " expression: " +
 										exp);