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 2014/11/10 11:23:21 UTC

[14/23] isis git commit: ISIS-537: factored out CollectionContentsSelectorDropdownPanel from CollectionContentsLinksSelectorPanel.

ISIS-537: factored out CollectionContentsSelectorDropdownPanel from CollectionContentsLinksSelectorPanel.


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

Branch: refs/heads/ISIS-939
Commit: 70af3c3238d90badefcb512cc733cf3e8ac3a294
Parents: 5918dd6
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Sun Nov 9 15:05:51 2014 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon Nov 10 10:21:41 2014 +0000

----------------------------------------------------------------------
 ...CollectionContentsSelectorDropdownPanel.html |  44 ++
 ...CollectionContentsSelectorDropdownPanel.java | 441 +++++++++++++++++++
 ...ionContentsSelectorSelectorDropdownPanel.css |  60 +++
 .../CollectionContentsLinksSelectorPanel.html   |  18 +-
 .../CollectionContentsLinksSelectorPanel.java   | 406 +++++++++--------
 .../java/dom/todo/ToDoItemContributions.java    |   1 +
 6 files changed, 788 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.html
new file mode 100644
index 0000000..ea2a4d8
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.html
@@ -0,0 +1,44 @@
+<?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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns:wicket="http://wicket.apache.org">
+<body>
+<wicket:panel>
+    <div class="linksSelectorPanel">
+        <div class="btn-group viewLinks" wicket:id="views">
+            <button type="button" class="btn btn-xs btn-info">
+                <span wicket:id="viewButtonIcon" class="ViewLinkItem"></span>
+                <span wicket:id="viewButtonTitle" class="ViewLinkItemTitle"></span>
+            </button>
+            <button type="button" class="btn btn-xs btn-info dropdown-toggle" data-toggle="dropdown">
+                <span class="caret"></span>
+            </button>
+            <ul wicket:id="viewList" class="dropdown-menu dropdown-menu-right" role="menu">
+                <li wicket:id="viewItem" class="viewItem">
+                    <a href="#" wicket:id="viewLink">
+                        <span wicket:id="viewItemIcon" class="ViewLinkItem"></span> <span wicket:id="viewItemTitle" class="ViewLinkItemTitle">[link title]</span>
+                    </a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</wicket:panel>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.java
new file mode 100644
index 0000000..0903d2a
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorDropdownPanel.java
@@ -0,0 +1,441 @@
+/*
+ *  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.selector.dropdown;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.core.commons.lang.StringExtensions;
+import org.apache.isis.core.metamodel.facets.members.render.RenderFacet;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+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.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.selector.links.CollectionContentsLinksSelectorPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsAsUnresolvedPanelFactory;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+import org.apache.isis.viewer.wicket.ui.util.CssClassRemover;
+
+/**
+ * Provides a list of links for selecting other views that support
+ * {@link org.apache.isis.viewer.wicket.ui.ComponentType#COLLECTION_CONTENTS} with a backing
+ * {@link org.apache.isis.viewer.wicket.model.models.EntityCollectionModel}.
+ */
+public class CollectionContentsSelectorDropdownPanel
+        extends PanelAbstract<EntityCollectionModel> implements UiHintPathSignificant /*,  CollectionCountProvider*/ {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String INVISIBLE_CLASS = "link-selector-panel-invisible";
+//    private static final int MAX_NUM_UNDERLYING_VIEWS = 10;
+
+    private static final String ID_VIEWS = "views";
+    private static final String ID_VIEW_LIST = "viewList";
+    private static final String ID_VIEW_LINK = "viewLink";
+    private static final String ID_VIEW_ITEM = "viewItem";
+    private static final String ID_VIEW_ITEM_TITLE = "viewItemTitle";
+    private static final String ID_VIEW_ITEM_ICON = "viewItemIcon";
+
+    private static final String UIHINT_VIEW = "view";
+    private static final String ID_VIEW_BUTTON_TITLE = "viewButtonTitle";
+    private static final String ID_VIEW_BUTTON_ICON = "viewButtonIcon";
+
+    private final ComponentType componentType;
+
+    private ComponentFactory selectedComponentFactory;
+//    private Component selectedComponent;
+
+//    /**
+//     * May be <tt>null</tt>, depending upon the model implementation.
+//     */
+//    protected WebMarkupContainer additionalLinks;
+
+    public CollectionContentsSelectorDropdownPanel(final String id, final EntityCollectionModel model, final ComponentFactory factory) {
+        super(id, model);
+        this.componentType = factory.getComponentType();
+    }
+
+    /**
+     * Build UI only after added to parent.
+     */
+    public void onInitialize() {
+        super.onInitialize();
+        ComponentFactory componentFactory = getComponentFactoryRegistry().findComponentFactoryElseFailFast(getComponentType(), getModel());
+        addUnderlyingViews(getModel(), componentFactory);
+    }
+
+
+    private void addUnderlyingViews(final EntityCollectionModel model, final ComponentFactory factory) {
+        final List<ComponentFactory> componentFactories = findOtherComponentFactories(model, factory);
+
+        final int selected = honourViewHintElseDefault(componentFactories, model);
+
+        final CollectionContentsSelectorDropdownPanel selectorPanel = this;
+
+        // create all, hide the one not selected
+//        final Component[] underlyingViews = new Component[MAX_NUM_UNDERLYING_VIEWS];
+//        int i = 0;
+//        final EntityCollectionModel emptyModel = model.asDummy();
+//        for (ComponentFactory componentFactory : componentFactories) {
+//            final String underlyingId = underlyingIdPrefix + "-" + i;
+//
+//            Component underlyingView = componentFactory.createComponent(underlyingId,i==selected? model: emptyModel);
+//            underlyingViews[i++] = underlyingView;
+//            selectorPanel.addOrReplace(underlyingView);
+//        }
+
+//        // hide any unused placeholders
+//        while(i<MAX_NUM_UNDERLYING_VIEWS) {
+//            String underlyingId = underlyingIdPrefix + "-" + i;
+//            permanentlyHide(underlyingId);
+//            i++;
+//        }
+
+        // selector
+        if (componentFactories.size() <= 1) {
+            permanentlyHide(ID_VIEWS);
+        } else {
+            final Model<ComponentFactory> componentFactoryModel = new Model<>();
+
+            selectorPanel.selectedComponentFactory = componentFactories.get(selected);
+            componentFactoryModel.setObject(selectorPanel.selectedComponentFactory);
+
+            final WebMarkupContainer views = new WebMarkupContainer(ID_VIEWS);
+
+            final Label viewButtonTitle = new Label(ID_VIEW_BUTTON_TITLE, "Hidden");
+            views.addOrReplace(viewButtonTitle);
+
+            final Label viewButtonIcon = new Label(ID_VIEW_BUTTON_ICON, "");
+            views.addOrReplace(viewButtonIcon);
+
+            final WebMarkupContainer container = new WebMarkupContainer(ID_VIEW_LIST);
+
+            views.addOrReplace(container);
+            views.setOutputMarkupId(true);
+
+            this.setOutputMarkupId(true);
+
+            final ListView<ComponentFactory> listView = new ListView<ComponentFactory>(ID_VIEW_ITEM, componentFactories) {
+
+                private static final long serialVersionUID = 1L;
+
+                @Override
+                protected void populateItem(ListItem<ComponentFactory> item) {
+
+                    final int underlyingViewNum = item.getIndex();
+
+                    final ComponentFactory componentFactory = item.getModelObject();
+                    final AbstractLink link = new AjaxLink<Void>(ID_VIEW_LINK) {
+                        private static final long serialVersionUID = 1L;
+                        @Override
+                        public void onClick(AjaxRequestTarget target) {
+                            CollectionContentsSelectorDropdownPanel linksSelectorPanel = CollectionContentsSelectorDropdownPanel.this;
+                            linksSelectorPanel.setViewHintAndBroadcast(underlyingViewNum, target);
+
+//                            final EntityCollectionModel dummyModel = model.asDummy();
+//                            for(int i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
+//                                final Component component = underlyingViews[i];
+//                                if(component == null) {
+//                                    continue;
+//                                }
+//                                final boolean isSelected = i == underlyingViewNum;
+//                                applyCssVisibility(component, isSelected);
+//                                component.setDefaultModel(isSelected? model: dummyModel);
+//                            }
+
+                            selectorPanel.selectedComponentFactory = componentFactory;
+//                            selectorPanel.selectedComponent = underlyingViews[underlyingViewNum];
+//                            selectorPanel.onSelect(target);
+                            target.add(selectorPanel, views);
+                        }
+
+                        @Override
+                        protected void onComponentTag(ComponentTag tag) {
+                            super.onComponentTag(tag);
+                            Buttons.fixDisabledState(this, tag);
+                        }
+                    };
+
+                    IModel<String> title = nameFor(componentFactory);
+                    Label viewItemTitleLabel = new Label(ID_VIEW_ITEM_TITLE, title);
+                    link.add(viewItemTitleLabel);
+
+                    Label viewItemIcon = new Label(ID_VIEW_ITEM_ICON, "");
+                    link.add(viewItemIcon);
+
+                    boolean isEnabled = componentFactory != selectorPanel.selectedComponentFactory;
+                    if (!isEnabled) {
+                        viewButtonTitle.setDefaultModel(title);
+                        IModel<String> cssClass = cssClassFor(componentFactory, viewButtonIcon);
+                        viewButtonIcon.add(AttributeModifier.replace("class", "ViewLinkItem " + cssClass.getObject()));
+                        link.setVisible(false);
+                    } else {
+                        IModel<String> cssClass = cssClassFor(componentFactory, viewItemIcon);
+                        viewItemIcon.add(new CssClassAppender(cssClass));
+                    }
+
+                    item.add(link);
+                }
+
+                private IModel<String> cssClassFor(final ComponentFactory componentFactory, Label viewIcon) {
+                    IModel<String> cssClass = null;
+                    if (componentFactory instanceof CollectionContentsAsFactory) {
+                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
+                        cssClass = collectionContentsAsFactory.getCssClass();
+                        viewIcon.setDefaultModelObject("");
+                        viewIcon.setEscapeModelStrings(true);
+                    }
+                    if (cssClass == null) {
+                        String name = componentFactory.getName();
+                        cssClass = Model.of(StringExtensions.asLowerDashed(name));
+                        // Small hack: if there is no specific CSS class then we assume that background-image is used
+                        // the span.ViewItemLink should have some content to show it
+                        // FIX: find a way to do this with CSS (width and height don't seems to help)
+                        viewIcon.setDefaultModelObject("&#160;&#160;&#160;&#160;&#160;");
+                        viewIcon.setEscapeModelStrings(false);
+                    }
+                    return cssClass;
+                }
+
+                private IModel<String> nameFor(final ComponentFactory componentFactory) {
+                    IModel<String> name = null;
+                    if (componentFactory instanceof CollectionContentsAsFactory) {
+                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
+                        name = collectionContentsAsFactory.getTitleLabel();
+                    }
+                    if (name == null) {
+                        name = Model.of(componentFactory.getName());
+                    }
+                    return name;
+                }
+            };
+            container.add(listView);
+            addOrReplace(views);
+        }
+
+//        for(i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
+//            Component component = underlyingViews[i];
+//            if(component != null) {
+//                if(i != selected) {
+//                    component.add(new CssClassAppender(INVISIBLE_CLASS));
+//                } else {
+//                    selectedComponent = component;
+//                }
+//            }
+//        }
+    }
+
+
+
+    protected void setViewHintAndBroadcast(int viewNum, AjaxRequestTarget target) {
+        final UiHintContainer uiHintContainer = getUiHintContainer();
+        if(uiHintContainer == null) {
+            return;
+        }
+        uiHintContainer.setHint(CollectionContentsSelectorDropdownPanel.this, UIHINT_VIEW, ""+viewNum);
+        send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
+    }
+
+//    /**
+//     * Iterates up the component hierarchy looking for a parent
+//     * {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}, and if so adds to ajax target so that it'll
+//     * be repainted.
+//     *
+//     * <p>
+//     * Yeah, agreed, it's a little bit hacky doing it this way, because it bakes
+//     * in knowledge that this component is created, somehow, by a parent {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}.
+//     * Perhaps it could be refactored to use a more general purpose observer pattern?
+//     *
+//     * <p>
+//     * In fact, I've since discovered that Wicket has an event bus, which is used by the
+//     * {@link org.apache.isis.viewer.wicket.model.hints.UiHintContainer hinting mechanism}.  So this ought to be relatively easy to do.
+//     */
+//    public void onSelect(AjaxRequestTarget target) {
+//        Component component = this;
+//        while(component != null) {
+//            if(component instanceof CollectionPanel) {
+//                CollectionPanel collectionPanel = (CollectionPanel) component;
+//                boolean hasCount = collectionPanel.hasCount();
+//                if(hasCount) {
+//                    collectionPanel.updateLabel(target);
+//                }
+////                if(additionalLinks != null) {
+////                    applyCssVisibility(additionalLinks, hasCount);
+////                }
+//                return;
+//            }
+//            component = component.getParent();
+//        }
+//    }
+
+
+    protected static void applyCssVisibility(final Component component, final boolean visible) {
+        if(component == null) {
+            return;
+        }
+        AttributeModifier modifier = visible ? new CssClassRemover(INVISIBLE_CLASS) : new CssClassAppender(INVISIBLE_CLASS);
+        component.add(modifier);
+    }
+
+    protected int honourViewHintElseDefault(final List<ComponentFactory> componentFactories, final IModel<?> model) {
+        // honour hints ...
+        final UiHintContainer hintContainer = getUiHintContainer();
+        if(hintContainer != null) {
+            String viewStr = hintContainer.getHint(this, UIHINT_VIEW);
+            if(viewStr != null) {
+                try {
+                    int view = Integer.parseInt(viewStr);
+                    if(view >= 0 && view < componentFactories.size()) {
+                        return view;
+                    }
+                } catch(NumberFormatException ex) {
+                    // ignore
+                }
+            }
+        }
+
+        // ... else default
+        int initialFactory = determineInitialFactory(componentFactories, model);
+        if(hintContainer != null) {
+            hintContainer.setHint(this, UIHINT_VIEW, ""+initialFactory);
+            // don't broadcast (no AjaxRequestTarget, still configuring initial setup)
+        }
+        return initialFactory;
+    }
+
+
+    /**
+     * return the index of {@link org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsAsUnresolvedPanelFactory unresolved panel} if present and not eager loading;
+     * else the index of {@link org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanelFactory ajax table} if present,
+     * otherwise first factory.
+     */
+    protected int determineInitialFactory(final List<ComponentFactory> componentFactories, final IModel<?> model) {
+        if(!hasRenderEagerlyFacet(model)) {
+            for(int i=0; i<componentFactories.size(); i++) {
+                if(componentFactories.get(i) instanceof CollectionContentsAsUnresolvedPanelFactory) {
+                    return i;
+                }
+            }
+        }
+        int ajaxTableIdx = findAjaxTable(componentFactories);
+        if(ajaxTableIdx>=0) {
+            return ajaxTableIdx;
+        }
+        return 0;
+    }
+
+    private List<ComponentFactory> findOtherComponentFactories(final EntityCollectionModel model, final ComponentFactory ignoreFactory) {
+        final List<ComponentFactory> componentFactories = getComponentFactoryRegistry().findComponentFactories(componentType, model);
+        ArrayList<ComponentFactory> otherFactories = Lists.newArrayList(Collections2.filter(componentFactories, new Predicate<ComponentFactory>() {
+            @Override
+            public boolean apply(final ComponentFactory input) {
+                return input != ignoreFactory && input.getClass() != CollectionContentsLinksSelectorPanelFactory.class;
+            }
+        }));
+        return ordered(otherFactories);
+    }
+
+    protected List<ComponentFactory> ordered(List<ComponentFactory> componentFactories) {
+        return orderAjaxTableToEnd(componentFactories);
+    }
+
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        PanelUtil.renderHead(response, CollectionContentsSelectorDropdownPanel.class);
+    }
+
+
+    static List<ComponentFactory> orderAjaxTableToEnd(List<ComponentFactory> componentFactories) {
+        int ajaxTableIdx = findAjaxTable(componentFactories);
+        if(ajaxTableIdx>=0) {
+            List<ComponentFactory> orderedFactories = Lists.newArrayList(componentFactories);
+            ComponentFactory ajaxTableFactory = orderedFactories.remove(ajaxTableIdx);
+            orderedFactories.add(ajaxTableFactory);
+            return orderedFactories;
+        } else {
+            return componentFactories;
+        }
+    }
+    
+    private static int findAjaxTable(List<ComponentFactory> componentFactories) {
+        for(int i=0; i<componentFactories.size(); i++) {
+            if(componentFactories.get(i) instanceof CollectionContentsAsAjaxTablePanelFactory) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    private static boolean hasRenderEagerlyFacet(IModel<?> model) {
+        if(!(model instanceof EntityCollectionModel)) {
+            return false;
+        }
+        final EntityCollectionModel entityCollectionModel = (EntityCollectionModel) model;
+        if(!entityCollectionModel.isParented()) {
+            return false;
+        }
+
+        final OneToManyAssociation collection = 
+                entityCollectionModel.getCollectionMemento().getCollection();
+        RenderFacet renderFacet = collection.getFacet(RenderFacet.class);
+        return renderFacet != null && renderFacet.value() == Type.EAGERLY;
+    }
+
+
+//    @Override
+//    public Integer getCount() {
+//        if(selectedComponent instanceof CollectionCountProvider) {
+//            final CollectionCountProvider collectionCountProvider = (CollectionCountProvider) selectedComponent;
+//            return collectionCountProvider.getCount();
+//        } else {
+//            return null;
+//        }
+//    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorSelectorDropdownPanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorSelectorDropdownPanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorSelectorDropdownPanel.css
new file mode 100644
index 0000000..8c3902e
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/dropdown/CollectionContentsSelectorSelectorDropdownPanel.css
@@ -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.
+ */
+.linksSelectorPanel .viewLinks {
+    float:right;
+    display:block;
+}
+
+.linksSelectorPanel ul.dropdown-menu {
+    min-width: 0;
+}
+
+.linksSelectorPanel ul.dropdown-menu li.viewItem {
+    min-width: 0;
+}
+
+.linksSelectorPanel ul.viewList li.viewItem:first-child span {
+    border-radius:4px 0 0 4px;
+    -moz-border-radius:4px 0 0 4px;
+    -webkit-border-radius:4px 0 0 4px;
+}
+
+.linksSelectorPanel ul.viewList li.viewItem:last-child span {
+    border-radius:0 4px 4px 0;
+    -moz-border-radius:0 4px 4px 0;
+    -webkit-border-radius:0 4px 4px 0;
+}
+
+
+.linksSelectorPanel .link-selector-panel-invisible {
+    display:none;
+}
+
+.linksSelectorPanel .list-inline {
+    margin-left: 0;
+}
+
+.linksSelectorPanel .list-inline li {
+    padding-left: 0;
+}
+
+
+.collectionContentsLinksSelectorPanel select {
+	margin-bottom: 1em;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.html
index 1fbf7df..2903711 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.html
@@ -22,22 +22,26 @@
 <body>
 <wicket:panel>
     <div class="linksSelectorPanel">
-        <div class="btn-group viewLinks" wicket:id="views">
+        <span wicket:id="selectorDropdown"/>
+
+        <!--
+        <div class="btn-group viewLinks" xxwicket:id="views">
             <button type="button" class="btn btn-xs btn-info">
-                <span wicket:id="viewButtonIcon" class="ViewLinkItem"></span>
-                <span wicket:id="viewButtonTitle" class="ViewLinkItemTitle"></span>
+                <span xxwicket:id="viewButtonIcon" class="ViewLinkItem"></span>
+                <span xxwicket:id="viewButtonTitle" class="ViewLinkItemTitle"></span>
             </button>
             <button type="button" class="btn btn-xs btn-info dropdown-toggle" data-toggle="dropdown">
                 <span class="caret"></span>
             </button>
-            <ul wicket:id="viewList" class="dropdown-menu dropdown-menu-right" role="menu">
-                <li wicket:id="viewItem" class="viewItem">
-                    <a href="#" wicket:id="viewLink">
-                        <span wicket:id="viewItemIcon" class="ViewLinkItem"></span> <span wicket:id="viewItemTitle" class="ViewLinkItemTitle">[link title]</span>
+            <ul xxwicket:id="viewList" class="dropdown-menu dropdown-menu-right" role="menu">
+                <li xxwicket:id="viewItem" class="viewItem">
+                    <a href="#" xxwicket:id="viewLink">
+                        <span xxwicket:id="viewItemIcon" class="ViewLinkItem"></span> <span xxwicket:id="viewItemTitle" class="ViewLinkItemTitle">[link title]</span>
                     </a>
                 </li>
             </ul>
         </div>
+        -->
 
         <div class="views">
             <div wicket:id="collectionContents-0" class="collectionContentsLinksSelectorPanel collectionContentsComponentType"></div>

http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.java
index d0d987b..f29244f 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/selector/links/CollectionContentsLinksSelectorPanel.java
@@ -19,8 +19,6 @@
 
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.selector.links;
 
-import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
-
 import java.util.ArrayList;
 import java.util.List;
 import com.google.common.base.Predicate;
@@ -29,31 +27,23 @@ import com.google.common.collect.Lists;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
-import org.apache.wicket.event.Broadcast;
-import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.event.IEvent;
 import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.link.AbstractLink;
-import org.apache.wicket.markup.html.list.ListItem;
-import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.isis.applib.annotation.Render.Type;
-import org.apache.isis.core.commons.lang.StringExtensions;
 import org.apache.isis.core.metamodel.facets.members.render.RenderFacet;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.viewer.wicket.model.hints.IsisEnvelopeEvent;
 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.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.collection.CollectionCountProvider;
-import org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.selector.dropdown.CollectionContentsSelectorDropdownPanel;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsAsUnresolvedPanelFactory;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
@@ -73,16 +63,20 @@ public class CollectionContentsLinksSelectorPanel
     private static final String INVISIBLE_CLASS = "link-selector-panel-invisible";
     private static final int MAX_NUM_UNDERLYING_VIEWS = 10;
 
-    private static final String ID_VIEWS = "views";
-    private static final String ID_VIEW_LIST = "viewList";
-    private static final String ID_VIEW_LINK = "viewLink";
-    private static final String ID_VIEW_ITEM = "viewItem";
-    private static final String ID_VIEW_ITEM_TITLE = "viewItemTitle";
-    private static final String ID_VIEW_ITEM_ICON = "viewItemIcon";
+    private static final String ID_SELECTOR_DROPDOWN = "selectorDropdown";
+
+//    private static final String ID_VIEWS = "views";
+//    private static final String ID_VIEW_LIST = "viewList";
+//    private static final String ID_VIEW_LINK = "viewLink";
+//    private static final String ID_VIEW_ITEM = "viewItem";
+//    private static final String ID_VIEW_ITEM_TITLE = "viewItemTitle";
+//    private static final String ID_VIEW_ITEM_ICON = "viewItemIcon";
 
     private static final String UIHINT_VIEW = "view";
-    private static final String ID_VIEW_BUTTON_TITLE = "viewButtonTitle";
-    private static final String ID_VIEW_BUTTON_ICON = "viewButtonIcon";
+//    private static final String ID_VIEW_BUTTON_TITLE = "viewButtonTitle";
+//    private static final String ID_VIEW_BUTTON_ICON = "viewButtonIcon";
+
+    private final ComponentFactory componentFactory;
 
     private final ComponentType componentType;
     private final String underlyingIdPrefix;
@@ -90,13 +84,21 @@ public class CollectionContentsLinksSelectorPanel
     private ComponentFactory selectedComponentFactory;
     protected Component selectedComponent;
 
-    /**
-     * May be <tt>null</tt>, depending upon the model implementation.
-     */
-    protected WebMarkupContainer additionalLinks;
+//    /**
+//     * May be <tt>null</tt>, depending upon the model implementation.
+//     */
+//    protected WebMarkupContainer additionalLinks;
+
+    private Component[] underlyingViews;
+    private List<ComponentFactory> componentFactories;
+    private CollectionContentsSelectorDropdownPanel selectorDropdownPanel;
 
-    public CollectionContentsLinksSelectorPanel(final String id, final EntityCollectionModel model, final ComponentFactory factory) {
+    public CollectionContentsLinksSelectorPanel(
+            final String id,
+            final EntityCollectionModel model,
+            final ComponentFactory factory) {
         super(id, model);
+        componentFactory = factory;
         this.underlyingIdPrefix = ComponentType.COLLECTION_CONTENTS.toString();
         this.componentType = factory.getComponentType();
     }
@@ -107,19 +109,20 @@ public class CollectionContentsLinksSelectorPanel
     public void onInitialize() {
         super.onInitialize();
         ComponentFactory componentFactory = getComponentFactoryRegistry().findComponentFactoryElseFailFast(getComponentType(), getModel());
-        addUnderlyingViews(underlyingIdPrefix, getModel(), componentFactory);
+        addUnderlyingViews(componentFactory);
     }
 
 
-    private void addUnderlyingViews(final String underlyingIdPrefix, final EntityCollectionModel model, final ComponentFactory factory) {
-        final List<ComponentFactory> componentFactories = findOtherComponentFactories(model, factory);
+    private void addUnderlyingViews(final ComponentFactory factory) {
+        final EntityCollectionModel model = getModel();
+        componentFactories = findOtherComponentFactories(model, factory);
 
         final int selected = honourViewHintElseDefault(componentFactories, model);
 
         final CollectionContentsLinksSelectorPanel selectorPanel = this;
 
         // create all, hide the one not selected
-        final Component[] underlyingViews = new Component[MAX_NUM_UNDERLYING_VIEWS];
+        underlyingViews = new Component[MAX_NUM_UNDERLYING_VIEWS];
         int i = 0;
         final EntityCollectionModel emptyModel = model.asDummy();
         for (ComponentFactory componentFactory : componentFactories) {
@@ -139,124 +142,130 @@ public class CollectionContentsLinksSelectorPanel
 
         // selector
         if (componentFactories.size() <= 1) {
-            permanentlyHide(ID_VIEWS);
+            //permanentlyHide(ID_VIEWS);
+
+            permanentlyHide(ID_SELECTOR_DROPDOWN);
         } else {
             final Model<ComponentFactory> componentFactoryModel = new Model<>();
 
             selectorPanel.selectedComponentFactory = componentFactories.get(selected);
             componentFactoryModel.setObject(selectorPanel.selectedComponentFactory);
 
-            final WebMarkupContainer views = new WebMarkupContainer(ID_VIEWS);
-
-            final Label viewButtonTitle = new Label(ID_VIEW_BUTTON_TITLE, "Hidden");
-            views.addOrReplace(viewButtonTitle);
-
-            final Label viewButtonIcon = new Label(ID_VIEW_BUTTON_ICON, "");
-            views.addOrReplace(viewButtonIcon);
-
-            final WebMarkupContainer container = new WebMarkupContainer(ID_VIEW_LIST);
-
-            views.addOrReplace(container);
-            views.setOutputMarkupId(true);
+            selectorDropdownPanel = new CollectionContentsSelectorDropdownPanel(ID_SELECTOR_DROPDOWN, getModel(), componentFactory);
 
             this.setOutputMarkupId(true);
 
-            final ListView<ComponentFactory> listView = new ListView<ComponentFactory>(ID_VIEW_ITEM, componentFactories) {
-
-                private static final long serialVersionUID = 1L;
-
-                @Override
-                protected void populateItem(ListItem<ComponentFactory> item) {
-
-                    final int underlyingViewNum = item.getIndex();
-
-                    final ComponentFactory componentFactory = item.getModelObject();
-                    final AbstractLink link = new AjaxLink<Void>(ID_VIEW_LINK) {
-                        private static final long serialVersionUID = 1L;
-                        @Override
-                        public void onClick(AjaxRequestTarget target) {
-                            CollectionContentsLinksSelectorPanel linksSelectorPanel = CollectionContentsLinksSelectorPanel.this;
-                            linksSelectorPanel.setViewHintAndBroadcast(underlyingViewNum, target);
-
-                            final EntityCollectionModel dummyModel = model.asDummy();
-                            for(int i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
-                                final Component component = underlyingViews[i];
-                                if(component == null) {
-                                    continue;
-                                }
-                                final boolean isSelected = i == underlyingViewNum;
-                                applyCssVisibility(component, isSelected);
-                                component.setDefaultModel(isSelected? model: dummyModel);
-                            }
-
-                            selectorPanel.selectedComponentFactory = componentFactory;
-                            selectorPanel.selectedComponent = underlyingViews[underlyingViewNum];
-                            selectorPanel.onSelect(target);
-                            target.add(selectorPanel, views);
-                        }
-
-                        @Override
-                        protected void onComponentTag(ComponentTag tag) {
-                            super.onComponentTag(tag);
-                            Buttons.fixDisabledState(this, tag);
-                        }
-                    };
-
-                    IModel<String> title = nameFor(componentFactory);
-                    Label viewItemTitleLabel = new Label(ID_VIEW_ITEM_TITLE, title);
-                    link.add(viewItemTitleLabel);
-
-                    Label viewItemIcon = new Label(ID_VIEW_ITEM_ICON, "");
-                    link.add(viewItemIcon);
-
-                    boolean isEnabled = componentFactory != selectorPanel.selectedComponentFactory;
-                    if (!isEnabled) {
-                        viewButtonTitle.setDefaultModel(title);
-                        IModel<String> cssClass = cssClassFor(componentFactory, viewButtonIcon);
-                        viewButtonIcon.add(AttributeModifier.replace("class", "ViewLinkItem " + cssClass.getObject()));
-                        link.setVisible(false);
-                    } else {
-                        IModel<String> cssClass = cssClassFor(componentFactory, viewItemIcon);
-                        viewItemIcon.add(new CssClassAppender(cssClass));
-                    }
-
-                    item.add(link);
-                }
-
-                private IModel<String> cssClassFor(final ComponentFactory componentFactory, Label viewIcon) {
-                    IModel<String> cssClass = null;
-                    if (componentFactory instanceof CollectionContentsAsFactory) {
-                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
-                        cssClass = collectionContentsAsFactory.getCssClass();
-                        viewIcon.setDefaultModelObject("");
-                        viewIcon.setEscapeModelStrings(true);
-                    }
-                    if (cssClass == null) {
-                        String name = componentFactory.getName();
-                        cssClass = Model.of(StringExtensions.asLowerDashed(name));
-                        // Small hack: if there is no specific CSS class then we assume that background-image is used
-                        // the span.ViewItemLink should have some content to show it
-                        // FIX: find a way to do this with CSS (width and height don't seems to help)
-                        viewIcon.setDefaultModelObject("&#160;&#160;&#160;&#160;&#160;");
-                        viewIcon.setEscapeModelStrings(false);
-                    }
-                    return cssClass;
-                }
-
-                private IModel<String> nameFor(final ComponentFactory componentFactory) {
-                    IModel<String> name = null;
-                    if (componentFactory instanceof CollectionContentsAsFactory) {
-                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
-                        name = collectionContentsAsFactory.getTitleLabel();
-                    }
-                    if (name == null) {
-                        name = Model.of(componentFactory.getName());
-                    }
-                    return name;
-                }
-            };
-            container.add(listView);
-            addOrReplace(views);
+//            final WebMarkupContainer views = new WebMarkupContainer(ID_VIEWS);
+//
+//            final Label viewButtonTitle = new Label(ID_VIEW_BUTTON_TITLE, "Hidden");
+//            views.addOrReplace(viewButtonTitle);
+//
+//            final Label viewButtonIcon = new Label(ID_VIEW_BUTTON_ICON, "");
+//            views.addOrReplace(viewButtonIcon);
+//
+//            final WebMarkupContainer container = new WebMarkupContainer(ID_VIEW_LIST);
+//
+//            views.addOrReplace(container);
+//            views.setOutputMarkupId(true);
+//
+//            this.setOutputMarkupId(true);
+
+//            final ListView<ComponentFactory> listView = new ListView<ComponentFactory>(ID_VIEW_ITEM, componentFactories) {
+//
+//                private static final long serialVersionUID = 1L;
+//
+//                @Override
+//                protected void populateItem(ListItem<ComponentFactory> item) {
+//
+//                    final int underlyingViewNum = item.getIndex();
+//
+//                    final ComponentFactory componentFactory = item.getModelObject();
+//                    final AbstractLink link = new AjaxLink<Void>(ID_VIEW_LINK) {
+//                        private static final long serialVersionUID = 1L;
+//                        @Override
+//                        public void onClick(AjaxRequestTarget target) {
+//                            CollectionContentsLinksSelectorPanel linksSelectorPanel = CollectionContentsLinksSelectorPanel.this;
+//                            linksSelectorPanel.setViewHintAndBroadcast(underlyingViewNum, target);
+//
+//                            final EntityCollectionModel dummyModel = model.asDummy();
+//                            for(int i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
+//                                final Component component = underlyingViews[i];
+//                                if(component == null) {
+//                                    continue;
+//                                }
+//                                final boolean isSelected = i == underlyingViewNum;
+//                                applyCssVisibility(component, isSelected);
+//                                component.setDefaultModel(isSelected? model: dummyModel);
+//                            }
+//
+//                            selectorPanel.selectedComponentFactory = componentFactory;
+//                            selectorPanel.selectedComponent = underlyingViews[underlyingViewNum];
+//                            selectorPanel.onSelect(target);
+//                            target.add(selectorPanel, views);
+//                        }
+//
+//                        @Override
+//                        protected void onComponentTag(ComponentTag tag) {
+//                            super.onComponentTag(tag);
+//                            Buttons.fixDisabledState(this, tag);
+//                        }
+//                    };
+//
+//                    IModel<String> title = nameFor(componentFactory);
+//                    Label viewItemTitleLabel = new Label(ID_VIEW_ITEM_TITLE, title);
+//                    link.add(viewItemTitleLabel);
+//
+//                    Label viewItemIcon = new Label(ID_VIEW_ITEM_ICON, "");
+//                    link.add(viewItemIcon);
+//
+//                    boolean isEnabled = componentFactory != selectorPanel.selectedComponentFactory;
+//                    if (!isEnabled) {
+//                        viewButtonTitle.setDefaultModel(title);
+//                        IModel<String> cssClass = cssClassFor(componentFactory, viewButtonIcon);
+//                        viewButtonIcon.add(AttributeModifier.replace("class", "ViewLinkItem " + cssClass.getObject()));
+//                        link.setVisible(false);
+//                    } else {
+//                        IModel<String> cssClass = cssClassFor(componentFactory, viewItemIcon);
+//                        viewItemIcon.add(new CssClassAppender(cssClass));
+//                    }
+//
+//                    item.add(link);
+//                }
+//
+//                private IModel<String> cssClassFor(final ComponentFactory componentFactory, Label viewIcon) {
+//                    IModel<String> cssClass = null;
+//                    if (componentFactory instanceof CollectionContentsAsFactory) {
+//                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
+//                        cssClass = collectionContentsAsFactory.getCssClass();
+//                        viewIcon.setDefaultModelObject("");
+//                        viewIcon.setEscapeModelStrings(true);
+//                    }
+//                    if (cssClass == null) {
+//                        String name = componentFactory.getName();
+//                        cssClass = Model.of(StringExtensions.asLowerDashed(name));
+//                        // Small hack: if there is no specific CSS class then we assume that background-image is used
+//                        // the span.ViewItemLink should have some content to show it
+//                        // FIX: find a way to do this with CSS (width and height don't seems to help)
+//                        viewIcon.setDefaultModelObject("&#160;&#160;&#160;&#160;&#160;");
+//                        viewIcon.setEscapeModelStrings(false);
+//                    }
+//                    return cssClass;
+//                }
+//
+//                private IModel<String> nameFor(final ComponentFactory componentFactory) {
+//                    IModel<String> name = null;
+//                    if (componentFactory instanceof CollectionContentsAsFactory) {
+//                        CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
+//                        name = collectionContentsAsFactory.getTitleLabel();
+//                    }
+//                    if (name == null) {
+//                        name = Model.of(componentFactory.getName());
+//                    }
+//                    return name;
+//                }
+//            };
+//            container.add(listView);
+            addOrReplace(selectorDropdownPanel);
         }
 
         for(i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
@@ -271,50 +280,97 @@ public class CollectionContentsLinksSelectorPanel
         }
     }
 
+    @Override
+    public void onEvent(IEvent<?> event) {
+        super.onEvent(event);
 
-
-    protected void setViewHintAndBroadcast(int viewNum, AjaxRequestTarget target) {
-        final UiHintContainer uiHintContainer = getUiHintContainer();
-        if(uiHintContainer == null) {
+        final IsisUiHintEvent uiHintEvent = IsisEnvelopeEvent.openLetter(event, IsisUiHintEvent.class);
+        if(uiHintEvent == null) {
             return;
         }
-        uiHintContainer.setHint(CollectionContentsLinksSelectorPanel.this, UIHINT_VIEW, ""+viewNum);
-        send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
-    }
-
-    /**
-     * Iterates up the component hierarchy looking for a parent
-     * {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}, and if so adds to ajax target so that it'll
-     * be repainted.
-     *
-     * <p>
-     * Yeah, agreed, it's a little bit hacky doing it this way, because it bakes
-     * in knowledge that this component is created, somehow, by a parent {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}.
-     * Perhaps it could be refactored to use a more general purpose observer pattern?
-     *
-     * <p>
-     * In fact, I've since discovered that Wicket has an event bus, which is used by the
-     * {@link UiHintContainer hinting mechanism}.  So this ought to be relatively easy to do.
-     */
-    protected void onSelect(AjaxRequestTarget target) {
-        Component component = this;
-        while(component != null) {
-            if(component instanceof CollectionPanel) {
-                CollectionPanel collectionPanel = (CollectionPanel) component;
-                boolean hasCount = collectionPanel.hasCount();
-                if(hasCount) {
-                    collectionPanel.updateLabel(target);
-                }
-                if(additionalLinks != null) {
-                    applyCssVisibility(additionalLinks, hasCount);
+        final UiHintContainer uiHintContainer = uiHintEvent.getUiHintContainer();
+
+        int underlyingViewNum = 0;
+        String viewStr = uiHintContainer.getHint(this.selectorDropdownPanel, UIHINT_VIEW);
+        if(viewStr != null) {
+            try {
+                int view = Integer.parseInt(viewStr);
+                if(view >= 0 && view < componentFactories.size()) {
+                    underlyingViewNum = view;
                 }
-                return;
+            } catch(NumberFormatException ex) {
+                // ignore
+            }
+        }
+
+        final EntityCollectionModel dummyModel = getModel().asDummy();
+        for(int i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
+            final Component component = underlyingViews[i];
+            if(component == null) {
+                continue;
             }
-            component = component.getParent();
+            final boolean isSelected = i == underlyingViewNum;
+            applyCssVisibility(component, isSelected);
+            component.setDefaultModel(isSelected? getModel(): dummyModel);
+        }
+
+        this.selectedComponentFactory = componentFactory;
+        this.selectedComponent = underlyingViews[underlyingViewNum];
+
+
+        final AjaxRequestTarget target = uiHintEvent.getTarget();
+        if(target != null) {
+//            selectorDropdownPanel.onSelect(target);
+            target.add(this, selectorDropdownPanel);
         }
+
+
     }
 
 
+
+//    protected void setViewHintAndBroadcast(int viewNum, AjaxRequestTarget target) {
+//        final UiHintContainer uiHintContainer = getUiHintContainer();
+//        if(uiHintContainer == null) {
+//            return;
+//        }
+//        uiHintContainer.setHint(CollectionContentsLinksSelectorPanel.this, UIHINT_VIEW, ""+viewNum);
+//        send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
+//    }
+
+//    /**
+//     * Iterates up the component hierarchy looking for a parent
+//     * {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}, and if so adds to ajax target so that it'll
+//     * be repainted.
+//     *
+//     * <p>
+//     * Yeah, agreed, it's a little bit hacky doing it this way, because it bakes
+//     * in knowledge that this component is created, somehow, by a parent {@link org.apache.isis.viewer.wicket.ui.components.collection.CollectionPanel}.
+//     * Perhaps it could be refactored to use a more general purpose observer pattern?
+//     *
+//     * <p>
+//     * In fact, I've since discovered that Wicket has an event bus, which is used by the
+//     * {@link UiHintContainer hinting mechanism}.  So this ought to be relatively easy to do.
+//     */
+//    protected void onSelect(AjaxRequestTarget target) {
+//        Component component = this;
+//        while(component != null) {
+//            if(component instanceof CollectionPanel) {
+//                CollectionPanel collectionPanel = (CollectionPanel) component;
+//                boolean hasCount = collectionPanel.hasCount();
+//                if(hasCount) {
+//                    collectionPanel.updateLabel(target);
+//                }
+//                if(additionalLinks != null) {
+//                    applyCssVisibility(additionalLinks, hasCount);
+//                }
+//                return;
+//            }
+//            component = component.getParent();
+//        }
+//    }
+
+
     protected static void applyCssVisibility(final Component component, final boolean visible) {
         if(component == null) {
             return;
@@ -375,7 +431,7 @@ public class CollectionContentsLinksSelectorPanel
         ArrayList<ComponentFactory> otherFactories = Lists.newArrayList(Collections2.filter(componentFactories, new Predicate<ComponentFactory>() {
             @Override
             public boolean apply(final ComponentFactory input) {
-                return input != ignoreFactory;
+                return input != ignoreFactory && input.getClass() != CollectionContentsLinksSelectorPanelFactory.class;
             }
         }));
         return ordered(otherFactories);

http://git-wip-us.apache.org/repos/asf/isis/blob/70af3c32/example/application/todoapp/dom/src/main/java/dom/todo/ToDoItemContributions.java
----------------------------------------------------------------------
diff --git a/example/application/todoapp/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/application/todoapp/dom/src/main/java/dom/todo/ToDoItemContributions.java
index e30378c..1b758f8 100644
--- a/example/application/todoapp/dom/src/main/java/dom/todo/ToDoItemContributions.java
+++ b/example/application/todoapp/dom/src/main/java/dom/todo/ToDoItemContributions.java
@@ -159,6 +159,7 @@ public class ToDoItemContributions extends AbstractFactoryAndRepository {
     @NotInServiceMenu
     @ActionSemantics(Of.SAFE)
     @NotContributed(As.ACTION)
+    @Programmatic
     public List<ToDoItem> similarTo(final ToDoItem toDoItem) {
         final List<ToDoItem> similarToDoItems = allMatches(
                 new QueryDefault<ToDoItem>(ToDoItem.class,