You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/09/03 14:32:31 UTC

[40/87] [abbrv] [partial] isis git commit: ISIS-1194: moving the wicket submodules to be direct children of core; removing the isis-viewer-wicket parent pom.

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanelFactory.java
new file mode 100644
index 0000000..e922ac9
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanelFactory.java
@@ -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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+/**
+ * {@link ComponentFactory} for {@link CollectionContentsAsAjaxTablePanel}.
+ */
+public class CollectionContentsAsAjaxTablePanelFactory extends ComponentFactoryAbstract implements CollectionContentsAsFactory {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String NAME = "table";
+
+    public CollectionContentsAsAjaxTablePanelFactory() {
+        super(ComponentType.COLLECTION_CONTENTS, NAME, CollectionContentsAsAjaxTablePanel.class);
+    }
+
+    @Override
+    public ApplicationAdvice appliesTo(final IModel<?> model) {
+        return appliesIf(model instanceof EntityCollectionModel);
+    }
+
+    @Override
+    public Component createComponent(final String id, final IModel<?> model) {
+        final EntityCollectionModel collectionModel = (EntityCollectionModel) model;
+        return new CollectionContentsAsAjaxTablePanel(id, collectionModel);
+    }
+
+    @Override
+    public IModel<String> getTitleLabel() {
+        return new ResourceModel("CollectionContentsAsAjaxTablePanelFactory.Table", "Table");
+    }
+
+    @Override
+    public IModel<String> getCssClass() {
+        return Model.of("fa fa-fw fa-table");
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
new file mode 100644
index 0000000..8b9641c
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsSortableDataProvider.java
@@ -0,0 +1,202 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import java.util.Iterator;
+import java.util.List;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+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;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
+import org.apache.isis.core.metamodel.consent.InteractionResult;
+import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
+import org.apache.isis.core.metamodel.interactions.InteractionUtils;
+import org.apache.isis.core.metamodel.interactions.ObjectVisibilityContext;
+import org.apache.isis.core.metamodel.interactions.VisibilityContext;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.ObjectSpecificationException;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+
+/**
+ * Part of the {@link AjaxFallbackDefaultDataTable} API.
+ */
+public class CollectionContentsSortableDataProvider extends SortableDataProvider<ObjectAdapter,String> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final EntityCollectionModel model;
+
+    public CollectionContentsSortableDataProvider(final EntityCollectionModel model) {
+        this.model = model;
+    }
+
+    @Override
+    public IModel<ObjectAdapter> model(final ObjectAdapter adapter) {
+        return new EntityModel(adapter);
+    }
+
+    @Override
+    public long size() {
+        return model.getObject().size();
+    }
+
+    @Override
+    public void detach() {
+        super.detach();
+        model.detach();
+    }
+
+    @Override
+    public Iterator<ObjectAdapter> iterator(final long first, final long count) {
+
+        final List<ObjectAdapter> adapters = model.getObject();
+
+        final Iterable<ObjectAdapter> visibleAdapters =
+                Iterables.filter(adapters, ignoreHidden());
+
+        // need to create a list from the iterable, then back to an iterable
+        // because guava's Ordering class doesn't support sorting of iterable -> iterable
+        final List<ObjectAdapter> sortedVisibleAdapters = sortedCopy(visibleAdapters, getSort());
+        final List<ObjectAdapter> pagedAdapters = subList(first, count, sortedVisibleAdapters);
+        return pagedAdapters.iterator();
+    }
+
+    private static List<ObjectAdapter> subList(
+            final long first,
+            final long count,
+            final List<ObjectAdapter> objectAdapters) {
+
+        final int fromIndex = (int) first;
+        // if adapters where filter out (as invisible), then make sure don't run off the end
+        final int toIndex = Math.min((int) (first + count), objectAdapters.size());
+
+        return objectAdapters.subList(fromIndex, toIndex);
+    }
+
+    private List<ObjectAdapter> sortedCopy(
+            final Iterable<ObjectAdapter> adapters,
+            final SortParam<String> sort) {
+
+        final ObjectAssociation sortProperty = lookupAssociationFor(sort);
+        if(sortProperty == null) {
+            return Lists.newArrayList(adapters);
+        }
+
+        final Ordering<ObjectAdapter> ordering =
+                orderingBy(sortProperty, sort.isAscending());
+        return ordering.sortedCopy(adapters);
+    }
+
+    private ObjectAssociation lookupAssociationFor(final SortParam<String> sort) {
+
+        if(sort == null) {
+            return null;
+        }
+
+        final ObjectSpecification elementSpec = model.getTypeOfSpecification();
+        final String sortPropertyId = sort.getProperty();
+
+        try {
+            // might be null, or throw ex
+            return elementSpec.getAssociation(sortPropertyId);
+        } catch(ObjectSpecificationException ex) {
+            // eg invalid propertyId
+            return null;
+        }
+    }
+
+    private Predicate<ObjectAdapter> ignoreHidden() {
+        return new Predicate<ObjectAdapter>() {
+            @Override
+            public boolean apply(ObjectAdapter input) {
+                final InteractionResult visibleResult = InteractionUtils.isVisibleResult(input.getSpecification(), createVisibleInteractionContext(input));
+                return visibleResult.isNotVetoing();
+            }
+        };
+    }
+
+    private VisibilityContext<?> createVisibleInteractionContext(final ObjectAdapter objectAdapter) {
+        return new ObjectVisibilityContext(
+                getDeploymentCategory(),
+                getAuthenticationSession(),
+                InteractionInvocationMethod.BY_USER,
+                objectAdapter,
+                objectAdapter.getSpecification().getIdentifier(),
+                Where.ALL_TABLES);
+    }
+
+    private static Ordering<ObjectAdapter> orderingBy(final ObjectAssociation sortProperty, final boolean ascending) {
+        final Ordering<ObjectAdapter> ordering = new Ordering<ObjectAdapter>(){
+    
+            @Override
+            public int compare(final ObjectAdapter p, final ObjectAdapter q) {
+                final ObjectAdapter pSort = sortProperty.get(p);
+                final ObjectAdapter qSort = sortProperty.get(q);
+                Ordering<ObjectAdapter> naturalOrdering = 
+                        ascending 
+                            ? ORDERING_BY_NATURAL.nullsFirst() 
+                            : ORDERING_BY_NATURAL.nullsLast();
+                return naturalOrdering.compare(pSort, qSort);
+            }
+        };
+        return ascending?ordering:ordering.reverse();
+    }
+
+    private static Ordering<ObjectAdapter> ORDERING_BY_NATURAL = new Ordering<ObjectAdapter>(){
+        @Override
+        public int compare(final ObjectAdapter p, final ObjectAdapter q) {
+            final Object pPojo = p.getObject();
+            final Object qPojo = q.getObject();
+            if(!(pPojo instanceof Comparable) || !(qPojo instanceof Comparable)) {
+                return 0;
+            } 
+            return naturalOrdering(pPojo, qPojo);
+        }
+        @SuppressWarnings("rawtypes")
+        private int naturalOrdering(final Object pPojo, final Object qPojo) {
+            Comparable pComparable = (Comparable) pPojo;
+            Comparable qComparable = (Comparable) qPojo;
+            return Ordering.natural().compare(pComparable, qComparable);
+        }
+    };
+
+    // //////////////////////////////////////
+
+    protected AuthenticationSession getAuthenticationSession() {
+        return IsisContext.getAuthenticationSession();
+    }
+
+    protected DeploymentCategory getDeploymentCategory() {
+        return IsisContext.getDeploymentType().getDeploymentCategory();
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
new file mode 100644
index 0000000..57580bd
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
@@ -0,0 +1,213 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.NoRecordsToolbar;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.repeater.IItemFactory;
+import org.apache.wicket.markup.repeater.IItemReuseStrategy;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.OddEvenItem;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.util.lang.Generics;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.wicket.model.hints.IsisUiHintEvent;
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+import org.apache.isis.viewer.wicket.model.hints.UiHintPathSignificant;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+public class IsisAjaxFallbackDataTable<T, S> extends DataTable<T, S> implements UiHintPathSignificant {
+    
+    private static final long serialVersionUID = 1L;
+    
+    static final String UIHINT_PAGE_NUMBER = "pageNumber";
+
+    private final ISortableDataProvider<T, S> dataProvider;
+
+    private IsisAjaxFallbackHeadersToolbar<S> headersToolbar;
+
+    public IsisAjaxFallbackDataTable(final String id, final List<? extends IColumn<T, S>> columns,
+        final ISortableDataProvider<T, S> dataProvider, final int rowsPerPage)
+    {
+        super(id, columns, dataProvider, rowsPerPage);
+        this.dataProvider = dataProvider;
+        setOutputMarkupId(true);
+        setVersioned(false);
+        setItemReuseStrategy(new PreserveModelReuseStrategy());
+    }
+
+    @Override
+    protected void onInitialize() {
+        super.onInitialize();
+        buildGui();
+    }
+    
+    private void buildGui() {
+        headersToolbar = new IsisAjaxFallbackHeadersToolbar<>(this, this.dataProvider);
+        addTopToolbar(headersToolbar);
+        addBottomToolbar(new IsisAjaxNavigationToolbar(this));
+        addBottomToolbar(new NoRecordsToolbar(this));
+    }
+    
+    @Override
+    protected Item<T> newRowItem(final String id, final int index, final IModel<T> model)
+    {
+        return new OddEvenItem<T>(id, index, model) {
+            @Override
+            protected void onComponentTag(ComponentTag tag) {
+                super.onComponentTag(tag);
+
+                if (model instanceof EntityModel) {
+                    EntityModel entityModel = (EntityModel) model;
+                    final ObjectAdapter objectAdapter = entityModel.getObject();
+                    final ObjectSpecification typeOfSpecification = entityModel.getTypeOfSpecification();
+                    String cssClass = typeOfSpecification.getCssClass(objectAdapter);
+                    CssClassAppender.appendCssClassTo(tag, cssClass);
+                }
+            }
+        };
+    }
+
+    static class PreserveModelReuseStrategy implements IItemReuseStrategy {
+        private static final long serialVersionUID = 1L;
+
+        private static IItemReuseStrategy instance = new PreserveModelReuseStrategy();
+
+        /**
+         * @return static instance
+         */
+        public static IItemReuseStrategy getInstance()
+        {
+            return instance;
+        }
+
+        /**
+         * @see org.apache.wicket.markup.repeater.IItemReuseStrategy#getItems(org.apache.wicket.markup.repeater.IItemFactory,
+         *      java.util.Iterator, java.util.Iterator)
+         */
+        @Override
+        public <T> Iterator<Item<T>> getItems(final IItemFactory<T> factory,
+            final Iterator<IModel<T>> newModels, Iterator<Item<T>> existingItems)
+        {
+            final Map<IModel<T>, Item<T>> modelToItem = Generics.newHashMap();
+            while (existingItems.hasNext())
+            {
+                final Item<T> item = existingItems.next();
+                modelToItem.put(item.getModel(), item);
+            }
+
+            return new Iterator<Item<T>>()
+            {
+                private int index = 0;
+
+                @Override
+                public boolean hasNext()
+                {
+                    return newModels.hasNext();
+                }
+
+                @Override
+                public Item<T> next()
+                {
+                    final IModel<T> model = newModels.next();
+                    final Item<T> oldItem = modelToItem.get(model);
+
+                    final IModel<T> model2 = oldItem != null ? oldItem.getModel() : model;
+                    return factory.newItem(index++, model2);
+                }
+
+                @Override
+                public void remove()
+                {
+                    throw new UnsupportedOperationException();
+                }
+
+            };
+        }
+
+    }
+
+    public void honourHints() {
+        UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        }
+        
+        headersToolbar.honourSortOrderHints();
+        
+        honourPageNumberHint(uiHintContainer);
+    }
+
+    private void honourPageNumberHint(final UiHintContainer uiHintContainer) {
+        final String pageNumberStr = uiHintContainer.getHint(this, UIHINT_PAGE_NUMBER);
+        if(pageNumberStr != null) {
+            try {
+                long pageNumber = Long.parseLong(pageNumberStr);
+                if(pageNumber >= 0) {
+                    // dataTable is clever enough to deal with too-large numbers
+                    this.setCurrentPage(pageNumber);
+                }
+            } catch(Exception ex) {
+                // ignore.
+            }
+        }
+        uiHintContainer.setHint(this, UIHINT_PAGE_NUMBER, ""+getCurrentPage());
+        // don't broadcast (no AjaxRequestTarget, still configuring initial setup)
+    }
+
+    public void setPageNumberHintAndBroadcast(AjaxRequestTarget target) {
+        final UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        } 
+        uiHintContainer.setHint(this, IsisAjaxFallbackDataTable.UIHINT_PAGE_NUMBER, ""+getCurrentPage());
+        send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
+    }
+
+    public void setSortOrderHintAndBroadcast(SortOrder order, String property, AjaxRequestTarget target) {
+        final UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        }
+
+        // first clear all SortOrder hints...
+        for (SortOrder eachSortOrder : SortOrder.values()) {
+            uiHintContainer.clearHint(this, eachSortOrder.name());
+        }
+        // .. then set this one
+        uiHintContainer.setHint(this, order.name(), property);
+        send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
+    }
+
+    private EntityModel getUiHintContainer() {
+        return UiHintContainer.Util.hintContainerOf(this, EntityModel.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
new file mode 100644
index 0000000..19c914d
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
@@ -0,0 +1,90 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import org.apache.wicket.ajax.attributes.IAjaxCallListener;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackHeadersToolbar;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+
+
+/**
+ * Adapted from Wicket's own {@link AjaxFallbackHeadersToolbar}.
+ */
+public class IsisAjaxFallbackHeadersToolbar<S> extends IsisAjaxHeadersToolbar<S>
+{
+    private static final long serialVersionUID = 1L;
+    private final ISortStateLocator<S> stateLocator;
+    private IsisAjaxFallbackDataTable<?, S> table;
+
+    public IsisAjaxFallbackHeadersToolbar(final IsisAjaxFallbackDataTable<?, S> table, final ISortStateLocator<S> stateLocator)
+    {
+        super(table, stateLocator);
+        this.table = table;
+        table.setOutputMarkupId(true);
+        this.stateLocator = stateLocator;
+    }
+    
+    @Override
+    protected void onInitialize() {
+        super.onInitialize();
+    }
+
+    // //////////////////////////////////////
+
+    @Override
+    protected WebMarkupContainer newSortableHeader(final String borderId, final S property,
+        final ISortStateLocator<S> locator)
+    {
+        return new IsisAjaxFallbackOrderByBorder<S>(borderId, table, property, locator, getAjaxCallListener());
+    }
+
+    /**
+     * Returns a decorator that will be used to decorate ajax links used in sortable headers
+     * 
+     * @return decorator or null for none
+     */
+    protected IAjaxCallListener getAjaxCallListener()
+    {
+        return null;
+    }
+    
+    // //////////////////////////////////////
+
+    void honourSortOrderHints() {
+        final UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        } 
+        for (SortOrder sortOrder : SortOrder.values()) {
+            String property = uiHintContainer.getHint(table, sortOrder.name());
+            if(property != null) {
+                // bit hacky... how know this cast is safe?
+                S propertyS = (S) property;
+                stateLocator.getSortState().setPropertySortOrder(propertyS, sortOrder);
+            }
+        }
+    }
+
+    private EntityModel getUiHintContainer() {
+        return UiHintContainer.Util.hintContainerOf(this, EntityModel.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
new file mode 100644
index 0000000..dedcfdd
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
@@ -0,0 +1,73 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.IAjaxCallListener;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.sort.AjaxFallbackOrderByBorder;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByLink;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+
+public class IsisAjaxFallbackOrderByBorder<T> extends AjaxFallbackOrderByBorder<T> {
+
+    private static final long serialVersionUID = 1L;
+    
+    private final T sortProperty;
+    private final IsisAjaxFallbackDataTable<?, ?> dataTable;
+
+    private final ISortStateLocator<T> stateLocator;
+    
+    public IsisAjaxFallbackOrderByBorder(String id, IsisAjaxFallbackDataTable<?, ?> dataTable, T sortProperty, ISortStateLocator<T> stateLocator, IAjaxCallListener ajaxCallListener) {
+        super(id, sortProperty, stateLocator, new OrderByLink.VoidCssProvider<T>(), ajaxCallListener);
+        this.dataTable = dataTable;
+        this.stateLocator = stateLocator;
+        this.sortProperty = sortProperty;
+    }
+
+    @Override
+    protected void onAjaxClick(final AjaxRequestTarget target)
+    {
+        target.add(dataTable);
+
+        final UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        }
+        
+        final ISortState<T> state = stateLocator.getSortState();
+        final SortOrder order = state.getPropertySortOrder(sortProperty);
+        
+        dataTable.setSortOrderHintAndBroadcast(order, sortProperty.toString(), target);
+        dataTable.setPageNumberHintAndBroadcast(target);
+    }
+
+    @Override
+    protected void onSortChanged()
+    {
+        super.onSortChanged();
+        // UI hint & event broadcast in onAjaxClick
+        dataTable.setCurrentPage(0); 
+    }
+    
+    public UiHintContainer getUiHintContainer() {
+        return UiHintContainer.Util.hintContainerOf(dataTable);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
new file mode 100644
index 0000000..5f8ddf4
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+   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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <tr class="headers">
+        <wicket:container wicket:id="headers">
+            <th wicket:id="header">
+                <div>
+                    <strong wicket:id="label">[header-label]</strong> <span wicket:id="sortIcon" style="float: right"></span>
+                </div>
+            </th>
+        </wicket:container>
+    </tr>
+</wicket:panel>

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
new file mode 100644
index 0000000..5a4544c
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
@@ -0,0 +1,214 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import de.agilecoders.wicket.core.util.Attributes;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.*;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebComponent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.RefreshingView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.string.Strings;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterTitleColumn;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+
+/**
+ * Adapted from Wicket's own {@link HeadersToolbar}.
+ */
+public class IsisAjaxHeadersToolbar<S> extends AbstractToolbar
+{
+    private static final long serialVersionUID = 1L;
+
+    private static final String CLASS_SORT_NONE = "fa fa-fw fa-sort";
+    private static final String CLASS_SORT_UP = "fa fa-fw fa-sort-up";
+    private static final String CLASS_SORT_DOWN = "fa fa-fw fa-sort-down";
+
+    static abstract class CssAttributeBehavior extends Behavior
+    {
+        private static final long serialVersionUID = 1L;
+
+        protected abstract String getCssClass();
+
+        /**
+         * @see Behavior#onComponentTag(Component, ComponentTag)
+         */
+        @Override
+        public void onComponentTag(final Component component, final ComponentTag tag)
+        {
+            String className = getCssClass();
+            if (!Strings.isEmpty(className))
+            {
+                tag.append("class", className, " ");
+            }
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param <T>
+     *            the column data type
+     * @param table
+     *            data table this toolbar will be attached to
+     * @param stateLocator
+     *            locator for the ISortState implementation used by sortable headers
+     */
+    public <T> IsisAjaxHeadersToolbar(final DataTable<T, S> table, final ISortStateLocator<S> stateLocator)
+    {
+        super(table);
+
+        RefreshingView<IColumn<T, S>> headers = new RefreshingView<IColumn<T, S>>("headers")
+        {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected Iterator<IModel<IColumn<T, S>>> getItemModels()
+            {
+                List<IModel<IColumn<T, S>>> columnsModels = new LinkedList<IModel<IColumn<T, S>>>();
+
+                for (IColumn<T, S> column : table.getColumns())
+                {
+                    columnsModels.add(Model.of(column));
+                }
+
+                return columnsModels.iterator();
+            }
+
+            @Override
+            protected void populateItem(Item<IColumn<T, S>> item)
+            {
+                final IColumn<T, S> column = item.getModelObject();
+
+                WebMarkupContainer header;
+
+                if (column.isSortable())
+                {
+                    header = newSortableHeader("header", column.getSortProperty(), stateLocator);
+
+                    if (column instanceof IStyledColumn)
+                    {
+                        CssAttributeBehavior cssAttributeBehavior = new CssAttributeBehavior()
+                        {
+                            private static final long serialVersionUID = 1L;
+
+                            @Override
+                            protected String getCssClass()
+                            {
+                                return ((IStyledColumn<?, S>)column).getCssClass();
+                            }
+                        };
+
+                        header.add(cssAttributeBehavior);
+                    }
+
+                }
+                else
+                {
+                    header = new WebMarkupContainer("header");
+                }
+
+
+                item.add(header);
+                item.setRenderBodyOnly(true);
+                Component label = column.getHeader("label");
+                Component sortIcon = newSortIcon("sortIcon", column, stateLocator);
+                header.add(label, sortIcon);
+
+                if(column instanceof ObjectAdapterTitleColumn) {
+                    header.add(new CssClassAppender("title-column"));
+                }
+            }
+        };
+        add(headers);
+    }
+
+    /**
+     * Factory method for the sort icon
+     *
+     * @param id
+     *          the component id
+     * @param column
+     *          the column for which a sort icon is needed
+     * @param stateLocator
+     *          locator for the ISortState implementation used by sortable headers
+     * @param <T>
+     *          The model object type of the data table
+     * @return A component that should be used as a sort icon
+     */
+    protected <T> Component newSortIcon(String id, final IColumn<T, S> column, final ISortStateLocator<S> stateLocator) {
+        return new WebComponent(id) {
+            @Override
+            protected void onComponentTag(ComponentTag tag) {
+                super.onComponentTag(tag);
+
+                if(column.isSortable()) {
+                    ISortState<S> sortState = stateLocator.getSortState();
+                    S sortProperty = column.getSortProperty();
+                    SortOrder sortOrder = sortProperty == null ? SortOrder.NONE : sortState.getPropertySortOrder(sortProperty);
+                    if (sortOrder == SortOrder.ASCENDING) {
+                        Attributes.addClass(tag, CLASS_SORT_UP);
+                    } else if (sortOrder == SortOrder.DESCENDING) {
+                        Attributes.addClass(tag, CLASS_SORT_DOWN);
+                    } else {
+                        Attributes.addClass(tag, CLASS_SORT_NONE);
+                    }
+                }
+            }
+        };
+    }
+
+    /**
+     * Factory method for sortable header components. A sortable header component must have id of
+     * <code>headerId</code> and conform to markup specified in <code>HeadersToolbar.html</code>
+     * 
+     * @param headerId
+     *            header component id
+     * @param property
+     *            property this header represents
+     * @param locator
+     *            sort state locator
+     * @return created header component
+     */
+    protected WebMarkupContainer newSortableHeader(final String headerId, final S property,
+        final ISortStateLocator<S> locator)
+    {
+        return new OrderByBorder<S>(headerId, property, locator)
+        {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onSortChanged()
+            {
+                getTable().setCurrentPage(0);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.html
new file mode 100644
index 0000000..604d8de
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+   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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <tr class="navigation">
+        <td wicket:id="span">
+            <div class="navigatorLabel">
+                <span wicket:id="navigatorLabel">[navigator-label]</span>
+                <button wicket:id="showAll" type="button" class="btn btn-xs btn-link">Show all</button>
+            </div>
+            <div class="navigator"><div wicket:id="navigator">[navigator]</div></div>
+        </td>
+    </tr>
+</wicket:panel>

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
new file mode 100644
index 0000000..f28b5e0
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
@@ -0,0 +1,55 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxNavigationToolbar;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
+import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
+
+
+public class IsisAjaxNavigationToolbar extends AjaxNavigationToolbar {
+
+    private static final long serialVersionUID = 1L;
+
+    public IsisAjaxNavigationToolbar(final DataTable<?, ?> table) {
+        super(table);
+
+        addShowAllButton(table);
+    }
+
+    private void addShowAllButton(final DataTable<?, ?> table) {
+        table.setOutputMarkupId(true);
+
+        ((MarkupContainer)get("span")).add(new AjaxLink("showAll") {
+
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                table.setItemsPerPage(Long.MAX_VALUE);
+                target.add(table);
+            }
+        });
+    }
+
+    @Override
+    protected PagingNavigator newPagingNavigator(String navigatorId, DataTable<?, ?> table) {
+        return new IsisAjaxPagingNavigator(navigatorId, table);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigation.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigation.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigation.java
new file mode 100644
index 0000000..aa173e6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigation.java
@@ -0,0 +1,54 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigation;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.list.LoopItem;
+import org.apache.wicket.markup.html.navigation.paging.IPageable;
+import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider;
+
+
+public class IsisAjaxPagingNavigation extends AjaxPagingNavigation {
+
+    private static final long serialVersionUID = 1L;
+
+    /** Attribute for active state */
+    private final AttributeModifier activeAttribute = AttributeModifier.append("class", "active");
+
+    public IsisAjaxPagingNavigation(String id, IPageable pageable, IPagingLabelProvider labelProvider) {
+        super(id, pageable, labelProvider);
+    }
+
+    public IsisAjaxPagingNavigation(String id, IPageable pageable) {
+        super(id, pageable);
+    }
+    
+    @Override
+    protected Link<?> newPagingNavigationLink(String id, IPageable pageable, long pageIndex) {
+        return new IsisAjaxPagingNavigationLink(id, pageable, pageIndex);
+    }
+
+    @Override
+    protected void populateItem(final LoopItem loopItem) {
+        super.populateItem(loopItem);
+        if ((getStartIndex() + loopItem.getIndex()) == pageable.getCurrentPage()) {
+            loopItem.add(activeAttribute);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationIncrementLink.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationIncrementLink.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationIncrementLink.java
new file mode 100644
index 0000000..9d56205
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationIncrementLink.java
@@ -0,0 +1,56 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.navigation.ajax.BootstrapAjaxPagingNavigationBehavior;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigationBehavior;
+import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigationIncrementLink;
+import org.apache.wicket.markup.html.navigation.paging.IPageable;
+
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+
+public class IsisAjaxPagingNavigationIncrementLink extends AjaxPagingNavigationIncrementLink {
+
+    private static final long serialVersionUID = 1L;
+    
+    private final IsisAjaxFallbackDataTable<?, ?> dataTable;
+    private final Component component;
+
+    public IsisAjaxPagingNavigationIncrementLink(String id, IPageable pageable, int increment) {
+        super(id, pageable, increment);
+        dataTable = (IsisAjaxFallbackDataTable<?, ?>) pageable;
+        component = pageable instanceof Component ? (Component) pageable : null;
+    }
+
+    @Override
+    public void onClick(AjaxRequestTarget target) {
+        super.onClick(target);
+        dataTable.setPageNumberHintAndBroadcast(target);
+    }
+
+    @Override
+    protected AjaxPagingNavigationBehavior newAjaxPagingNavigationBehavior(IPageable pageable, String event) {
+        return new BootstrapAjaxPagingNavigationBehavior(this, pageable, event);
+    }
+
+    public UiHintContainer getUiHintContainer() {
+        return UiHintContainer.Util.hintContainerOf(component);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationLink.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationLink.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationLink.java
new file mode 100644
index 0000000..8ec643b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigationLink.java
@@ -0,0 +1,56 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.navigation.ajax.BootstrapAjaxPagingNavigationBehavior;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigationBehavior;
+import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigationLink;
+import org.apache.wicket.markup.html.navigation.paging.IPageable;
+
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+
+public class IsisAjaxPagingNavigationLink extends AjaxPagingNavigationLink {
+
+    private static final long serialVersionUID = 1L;
+    private final IsisAjaxFallbackDataTable<?, ?> dataTable;
+    private final Component component;
+
+    public IsisAjaxPagingNavigationLink(String id, IPageable pageable, long pageNumber) {
+        super(id, pageable, pageNumber);
+        dataTable = (IsisAjaxFallbackDataTable<?, ?>) pageable;
+        component = pageable instanceof Component ? (Component) pageable : null;
+    }
+
+    @Override
+    public void onClick(AjaxRequestTarget target) {
+        super.onClick(target);
+        dataTable.setPageNumberHintAndBroadcast(target);
+    }
+
+    @Override
+    protected AjaxPagingNavigationBehavior newAjaxPagingNavigationBehavior(IPageable pageable, String event) {
+        return new BootstrapAjaxPagingNavigationBehavior(this, pageable, event);
+    }
+
+    public UiHintContainer getUiHintContainer() {
+        return UiHintContainer.Util.hintContainerOf(component);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigator.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigator.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigator.java
new file mode 100644
index 0000000..f9ede18
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxPagingNavigator.java
@@ -0,0 +1,63 @@
+/**
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.navigation.ajax.BootstrapAjaxPagingNavigator;
+
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.navigation.paging.IPageable;
+import org.apache.wicket.markup.html.navigation.paging.IPagingLabelProvider;
+import org.apache.wicket.markup.html.navigation.paging.PagingNavigation;
+
+
+public class IsisAjaxPagingNavigator extends BootstrapAjaxPagingNavigator {
+
+    private static final long serialVersionUID = 1L;
+
+    public IsisAjaxPagingNavigator(String id, IPageable pageable) {
+        this(id, pageable, null);
+    }
+
+    public IsisAjaxPagingNavigator(String id, IPageable pageable, IPagingLabelProvider labelProvider) {
+        super(id, pageable, labelProvider);
+
+        setSize(Size.Small);
+    }
+
+    @Override
+    protected AbstractLink newPagingNavigationLink(String id, IPageable pageable, int pageNumber) {
+        return new IsisAjaxPagingNavigationLink(id, pageable, pageNumber);
+    }
+
+    @Override
+    protected AbstractLink newPagingNavigationIncrementLink(String id, IPageable pageable, int increment) {
+        return new IsisAjaxPagingNavigationIncrementLink(id, pageable, increment);
+    }
+    
+    @Override
+    protected PagingNavigation newNavigation(String id, IPageable pageable, IPagingLabelProvider labelProvider) {
+        return new IsisAjaxPagingNavigation(id, pageable, labelProvider);
+    }
+
+    @Override
+    protected void onComponentTag(ComponentTag tag) {
+        tag.setName("ul");
+
+        super.onComponentTag(tag);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ColumnAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ColumnAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ColumnAbstract.java
new file mode 100644
index 0000000..c6d9dbe
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ColumnAbstract.java
@@ -0,0 +1,62 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
+import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanel;
+
+/**
+ * Represents a {@link AbstractColumn} within a
+ * {@link AjaxFallbackDefaultDataTable}.
+ * 
+ * <p>
+ * Part of the implementation of {@link CollectionContentsAsAjaxTablePanel}.
+ */
+public abstract class ColumnAbstract<T> extends AbstractColumn<T,String> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ColumnAbstract(final String columnName) {
+        this(Model.of(columnName), null);
+    }
+
+    public ColumnAbstract(final IModel<String> columnNameModel, final String sortColumn) {
+        super(columnNameModel, sortColumn);
+    }
+
+    protected ComponentFactory findComponentFactory(final ComponentType componentType, final IModel<?> model) {
+        return getComponentRegistry().findComponentFactory(componentType, model);
+    }
+
+    protected ComponentFactoryRegistry getComponentRegistry() {
+        final ComponentFactoryRegistryAccessor cfra = (ComponentFactoryRegistryAccessor) Application.get();
+        return cfra.getComponentFactoryRegistry();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
new file mode 100644
index 0000000..eb07ad6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
@@ -0,0 +1,96 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.viewer.wicket.model.mementos.PropertyMemento;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel.RenderingHint;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanel;
+
+/**
+ * A {@link ColumnAbstract column} within a
+ * {@link CollectionContentsAsAjaxTablePanel} representing a single property of the
+ * provided {@link ObjectAdapter}.
+ * 
+ * <p>
+ * Looks up the {@link ComponentFactory} to render the property from the
+ * {@link ComponentFactoryRegistry}.
+ */
+public final class ObjectAdapterPropertyColumn extends ColumnAbstract<ObjectAdapter> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String propertyExpression;
+    private final boolean escaped;
+
+    public ObjectAdapterPropertyColumn(
+            final IModel<String> columnNameModel,
+            final String sortProperty,
+            final String propertyName,
+            final boolean escaped) {
+        super(columnNameModel, sortProperty);
+        this.propertyExpression = propertyName;
+        this.escaped = escaped;
+    }
+
+    public Component getHeader(final String componentId)
+    {
+        final Label label = new Label(componentId, getDisplayModel());
+        label.setEscapeModelStrings(escaped);
+        return label;
+    }
+
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<ObjectAdapter>> cellItem, final String componentId, final IModel<ObjectAdapter> rowModel) {
+        final Component component = createComponent(componentId, rowModel);
+        cellItem.add(component);
+    }
+
+    private Component createComponent(final String id, final IModel<ObjectAdapter> rowModel) {
+
+        final ObjectAdapter adapter = rowModel.getObject();
+        final EntityModel model = new EntityModel(adapter);
+        final OneToOneAssociation property = (OneToOneAssociation) adapter.getSpecification().getAssociation(propertyExpression);
+        final PropertyMemento pm = new PropertyMemento(property);
+        final ScalarModel scalarModel = model.getPropertyModel(pm);
+
+        scalarModel.setRenderingHint(RenderingHint.PROPERTY_COLUMN);
+        scalarModel.toViewMode();
+
+        final ComponentFactory componentFactory = findComponentFactory(ComponentType.SCALAR_NAME_AND_VALUE, scalarModel);
+        final Component component = componentFactory.createComponent(id, scalarModel);
+        
+        return component;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
new file mode 100644
index 0000000..a152450
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
@@ -0,0 +1,70 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel.RenderingHint;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+public class ObjectAdapterTitleColumn extends ColumnAbstract<ObjectAdapter> {
+
+    private static final long serialVersionUID = 1L;
+    private final ObjectAdapterMemento parentAdapterMementoIfAny;
+
+    private static String columnName(final ObjectAdapterMemento parentAdapterMementoIfAny, final int maxTitleLength) {
+        if(maxTitleLength == 0) {
+            return "";
+        }
+        return (parentAdapterMementoIfAny != null? "Related ":"") + "Object";
+    }
+
+    public ObjectAdapterTitleColumn(final ObjectAdapterMemento parentAdapterMementoIfAny, final int maxTitleLength) {
+        super(columnName(parentAdapterMementoIfAny, maxTitleLength)); // i18n
+        this.parentAdapterMementoIfAny = parentAdapterMementoIfAny;
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<ObjectAdapter>> cellItem, final String componentId, final IModel<ObjectAdapter> rowModel) {
+        final Component component = createComponent(componentId, rowModel);
+        cellItem.add(component);
+        cellItem.add(new CssClassAppender("title-column"));
+    }
+
+    private Component createComponent(final String id, final IModel<ObjectAdapter> rowModel) {
+        final ObjectAdapter adapter = rowModel.getObject();
+        final EntityModel model = new EntityModel(adapter);
+        model.setRenderingHint(parentAdapterMementoIfAny != null? RenderingHint.PARENTED_TITLE_COLUMN: RenderingHint.STANDALONE_TITLE_COLUMN);
+        model.setContextAdapterIfAny(parentAdapterMementoIfAny);
+        // will use EntityLinkSimplePanelFactory as model is an EntityModel
+        final ComponentFactory componentFactory = findComponentFactory(ComponentType.ENTITY_LINK, model);
+        return componentFactory.createComponent(id, model);
+    }
+
+    
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
new file mode 100644
index 0000000..8dde6ff
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
@@ -0,0 +1,145 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
+
+import java.util.List;
+import com.google.common.collect.Lists;
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.viewer.wicket.model.common.OnConcurrencyExceptionHandler;
+import org.apache.isis.viewer.wicket.model.common.OnSelectionHandler;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.widgets.checkbox.ContainedToggleboxPanel;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ObjectAdapter> {
+
+    private static final long serialVersionUID = 1L;
+
+
+    public ObjectAdapterToggleboxColumn() {
+        this(null, null);
+    }
+    
+    public ObjectAdapterToggleboxColumn(
+            final OnSelectionHandler onSelectionHandler,
+            final OnConcurrencyExceptionHandler onConcurrencyExceptionHandler) {
+        super("");
+        this.onSelectionHandler = onSelectionHandler;
+        this.onConcurrencyExceptionHandler = onConcurrencyExceptionHandler;
+    }
+
+    //region > OnSelectionHandler
+    private OnSelectionHandler onSelectionHandler;
+    public OnSelectionHandler getOnSelectionHandler() {
+        return onSelectionHandler;
+    }
+
+    public void setOnSelectionHandler(OnSelectionHandler onSelectionHandler) {
+        this.onSelectionHandler = onSelectionHandler;
+    }
+    //endregion
+
+    //region > OnConcurrencyExceptionHandler
+
+    private OnConcurrencyExceptionHandler onConcurrencyExceptionHandler;
+    public OnConcurrencyExceptionHandler getOnConcurrencyExceptionHandler() {
+        return onConcurrencyExceptionHandler;
+    }
+
+    public void setOnConcurrencyExceptionHandler(OnConcurrencyExceptionHandler onConcurrencyExceptionHandler) {
+        this.onConcurrencyExceptionHandler = onConcurrencyExceptionHandler;
+    }
+    //endregion
+
+
+    @Override
+    public Component getHeader(String componentId) {
+        
+        final ContainedToggleboxPanel toggle = new ContainedToggleboxPanel(componentId) {
+            private static final long serialVersionUID = 1L;
+            @Override
+            public void onSubmit(AjaxRequestTarget target) {
+                for (ContainedToggleboxPanel toggle : rowToggles) {
+                    toggle.toggle(target);
+                    target.add(toggle);
+                }
+            }
+        };
+        toggle.add(new CssClassAppender("title-column"));
+        return toggle;
+    }
+
+    private final List<ContainedToggleboxPanel> rowToggles = Lists.newArrayList(); 
+            
+    @Override
+    public void populateItem(final Item<ICellPopulator<ObjectAdapter>> cellItem, final String componentId, final IModel<ObjectAdapter> rowModel) {
+
+        cellItem.add(new CssClassAppender("togglebox-column"));
+
+        final MarkupContainer row = cellItem.getParent().getParent();
+        row.setOutputMarkupId(true);
+        final EntityModel entityModel = (EntityModel) rowModel;
+        String concurrencyExceptionIfAny = entityModel.getAndClearConcurrencyExceptionIfAny();
+        if(concurrencyExceptionIfAny != null) {
+            row.add(new CssClassAppender("reloaded-after-concurrency-exception"));
+        }
+        
+        final ContainedToggleboxPanel toggle = new ContainedToggleboxPanel(componentId) {
+            private static final long serialVersionUID = 1L;
+            @Override
+            public void onSubmit(AjaxRequestTarget target) {
+                final EntityModel entityModel = (EntityModel) rowModel;
+                ObjectAdapter selectedAdapter = null;
+                try {
+                    selectedAdapter = entityModel.load(ConcurrencyChecking.CHECK);
+                    if(onSelectionHandler != null) {
+                        onSelectionHandler.onSelected(this, selectedAdapter, target);
+                    }
+                } catch(ConcurrencyException ex) {
+
+                    // should work second time, because the previous attempt will have updated the OAM's OIDs version.
+                    selectedAdapter = entityModel.load(ConcurrencyChecking.CHECK);
+                    if(onConcurrencyExceptionHandler != null) {
+                        onConcurrencyExceptionHandler.onConcurrencyException(this, selectedAdapter, ex, target);
+                    }
+                    
+                    entityModel.setException(ex);
+                }
+            }
+        };
+        rowToggles.add(toggle);
+        toggle.setOutputMarkupId(true);
+        cellItem.add(toggle);
+    }
+
+    public void clearToggles() {
+        rowToggles.clear();
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_down.png
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_down.png b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_down.png
new file mode 100644
index 0000000..f31cc81
Binary files /dev/null and b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_down.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_off.png
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_off.png b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_off.png
new file mode 100644
index 0000000..f9b1ced
Binary files /dev/null and b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_off.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_up.png
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_up.png b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_up.png
new file mode 100644
index 0000000..63031c3
Binary files /dev/null and b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/images/arrow_up.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.html
new file mode 100644
index 0000000..afaa78a
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<html xmlns:wicket="http://wicket.apache.org">
+	<body>
+		<wicket:panel>
+			<ul class="collectionContentsAsIconsPanel collectionContentsComponentType">
+				<li wicket:id="entityInstance">[entity instance as icon]</li>
+			</ul>
+		</wicket:panel>
+	</body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.java
new file mode 100644
index 0000000..0c1e75c
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/icons/CollectionContentsAsIconsPanel.java
@@ -0,0 +1,60 @@
+/*
+ *  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.isis.viewer.wicket.ui.components.collectioncontents.icons;
+
+import java.util.List;
+
+import org.apache.wicket.markup.repeater.RepeatingView;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.entity.header.EntityHeaderPanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * {@link PanelAbstract Panel} that represents a {@link EntityCollectionModel
+ * collection of entity}s rendered using a simple list of icons.
+ */
+public class CollectionContentsAsIconsPanel extends PanelAbstract<EntityCollectionModel> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_ENTITY_INSTANCE = "entityInstance";
+
+    public CollectionContentsAsIconsPanel(final String id, final EntityCollectionModel model) {
+        super(id, model);
+        buildGui();
+    }
+
+    private void buildGui() {
+        final EntityCollectionModel model = getModel();
+        final List<ObjectAdapter> adapterList = model.getObject();
+        final RepeatingView entityInstances = new RepeatingView(ID_ENTITY_INSTANCE);
+        add(entityInstances);
+        for (final ObjectAdapter adapter : adapterList) {
+            final String childId = entityInstances.newChildId();
+            final EntityModel entityModel = new EntityModel(adapter);
+            final EntityHeaderPanel entitySummaryPanel = new EntityHeaderPanel(childId, entityModel);
+            entityInstances.add(entitySummaryPanel);
+        }
+    }
+
+}