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 2013/12/23 15:32:25 UTC

git commit: ISIS-642: added breadcrumb panel

Updated Branches:
  refs/heads/master 2f4941b16 -> c58864e6d


ISIS-642: added breadcrumb panel

In addition:
- moved BookmarkedPagedModelProvider from applicaiton (which has global scope) to session (per user)


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

Branch: refs/heads/master
Commit: c58864e6daf89ea1f77b13fd0260cf27df69d1b3
Parents: 2f4941b
Author: Dan Haywood <da...@apache.org>
Authored: Mon Dec 23 13:56:16 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Mon Dec 23 13:56:16 2013 +0000

----------------------------------------------------------------------
 .../wicket/viewer/IsisWicketApplication.java    |  20 +---
 .../viewer/IsisWicketUnsecuredApplication.java  |   7 +-
 .../wicket/AuthenticatedWebSessionForIsis.java  |  27 ++++-
 .../model/mementos/ObjectAdapterMemento.java    |   1 -
 .../wicket/model/models/BookmarkTreeNode.java   |  30 +++--
 .../ui/components/actions/ActionPanel.java      |   2 +-
 .../widgets/breadcrumbs/BreadcrumbModel.java    | 106 +++++++++++++++++
 .../breadcrumbs/BreadcrumbModelProvider.java    |  23 ++++
 .../widgets/breadcrumbs/BreadcrumbPanel.css     |  23 ++++
 .../widgets/breadcrumbs/BreadcrumbPanel.html    |  29 +++++
 .../widgets/breadcrumbs/BreadcrumbPanel.java    | 116 +++++++++++++++++++
 .../widgets/zclip/ZeroClipboardPanel.java       |   5 +-
 .../viewer/wicket/ui/pages/PageAbstract.css     |  31 +++--
 .../viewer/wicket/ui/pages/PageAbstract.html    |  11 +-
 .../viewer/wicket/ui/pages/PageAbstract.java    |  18 ++-
 .../wicket/ui/pages/entity/EntityPage.java      |  15 ++-
 16 files changed, 392 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index b767159..3a6f6ca 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.viewer.wicket.viewer;
 
-import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -54,10 +53,8 @@ import org.apache.wicket.markup.html.IHeaderResponseDecorator;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.Response;
-import org.apache.wicket.request.resource.ByteArrayResource;
 import org.apache.wicket.request.resource.CssResourceReference;
 import org.apache.wicket.settings.IRequestCycleSettings.RenderStrategy;
-import org.apache.wicket.util.resource.IResourceStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -92,14 +89,12 @@ import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar;
 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.additionallinks.AdditionalLinksPanel;
-import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconAndTitlePanel;
 import org.apache.isis.viewer.wicket.ui.components.entity.properties.EntityPropertiesForm;
 import org.apache.isis.viewer.wicket.ui.components.scalars.string.MultiLineStringPanel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItemPanel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssSubMenuItemsPanel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.zclip.ZeroClipboardLink;
 import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider;
-import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassList;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
@@ -151,7 +146,7 @@ import org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleFo
  * changed.)</li>
  * </ul>
  */
-public class IsisWicketApplication extends AuthenticatedWebApplication implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, AuthenticationSessionProvider, BookmarkedPagesModelProvider {
+public class IsisWicketApplication extends AuthenticatedWebApplication implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, AuthenticationSessionProvider {
 
     private static final long serialVersionUID = 1L;
     
@@ -200,7 +195,6 @@ public class IsisWicketApplication extends AuthenticatedWebApplication implement
     @Inject
     private IsisSystem system;
 
-    private BookmarkedPagesModel bookmarkedPagesModel;
 
     private boolean determiningDeploymentType;
     private DeploymentTypeWicketAbstract deploymentType;
@@ -245,8 +239,6 @@ public class IsisWicketApplication extends AuthenticatedWebApplication implement
             final IsisConfiguration configuration = isisConfigurationBuilder.getConfiguration();
             this.getMarkupSettings().setStripWicketTags(determineStripWicketTags(deploymentType, configuration));
     
-            this.bookmarkedPagesModel = new BookmarkedPagesModel();
-    
             initWicketComponentInjection(injector);
 
             // must be done after injected componentFactoryRegistry into the app itself
@@ -605,16 +597,6 @@ public class IsisWicketApplication extends AuthenticatedWebApplication implement
 
 
     // /////////////////////////////////////////////////
-    // Breadcrumbs support
-    // /////////////////////////////////////////////////
-
-    @Override
-    public BookmarkedPagesModel getBookmarkedPagesModel() {
-        return bookmarkedPagesModel;
-    }
-
-
-    // /////////////////////////////////////////////////
     // *Provider impl.
     // /////////////////////////////////////////////////
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketUnsecuredApplication.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketUnsecuredApplication.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketUnsecuredApplication.java
index 88ed44c..ab27327 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketUnsecuredApplication.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketUnsecuredApplication.java
@@ -75,7 +75,7 @@ import org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjec
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.ConverterForObjectAdapterMemento;
 import org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis;
 
-public class IsisWicketUnsecuredApplication extends WebApplication implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, AuthenticationSessionProvider, BookmarkedPagesModelProvider {
+public class IsisWicketUnsecuredApplication extends WebApplication implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, AuthenticationSessionProvider {
 
     private static final long serialVersionUID = 1L;
 
@@ -314,9 +314,4 @@ public class IsisWicketUnsecuredApplication extends WebApplication implements Co
         }
     }
 
-    @Override
-    public BookmarkedPagesModel getBookmarkedPagesModel() {
-        return bookmarkedPagesModel;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/AuthenticatedWebSessionForIsis.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/AuthenticatedWebSessionForIsis.java b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/AuthenticatedWebSessionForIsis.java
index 6d2c422..2851202 100644
--- a/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/AuthenticatedWebSessionForIsis.java
+++ b/component/viewer/wicket/impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/AuthenticatedWebSessionForIsis.java
@@ -40,6 +40,10 @@ import org.apache.isis.core.runtime.authentication.AuthenticationManager;
 import org.apache.isis.core.runtime.authentication.AuthenticationRequest;
 import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
 import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
+import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModel;
+import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModelProvider;
+import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider;
 
 /**
  * Viewer-specific implementation of {@link AuthenticatedWebSession}, which
@@ -47,7 +51,7 @@ import org.apache.isis.core.runtime.system.context.IsisContext;
  * also tracks threadusage (so that multiple concurrent requests are all
  * associated with the same session).
  */
-public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession implements AuthenticationSessionProvider {
+public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession implements AuthenticationSessionProvider, BreadcrumbModelProvider, BookmarkedPagesModelProvider {
 
     private static final long serialVersionUID = 1L;
 
@@ -57,6 +61,9 @@ public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession impl
         return (AuthenticatedWebSessionForIsis) Session.get();
     }
 
+    private final BookmarkedPagesModel bookmarkedPagesModel = new BookmarkedPagesModel();
+    private final BreadcrumbModel breadcrumbModel = new BreadcrumbModel();
+    
     private AuthenticationSession authenticationSession;
 
     public AuthenticatedWebSessionForIsis(final Request request) {
@@ -94,6 +101,22 @@ public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession impl
         return (WebClientInfo) super.getClientInfo();
     }
 
+    
+    // /////////////////////////////////////////////////
+    // Breadcrumbs and Bookmarks support
+    // /////////////////////////////////////////////////
+
+    @Override
+    public BreadcrumbModel getBreadcrumbModel() {
+        return breadcrumbModel;
+    }
+
+    @Override
+    public BookmarkedPagesModel getBookmarkedPagesModel() {
+        return bookmarkedPagesModel;
+    }
+
+
     // /////////////////////////////////////////////////
     // Dependencies
     // /////////////////////////////////////////////////
@@ -113,6 +136,6 @@ public class AuthenticatedWebSessionForIsis extends AuthenticatedWebSession impl
             cast.setAuthenticationSessionProvider(this);
         }
     }
-    
+
     
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
index f7b4e0c..d6140f9 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
@@ -317,7 +317,6 @@ public class ObjectAdapterMemento implements Serializable {
         return objectSpecId;
     }
 
-
     /**
      * Analogous to {@link List#contains(Object)}, but does not perform
      * {@link ConcurrencyChecking concurrency checking} of the OID.

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
index 741f0b6..ad2cd9b 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
@@ -30,6 +30,7 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
 
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
@@ -40,15 +41,9 @@ public class BookmarkTreeNode implements Serializable {
     
         private static final long serialVersionUID = 1L;
         
-//        public static final Function<? super BookmarkTreeNode, ? extends PageParameters> AS_PAGE_PARAMETERS = new Function<BookmarkTreeNode, PageParameters>() {
-//            public PageParameters apply(BookmarkTreeNode node) {
-//                return node.getPageParameters();
-//            }
-//        };
         private final List<BookmarkTreeNode> children = Lists.newArrayList();
         private final int depth;
 
-        //private final PageParameters pageParameters;
         private final RootOid oidNoVer;
         private final String oidNoVerStr;
         private final PageType pageType;
@@ -66,8 +61,8 @@ public class BookmarkTreeNode implements Serializable {
                 final int depth) {
             PageParameters pageParameters = bookmarkableModel.getPageParameters();
             RootOid oid = oidFrom(pageParameters);
-            this.oidNoVerStr = IsisContext.getOidMarshaller().marshalNoVersion(oid);
-            this.oidNoVer = IsisContext.getOidMarshaller().unmarshal(oidNoVerStr, RootOid.class); 
+            this.oidNoVerStr = getOidMarshaller().marshalNoVersion(oid);
+            this.oidNoVer = getOidMarshaller().unmarshal(oidNoVerStr, RootOid.class); 
             this.title = bookmarkableModel.getTitle();
             this.pageType = bookmarkableModel instanceof EntityModel ? PageType.ENTITY : PageType.ACTION_PROMPT;
             this.depth = depth;
@@ -92,10 +87,6 @@ public class BookmarkTreeNode implements Serializable {
             return pageType;
         }
 
-
-//        public PageParameters getPageParameters() {
-//            return pageParameters;
-//        }
         public List<BookmarkTreeNode> getChildren() {
             return children;
         }
@@ -144,8 +135,6 @@ public class BookmarkTreeNode implements Serializable {
             return inGraph;
         }
 
-
-
         private boolean addToGraphIfParented(BookmarkableModel<?> candidateBookmarkableModel) {
             
             boolean whetherAdded = false;
@@ -163,7 +152,7 @@ public class BookmarkTreeNode implements Serializable {
                     if(possibleParentOid == null) {
                         continue;
                     } 
-                    final String possibleParentOidStr = possibleParentOid.enStringNoVersion(IsisContext.getOidMarshaller());
+                    final String possibleParentOidStr = possibleParentOid.enStringNoVersion(getOidMarshaller());
                     if(Objects.equal(this.oidNoVerStr, possibleParentOidStr)) {
                         this.addChild(candidateBookmarkableModel);
                         whetherAdded = true;
@@ -193,7 +182,7 @@ public class BookmarkTreeNode implements Serializable {
                 return null;
             }
             try {
-                return IsisContext.getOidMarshaller().unmarshal(oidStr, RootOid.class);
+                return getOidMarshaller().unmarshal(oidStr, RootOid.class);
             } catch(Exception ex) {
                 return null;
             }
@@ -201,7 +190,14 @@ public class BookmarkTreeNode implements Serializable {
 
         public static String oidStrFrom(BookmarkableModel<?> candidateBookmarkableModel) {
             final RootOid oid = oidFrom(candidateBookmarkableModel.getPageParameters());
-            return oid != null? IsisContext.getOidMarshaller().marshalNoVersion(oid): null;
+            return oid != null? getOidMarshaller().marshalNoVersion(oid): null;
+        }
+
+
+        // //////////////////////////////////////
+
+        protected static OidMarshaller getOidMarshaller() {
+            return IsisContext.getOidMarshaller();
         }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
index c619c0f..03e4f88 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
@@ -135,7 +135,7 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
     }
 
     private BookmarkedPagesModel getBookmarkedPagesModel() {
-        BookmarkedPagesModelProvider application = (BookmarkedPagesModelProvider) getApplication();
+        BookmarkedPagesModelProvider application = (BookmarkedPagesModelProvider) getSession();
         return application.getBookmarkedPagesModel();
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModel.java
new file mode 100644
index 0000000..d49b96e
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModel.java
@@ -0,0 +1,106 @@
+/**
+ *  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.widgets.breadcrumbs;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+import org.apache.isis.viewer.wicket.model.mementos.PageParameterNames;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+
+public class BreadcrumbModel implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    
+    private static final int MAX_SIZE = 5;
+
+    private final Map<String, EntityModel> entityModelByOidStr = Maps.newHashMap();
+    private final Map<EntityModel, String> titleByEntityModel = Maps.newHashMap();
+    private final Map<EntityModel, String> oidStrByEntityModel = Maps.newHashMap();
+    private final List<EntityModel> list = Lists.newArrayList();
+    
+    public List<EntityModel> getList() {
+        return Collections.unmodifiableList(list);
+    }
+
+    public void visited(final EntityModel entityModel) {
+        final String oidStr = oidStrFor(entityModel);
+        
+        removeExisting(oidStr);
+        addToStart(oidStr, entityModel);
+        
+        trimTo(MAX_SIZE);
+    }
+
+    private String oidStrFor(final EntityModel entityModel) {
+        final PageParameters pageParameters = entityModel.getPageParametersWithoutUiHints();
+        return PageParameterNames.OBJECT_OID.getStringFrom(pageParameters);
+    }
+
+    private void addToStart(final String oidStr, final EntityModel entityModel) {
+        entityModelByOidStr.put(oidStr, entityModel);
+        titleByEntityModel.put(entityModel, entityModel.getTitle());
+        oidStrByEntityModel.put(entityModel, oidStr);
+        list.add(0, entityModel);
+    }
+
+    private void removeExisting(final String oidStr) {
+        final EntityModel existingModel = entityModelByOidStr.get(oidStr);
+        if(existingModel != null) {
+            remove(oidStr, existingModel);
+        }
+    }
+
+    private void trimTo(final int size) {
+        if(list.size() <= size) {
+            return;
+        } 
+        final List<EntityModel> modelsToRemove = list.subList(size, list.size());
+        for (final EntityModel model : modelsToRemove) {
+            final String oidStr = oidStrByEntityModel.get(model);
+            remove(oidStr, model);
+        }
+    }
+
+    private void remove(final String oidStr, final EntityModel model) {
+        entityModelByOidStr.remove(oidStr);
+        titleByEntityModel.remove(model);
+        oidStrByEntityModel.remove(model);
+        list.remove(model);
+    }
+
+    public String titleFor(final EntityModel model) {
+        return titleByEntityModel.get(model);
+    }
+
+    public EntityModel lookup(String oidStr) {
+        if(oidStr == null) {
+            return null;
+        }
+        return entityModelByOidStr.get(oidStr);
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModelProvider.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModelProvider.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModelProvider.java
new file mode 100644
index 0000000..1f41ce2
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbModelProvider.java
@@ -0,0 +1,23 @@
+/**
+ *  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.widgets.breadcrumbs;
+
+
+public interface BreadcrumbModelProvider {
+
+    BreadcrumbModel getBreadcrumbModel();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.css
new file mode 100644
index 0000000..3fbc5c3
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.css
@@ -0,0 +1,23 @@
+/*
+ *  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.
+ */
+
+.zeroClipboardPanel .subscribingLink {
+	display: none;
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.html
new file mode 100644
index 0000000..6fa2600
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.html
@@ -0,0 +1,29 @@
+<?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>
+	<body>
+		<wicket:panel>
+            <div class="breadcrumbPanel">
+                <input wicket:id="breadcrumbs" type="hidden" class="autoComplete" />
+            </div>
+		</wicket:panel>
+	</body>
+</html>
+

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.java
new file mode 100644
index 0000000..67550db
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/breadcrumbs/BreadcrumbPanel.java
@@ -0,0 +1,116 @@
+/**
+ *  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.widgets.breadcrumbs;
+
+import java.util.Collection;
+
+import com.vaynberg.wicket.select2.Response;
+import com.vaynberg.wicket.select2.Select2Choice;
+import com.vaynberg.wicket.select2.Settings;
+import com.vaynberg.wicket.select2.TextChoiceProvider;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+import org.apache.isis.viewer.wicket.model.mementos.PageParameterNames;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarModelSubscriber;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
+import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
+import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+public class BreadcrumbPanel extends PanelAbstract<IModel<Void>> {
+
+    private static final long serialVersionUID = 1L;
+    
+    private static final String ID_BREADCRUMBS = "breadcrumbs";
+
+    public BreadcrumbPanel(String id) {
+        super(id);
+    }
+    
+    @Override
+    protected void onInitialize() {
+        super.onInitialize();
+        
+        final BreadcrumbModelProvider session = (BreadcrumbModelProvider) getSession();
+        final BreadcrumbModel breadcrumbModel = session.getBreadcrumbModel();
+        
+        final IModel<EntityModel> entityModel = new Model<EntityModel>();
+        final Select2Choice<EntityModel> breadcrumbChoice = new Select2Choice<EntityModel>(ID_BREADCRUMBS, entityModel);
+
+        breadcrumbChoice.add(
+            new AjaxFormComponentUpdatingBehavior("onchange"){
+    
+                private static final long serialVersionUID = 1L;
+    
+                @Override
+                protected void onUpdate(AjaxRequestTarget target) {
+                    final String oidStr = breadcrumbChoice.getInput();
+                    final EntityModel selectedModel = breadcrumbModel.lookup(oidStr);
+                    if(selectedModel == null) {
+                        return;
+                    }
+                    setResponsePage(EntityPage.class, selectedModel.getPageParameters());
+                }
+            });
+        
+        final Settings settings = breadcrumbChoice.getSettings();
+        settings.setMinimumInputLength(0);
+        settings.setWidth("90%");
+        
+        breadcrumbChoice.setProvider(new TextChoiceProvider<EntityModel>() {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected String getDisplayText(EntityModel choice) {
+                return breadcrumbModel.titleFor(choice);
+            }
+
+            @Override
+            protected Object getId(EntityModel choice) {
+                return PageParameterNames.OBJECT_OID.getStringFrom(choice.getPageParameters());
+            }
+
+            @Override
+            public void query(String term, int page, Response<EntityModel> response) {
+                response.addAll(breadcrumbModel.getList());
+            }
+
+            @Override
+            public Collection<EntityModel> toChoices(Collection<String> ids) {
+                return breadcrumbModel.getList();
+            }
+            
+        });
+        addOrReplace(breadcrumbChoice);
+    }
+
+    // //////////////////////////////////////
+
+    protected PageClassRegistry getPageClassRegistry() {
+        final PageClassRegistryAccessor pcra = (PageClassRegistryAccessor) getApplication();
+        return pcra.getPageClassRegistry();
+    }
+
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/zclip/ZeroClipboardPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/zclip/ZeroClipboardPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/zclip/ZeroClipboardPanel.java
index 767d40f..7d68eb3 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/zclip/ZeroClipboardPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/zclip/ZeroClipboardPanel.java
@@ -31,8 +31,6 @@ import org.apache.isis.viewer.wicket.model.models.PageType;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
-import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
-import org.apache.isis.viewer.wicket.ui.util.CssClassRemover;
 import org.apache.isis.viewer.wicket.ui.util.Links;
 
 public class ZeroClipboardPanel extends PanelAbstract<IModel<Void>> {
@@ -52,6 +50,9 @@ public class ZeroClipboardPanel extends PanelAbstract<IModel<Void>> {
     @Override
     protected void onInitialize() {
         super.onInitialize();
+        
+
+        
         if(copyLink == null) {
             copyLink = new ZeroClipboardLink(ID_COPY_LINK, "#subscribingLink");
             addOrReplace(copyLink);

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
index 4e53306..ccc1ccb 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
@@ -127,7 +127,13 @@ colors
 }
 
 #tertiaryMenu {
-    width: 8%;
+    width: 4%;
+    float: right;
+    padding-right: 20px;
+}
+#breadcrumbsMenu {
+    width: 10%;
+    float: right;
 }
 #tertiaryMenu .imgLinks {
 	line-height: 30px;
@@ -135,13 +141,6 @@ colors
 	margin-right:20px;
 }
 
-#tertiaryMenu .imgLinks a {
-    background-image: url("copy-26.png"); 
-    background-position: right;
-    background-repeat: no-repeat;
-    cursor: pointer;
-}
-
 #tertiaryMenu  a.copyLink:hover,
 #tertiaryMenu  a.copyLink.hover {
     cursor: pointer;
@@ -161,6 +160,11 @@ colors
     margin-right: 5px;
 }
 
+#tertiaryMenu a {
+	font-size:3em;
+	line-height: 30px;
+}
+
 #header h1 {
 	margin: 10px 10px 10px 0px;
 	font-size: xx-large;
@@ -954,3 +958,14 @@ div.wicket-mask-dark {
 
 
 
+/**
+zero clipboard
+(for some reason - perhaps to do with Flash - this CSS doesn't seem to 
+ do anything if within the ZeroClipboard.css)
+*/
+.zeroClipboardPanel a {
+    background-image: url("copy-26.png"); 
+    background-position: right;
+    background-repeat: no-repeat;
+    cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
index 5056d66..327d46f 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.html
@@ -54,12 +54,13 @@
 			<div class="clear"/>
 
 			<div wicket:id="applicationActions" id="applicationActions"/>
+            <div id="breadcrumbsMenu">
+                <span wicket:id="breadcrumbs"/>
+            </div>
             <div id="tertiaryMenu">
-                <div class="imgLinks">
-                    <a wicket:id="copyLink" href="#">
-                        <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
-                    </a>
-                </div>
+                <a wicket:id="copyLink" href="#">
+                    <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                </a>
             </div>
 
 		</div>

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
index 05c60bc..a346421 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
@@ -71,6 +71,7 @@ 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.actionprompt.ActionPromptModalWindow;
+import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbPanel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.zclip.ZeroClipboardLink;
 import org.apache.isis.viewer.wicket.ui.components.widgets.zclip.ZeroClipboardPanel;
 import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel;
@@ -102,6 +103,7 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
     public static final String ID_LOGOUT_LINK = "logoutLink";
     public static final String ID_ABOUT_LINK = "aboutLink";
     private static final String ID_COPY_LINK = "copyLink";
+    private static final String ID_BREADCRUMBS = "breadcrumbs";
 
 
     private static final JavaScriptResourceReference JQUERY_JGROWL_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.jgrowl.js");
@@ -155,6 +157,9 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
     
     public PageAbstract(final PageParameters pageParameters, ApplicationActions applicationActions, final String title, final ComponentType... childComponentIds) {
         try {
+            // for breadcrumbs support
+            getSession().bind();
+            
             addApplicationActions(applicationActions);
             this.childComponentIds = Collections.unmodifiableList(Arrays.asList(childComponentIds));
             this.pageParameters = pageParameters;
@@ -162,6 +167,7 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
             addUserName();
             addLogoutLink();
             addAboutLink();
+            addBreadcrumbs();
             addCopyLink();
             
             add(new Label(ID_PAGE_TITLE, title != null? title: applicationName));
@@ -187,8 +193,6 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
             throw new RestartResponseAtInterceptPageException(WicketSignInPage.class);
         }
     }
-    
-
 
     protected ExceptionModel recognizeException(Exception ex) {
         List<ExceptionRecognizer> exceptionRecognizers;
@@ -226,7 +230,6 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
         }
     }
 
-
     private void addHomePageLinkAndApplicationName() {
         // this is a bit hacky, but it'll do...
         ExternalLink homePageLink = new ExternalLink(ID_HOME_PAGE_LINK, "/wicket/");
@@ -262,6 +265,11 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
         });
     }
 
+    private void addBreadcrumbs() {
+        BreadcrumbPanel breadcrumbPanel = new BreadcrumbPanel(ID_BREADCRUMBS);
+        addOrReplace(breadcrumbPanel);
+    }
+    
     private void addCopyLink() {
         ZeroClipboardPanel zClipCopyLink = new ZeroClipboardPanel(ID_COPY_LINK);
         addOrReplace(zClipCopyLink);
@@ -334,8 +342,8 @@ public abstract class PageAbstract extends WebPage implements ActionPromptProvid
     }
 
     private BookmarkedPagesModel getBookmarkedPagesModel() {
-        BookmarkedPagesModelProvider application = (BookmarkedPagesModelProvider) getApplication();
-        return application.getBookmarkedPagesModel();
+        BookmarkedPagesModelProvider session = (BookmarkedPagesModelProvider) getSession();
+        return session.getBookmarkedPagesModel();
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c58864e6/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
index b942a31..bb03392 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
@@ -22,6 +22,7 @@ package org.apache.isis.viewer.wicket.ui.pages.entity;
 import java.util.List;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.Session;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
@@ -42,6 +43,8 @@ import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModel;
+import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModelProvider;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 
 /**
@@ -88,18 +91,18 @@ public class EntityPage extends PageAbstract {
     private EntityPage(PageParameters pageParameters, EntityModel entityModel, String titleString) {
         super(pageParameters, ApplicationActions.INCLUDE, titleString, ComponentType.ENTITY);
         this.model = entityModel;
-        //try {
-        //    UiHintContainer.CURRENT.set(entityModel);
-            addChildComponents(model);
-        //} finally {
-        //    UiHintContainer.CURRENT.set(null);
-        //}
+        addChildComponents(model);
         
         final ObjectAndAction objectAndAction =lookupHomePageAction();
         final ActionModel actionModel = ActionModel.create(objectAndAction.objectAdapter, objectAndAction.action);
         
         bookmarkPage(model);
         addBookmarkedPages();
+        
+        final BreadcrumbModelProvider session = (BreadcrumbModelProvider) getSession();
+        final BreadcrumbModel breadcrumbModel = session.getBreadcrumbModel();
+        
+        breadcrumbModel.visited(entityModel);
     }
 
     private static class ObjectAndAction {