You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/09/03 14:32:32 UTC
[41/87] [abbrv] [partial] isis git commit: ISIS-1194: moving the
wicket submodules to be direct children of core;
removing the isis-viewer-wicket parent pom.
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
new file mode 100644
index 0000000..c9429b5
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
@@ -0,0 +1,239 @@
+/*
+ * 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.bookmarkedpages;
+
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.models.BookmarkTreeNode;
+import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
+import org.apache.isis.viewer.wicket.model.models.ImageResourceCache;
+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.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+import org.apache.isis.viewer.wicket.ui.util.Links;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.head.CssHeaderItem;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.Image;
+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.AbstractReadOnlyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.CssResourceReference;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.string.Strings;
+
+import com.google.inject.Inject;
+
+public class BookmarkedPagesPanel extends PanelAbstract<BookmarkedPagesModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_BOOKMARK_LIST = "bookmarkList";
+ private static final String ID_BOOKMARKS_HELP_TEXT = "helpText";
+ private static final String ID_BOOKMARKED_PAGE_LINK = "bookmarkedPageLink";
+ private static final String ID_CLEAR_BOOKMARK_LINK = "clearBookmarkLink";
+ private static final String ID_BOOKMARKED_PAGE_ITEM = "bookmarkedPageItem";
+ private static final String ID_BOOKMARKED_PAGE_TITLE = "bookmarkedPageTitle";
+
+ private static final String ID_BOOKMARKED_PAGE_ICON = "bookmarkedPageImage";
+
+ private static final String CLEAR_BOOKMARKS = "clearBookmarks";
+
+
+ private static final JavaScriptResourceReference SLIDE_PANEL_JS = new JavaScriptResourceReference(BookmarkedPagesPanel.class, "slide-panel.js");
+
+ @Inject
+ private PageClassRegistry pageClassRegistry;
+
+ public BookmarkedPagesPanel(final String id, final BookmarkedPagesModel bookmarkedPagesModel) {
+ super(id, bookmarkedPagesModel);
+ buildGui();
+ }
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ super.renderHead(response);
+
+ response.render(OnDomReadyHeaderItem.forScript("$('.bookmarkRibbon').height($('.navbar.navbar-fixed-top').height()-5);"));
+ }
+
+ private void buildGui() {
+
+ final BookmarkedPagesModel bookmarkedPagesModel = getModel();
+
+ Component helpText = addHelpText(bookmarkedPagesModel);
+ addOrReplace(helpText);
+
+ final WebMarkupContainer container = new WebMarkupContainer(ID_BOOKMARK_LIST) {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ response.render(CssHeaderItem.forReference(new CssResourceReference(BookmarkedPagesPanel.class, "BookmarkedPagesPanel.css")));
+ response.render(JavaScriptReferenceHeaderItem.forReference(SLIDE_PANEL_JS));
+ }
+ };
+ // allow to be updated by AjaxLink
+ container.setOutputMarkupId(true);
+ add(container);
+
+ final AjaxLink<Void> clearAllBookmarksLink = new AjaxLink<Void>(CLEAR_BOOKMARKS){
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick(AjaxRequestTarget target) {
+ BookmarkedPagesPanel.this.getModel().clear();
+ setEnabled(false);
+ target.add(container, this);
+ }
+ };
+ clearAllBookmarksLink.setOutputMarkupId(true);
+ add(clearAllBookmarksLink);
+ clearAllBookmarksLink.setOutputMarkupId(true);
+
+ if(getModel().isEmpty()) {
+ clearAllBookmarksLink.setVisible(false);
+ }
+
+
+ final ListView<BookmarkTreeNode> listView = new ListView<BookmarkTreeNode>(ID_BOOKMARKED_PAGE_ITEM, bookmarkedPagesModel) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void populateItem(ListItem<BookmarkTreeNode> item) {
+ final BookmarkTreeNode node = item.getModelObject();
+ try {
+ final PageType pageType = node.getPageType();
+ final Class<? extends Page> pageClass = pageClassRegistry.getPageClass(pageType);
+
+ final AjaxLink<Object> clearBookmarkLink = new AjaxLink<Object>(ID_CLEAR_BOOKMARK_LINK) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick(AjaxRequestTarget target) {
+ bookmarkedPagesModel.remove(node);
+ if(bookmarkedPagesModel.isEmpty()) {
+ permanentlyHide(CLEAR_BOOKMARKS);
+ }
+ target.add(container, clearAllBookmarksLink);
+ }
+
+ };
+ if(node.getDepth() == 0) {
+ clearBookmarkLink.add(new CssClassAppender("clearBookmark"));
+ } else {
+ clearBookmarkLink.setEnabled(true);
+ }
+ item.add(clearBookmarkLink);
+
+ PageParameters pageParameters = node.getPageParameters();
+ final AbstractLink link = Links.newBookmarkablePageLink(ID_BOOKMARKED_PAGE_LINK, pageParameters, pageClass);
+
+ ObjectSpecification objectSpec = null;
+ RootOid oid = node.getOidNoVer();
+ if(oid != null) {
+ ObjectSpecId objectSpecId = oid.getObjectSpecId();
+ objectSpec = getSpecificationLoader().lookupBySpecId(objectSpecId);
+ }
+ final ResourceReference imageResource = imageCache.resourceReferenceForSpec(objectSpec);
+ final Image image = new Image(ID_BOOKMARKED_PAGE_ICON, imageResource) {
+ private static final long serialVersionUID = 1L;
+ @Override
+ protected boolean shouldAddAntiCacheParameter() {
+ return false;
+ }
+ };
+ link.addOrReplace(image);
+
+ String title = node.getTitle();
+ final Label label = new Label(ID_BOOKMARKED_PAGE_TITLE, title);
+ link.add(label);
+ item.add(link);
+ if(bookmarkedPagesModel.isCurrent(pageParameters)) {
+ item.add(new CssClassAppender("disabled"));
+ }
+ item.add(new CssClassAppender("bookmarkDepth" + node.getDepth()));
+ } catch(ObjectNotFoundException ex) {
+ // ignore
+ // this is a partial fix for an infinite redirect loop.
+ // should be a bit smarter here, though; see ISIS-596.
+ }
+
+ }
+ };
+ container.add(listView);
+ }
+
+ protected Component addHelpText(final BookmarkedPagesModel bookmarkedPagesModel) {
+
+ IModel<String> helpTextModel = new AbstractReadOnlyModel<String>() {
+ @Override
+ public String getObject() {
+ return bookmarkedPagesModel.isEmpty() ? "You have no bookmarks!" : "";
+ }
+ };
+
+ Label helpText = new Label(ID_BOOKMARKS_HELP_TEXT, helpTextModel) {
+ @Override
+ protected void onConfigure() {
+ super.onConfigure();
+
+ setVisible(!Strings.isEmpty(getDefaultModelObjectAsString()));
+ }
+ };
+ helpText.setOutputMarkupPlaceholderTag(true);
+ return helpText;
+ }
+
+ // ///////////////////////////////////////////////
+ // Dependency Injection
+ // ///////////////////////////////////////////////
+
+ @Inject
+ private ImageResourceCache imageCache;
+
+ protected ImageResourceCache getImageCache() {
+ return imageCache;
+ }
+
+
+ protected SpecificationLoaderSpi getSpecificationLoader() {
+ return IsisContext.getSpecificationLoader();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanelFactory.java
new file mode 100644
index 0000000..06378bc
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanelFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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.bookmarkedpages;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+public class BookmarkedPagesPanelFactory extends ComponentFactoryAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public BookmarkedPagesPanelFactory() {
+ super(ComponentType.BOOKMARKED_PAGES, BookmarkedPagesPanel.class);
+ }
+
+ @Override
+ public ApplicationAdvice appliesTo(final IModel<?> model) {
+ return appliesIf(model instanceof BookmarkedPagesModel);
+ }
+
+ @Override
+ public Component createComponent(final String id, final IModel<?> model) {
+ final BookmarkedPagesModel bookmarkedPagesModel = (BookmarkedPagesModel) model;
+ return new BookmarkedPagesPanel(id, bookmarkedPagesModel);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/images/clear_bookmarks.png
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/images/clear_bookmarks.png b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/images/clear_bookmarks.png
new file mode 100644
index 0000000..b798031
Binary files /dev/null and b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/images/clear_bookmarks.png differ
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/slide-panel.js
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/slide-panel.js b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/slide-panel.js
new file mode 100644
index 0000000..ca5bbac
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/slide-panel.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+$(function(){
+
+ 'use strict';
+
+ var showBookmarks = function(){
+ $('#bookmarkedPagesSlidingDiv').slideDown('50');
+ $('.bookmarkRibbon').fadeOut(50);
+ };
+
+ var hideBookmarks = function(){
+ $('#bookmarkedPagesSlidingDiv').slideUp('50');
+ $('.bookmarkRibbon').fadeIn(50);
+ };
+
+ var hideBookmarksQuickly = function() {
+ $('#bookmarkedPagesSlidingDiv').hide();
+ $('.bookmarkRibbon').show();
+ };
+
+ $('.bookmarkRibbon').mouseenter(showBookmarks);
+ $('#bookmarkedPagesSlidingDiv').mouseleave(hideBookmarks);
+
+ $('body').keydown(function(e) {
+ // alt+[
+ if(e.which === 219 && e.altKey) {
+ if($('#bookmarkedPagesSlidingDiv').is(":visible")) {
+ hideBookmarksQuickly();
+ } else {
+ showBookmarks();
+ }
+ } else if (e.which === 27) {
+ hideBookmarksQuickly();
+ }
+ });
+});
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.html
new file mode 100644
index 0000000..569d0a6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.html
@@ -0,0 +1,33 @@
+<?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="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"
+ xml:lang="en"
+ lang="en">
+ <body>
+ <wicket:panel>
+ <div class="collectionPanel collectionNameAndContentsComponentType">
+ <div class="collectionContents" wicket:id="collectionContents"></div>
+ <span wicket:id="feedback"></span>
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
new file mode 100644
index 0000000..1ae3b3b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
@@ -0,0 +1,130 @@
+/*
+ * 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.collection;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
+
+import java.util.List;
+import com.google.common.collect.Lists;
+import org.apache.wicket.Component;
+import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.runtime.system.DeploymentType;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.EntityActionUtil;
+import org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorPanel;
+import org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorProvider;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * Panel for rendering entity collection; analogous to (any concrete subclass
+ * of) {@link ScalarPanelAbstract}.
+ */
+public class CollectionPanel extends PanelAbstract<EntityCollectionModel> implements CollectionSelectorProvider {
+
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_FEEDBACK = "feedback";
+
+ private Component collectionContents;
+
+ private Label label;
+
+ public CollectionPanel(final String id, final EntityModel entityModel, OneToManyAssociation otma) {
+ this(id, newEntityCollectionModel(entityModel, otma), entityModel, otma);
+ }
+
+ private static EntityCollectionModel newEntityCollectionModel(final EntityModel entityModel, OneToManyAssociation otma) {
+ EntityCollectionModel collectionModel = EntityCollectionModel.createParented(entityModel, otma);
+ return collectionModel;
+ }
+
+ CollectionPanel(
+ final String id,
+ final EntityCollectionModel collectionModel) {
+ this(id, collectionModel, new EntityModel(collectionModel.getParentObjectAdapterMemento()), collectionModel.getCollectionMemento().getCollection());
+ }
+
+ CollectionPanel(
+ final String id,
+ final EntityCollectionModel collectionModel,
+ final EntityModel entityModel,
+ final OneToManyAssociation otma) {
+ super(id, collectionModel);
+
+ final List<LinkAndLabel> entityActionLinks = Lists.newArrayList();
+
+ final List<ObjectAction> associatedActions = EntityActionUtil.getObjectActionsForAssociation(entityModel, otma, getDeploymentType());
+
+ entityActionLinks.addAll(EntityActionUtil.asLinkAndLabelsForAdditionalLinksPanel(entityModel, associatedActions));
+
+ collectionModel.addEntityActions(entityActionLinks);
+ }
+
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
+ buildGui();
+ }
+
+ private void buildGui() {
+ collectionContents = getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.COLLECTION_CONTENTS, getModel());
+
+ addOrReplace(new NotificationPanel(ID_FEEDBACK, collectionContents, new ComponentFeedbackMessageFilter(collectionContents)));
+ }
+
+ public Label createLabel(final String id, final String collectionName) {
+ this.label = new Label(id, collectionName);
+ label.setOutputMarkupId(true);
+ return this.label;
+ }
+
+ //region > SelectorDropdownPanel (impl)
+
+ private CollectionSelectorPanel selectorDropdownPanel;
+
+ @Override
+ public CollectionSelectorPanel getSelectorDropdownPanel() {
+ return selectorDropdownPanel;
+ }
+ public void setSelectorDropdownPanel(CollectionSelectorPanel selectorDropdownPanel) {
+ this.selectorDropdownPanel = selectorDropdownPanel;
+ }
+ //endregion
+
+
+
+ //region > dependencies
+
+ protected DeploymentType getDeploymentType() {
+ return IsisContext.getDeploymentType();
+ }
+
+ //endregion
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanelFactory.java
new file mode 100644
index 0000000..9a9f6e2
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanelFactory.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.collection;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+/**
+ * {@link ComponentFactory} for {@link CollectionPanel}.
+ */
+public class CollectionPanelFactory extends ComponentFactoryAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String NAME = "labelled";
+
+ public CollectionPanelFactory() {
+ super(ComponentType.COLLECTION_NAME_AND_CONTENTS, NAME, CollectionPanel.class);
+ }
+
+ @Override
+ public ApplicationAdvice appliesTo(final IModel<?> model) {
+ if (!(model instanceof EntityCollectionModel)) {
+ return ApplicationAdvice.DOES_NOT_APPLY;
+ }
+ return ApplicationAdvice.APPLIES;
+ }
+
+ @Override
+ public Component createComponent(final String id, final IModel<?> model) {
+ final EntityCollectionModel collectionModel = (EntityCollectionModel) model;
+ return new CollectionPanel(id, collectionModel);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
new file mode 100644
index 0000000..b54a4d7
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
@@ -0,0 +1,102 @@
+/*
+ * 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.collection.bulk;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.isis.applib.filter.Filters;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+
+public class BulkActionsHelper implements Serializable {
+
+ private final EntityCollectionModel model;
+
+ private static final long serialVersionUID = 1L;
+
+ public BulkActionsHelper(final EntityCollectionModel model) {
+ this.model = model;
+ }
+
+ private EntityCollectionModel getModel() {
+ return model;
+ }
+
+ public List<ObjectAction> getBulkActions() {
+ final EntityCollectionModel model = getModel();
+
+ if(model.isParented()) {
+ return Collections.emptyList();
+ }
+
+ final ObjectSpecification typeSpec = model.getTypeOfSpecification();
+
+ List<ObjectAction> objectActions = typeSpec.getObjectActions(ActionType.USER, Contributed.INCLUDED, Filters.<ObjectAction>any());
+
+ if ( isExploring() || isPrototyping()) {
+ List<ObjectAction> explorationActions = typeSpec.getObjectActions(ActionType.EXPLORATION, Contributed.INCLUDED, Filters.<ObjectAction>any());
+ List<ObjectAction> prototypeActions = typeSpec.getObjectActions(ActionType.PROTOTYPE, Contributed.INCLUDED, Filters.<ObjectAction>any());
+ objectActions.addAll(explorationActions);
+ objectActions.addAll(prototypeActions);
+ }
+ if (isDebugMode()) {
+ List<ObjectAction> debugActions = typeSpec.getObjectActions(ActionType.DEBUG, Contributed.INCLUDED, Filters.<ObjectAction>any());
+ objectActions.addAll(debugActions);
+ }
+
+ List<ObjectAction> flattenedActions = objectActions;
+
+ return Lists.newArrayList(Iterables.filter(flattenedActions, BULK));
+ }
+
+
+ @SuppressWarnings("deprecation")
+ private static final Predicate<ObjectAction> BULK = Filters.asPredicate(ObjectAction.Filters.bulk());
+
+
+ //region > from context
+
+ public boolean isExploring() {
+ return IsisContext.getDeploymentType().isExploring();
+ }
+ public boolean isPrototyping() {
+ return IsisContext.getDeploymentType().isPrototyping();
+ }
+
+ /**
+ * Protected so can be overridden in testing if required.
+ */
+ protected boolean isDebugMode() {
+ // TODO: need to figure out how to switch into debug mode;
+ // probably call a Debug toggle page, and stuff into
+ // Session.getMetaData()
+ return true;
+ }
+
+ //endregion
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
new file mode 100644
index 0000000..941d3ea
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
@@ -0,0 +1,239 @@
+/*
+ * 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.collection.bulk;
+
+import java.util.List;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.services.actinvoc.ActionInvocationContext;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaPosition;
+import org.apache.isis.applib.annotation.InvokedOn;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.Command.Executor;
+import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.commons.authentication.MessageBroker;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.isis.viewer.wicket.model.mementos.ActionMemento;
+import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.ActionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponse;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseType;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
+import org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel.ActionLinkFactory;
+import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
+
+public final class BulkActionsLinkFactory implements ActionLinkFactory {
+
+ private static final long serialVersionUID = 1L;
+ private final EntityCollectionModel model;
+
+ private final ObjectAdapterToggleboxColumn toggleboxColumn;
+
+ public BulkActionsLinkFactory(
+ final EntityCollectionModel model,
+ final ObjectAdapterToggleboxColumn toggleboxColumn) {
+ this.model = model;
+ this.toggleboxColumn = toggleboxColumn;
+ }
+
+
+ @Override
+ public LinkAndLabel newLink(
+ final ObjectAdapterMemento objectAdapterMemento,
+ final ObjectAction objectAction,
+ final String linkId) {
+
+ final ActionMemento actionMemento = new ActionMemento(objectAction);
+ final AbstractLink link = new Link<Object>(linkId) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ final ObjectAction objectAction = actionMemento.getAction();
+ final ConcurrencyChecking concurrencyChecking =
+ ConcurrencyChecking.concurrencyCheckingFor(objectAction.getSemantics());
+
+ try {
+ final List<ObjectAdapterMemento> toggleMementosList = model.getToggleMementosList();
+
+ final Iterable<ObjectAdapter> toggledAdapters =
+ Iterables.transform(toggleMementosList, ObjectAdapterMemento.Functions.fromMemento(concurrencyChecking));
+
+ final List<Object> domainObjects = Lists.newArrayList(Iterables.transform(toggledAdapters, ObjectAdapter.Functions.getObject()));
+
+
+ final ActionInvocationContext actionInvocationContext = getServicesInjector().lookupService(ActionInvocationContext.class);
+ if (actionInvocationContext != null) {
+ actionInvocationContext.setInvokedOn(InvokedOn.COLLECTION);
+ actionInvocationContext.setDomainObjects(domainObjects);
+ }
+
+ final Bulk.InteractionContext bulkInteractionContext = getServicesInjector().lookupService(Bulk.InteractionContext.class);
+ if (bulkInteractionContext != null) {
+ bulkInteractionContext.setInvokedAs(Bulk.InteractionContext.InvokedAs.BULK);
+ bulkInteractionContext.setDomainObjects(domainObjects);
+ }
+
+ final CommandContext commandContext = getServicesInjector().lookupService(CommandContext.class);
+ final Command command;
+ if (commandContext != null) {
+ command = commandContext.getCommand();
+ command.setExecutor(Executor.USER);
+ }
+
+
+ ObjectAdapter lastReturnedAdapter = null;
+ int i=0;
+ for(final ObjectAdapter adapter : toggledAdapters) {
+
+ int numParameters = objectAction.getParameterCount();
+ if(numParameters != 0) {
+ return;
+ }
+ if (bulkInteractionContext != null) {
+ bulkInteractionContext.setIndex(i++);
+ }
+
+ lastReturnedAdapter = objectAction.executeWithRuleChecking(adapter, new ObjectAdapter[]{}, getAuthenticationSession(), ActionModel.WHERE_FOR_ACTION_INVOCATION);
+ }
+
+
+
+ model.clearToggleMementosList();
+ toggleboxColumn.clearToggles();
+ final ActionModel actionModelHint = model.getActionModelHint();
+ if(actionModelHint != null && actionModelHint.getActionMemento().getAction().getSemantics().isIdempotentInNature()) {
+ ObjectAdapter resultAdapter = actionModelHint.getObject();
+ model.setObjectList(resultAdapter);
+ } else {
+ model.setObject(persistentAdaptersWithin(model.getObject()));
+ }
+
+ if(lastReturnedAdapter != null) {
+ final ActionResultResponse resultResponse =
+ ActionResultResponseType.determineAndInterpretResult(actionModelHint, null, lastReturnedAdapter);
+ resultResponse.getHandlingStrategy().handleResults(this, resultResponse);
+ }
+
+ } catch(final ConcurrencyException ex) {
+
+ recover();
+ // display a warning to the user so that they know that the action wasn't performed
+ getMessageBroker().addWarning(ex.getMessage());
+ return;
+
+ } catch(final RuntimeException ex) {
+
+ final RecoverableException appEx = ActionModel.getApplicationExceptionIfAny(ex);
+ if (appEx != null) {
+
+ recover();
+
+ getMessageBroker().setApplicationError(appEx.getMessage());
+
+ // there's no need to abort the transaction, it will have already been done
+ // (in IsisTransactionManager#executeWithinTransaction(...)).
+ return;
+ }
+ throw ex;
+ }
+ }
+
+ private void recover() {
+ // resync with the objectstore
+ final List<ObjectAdapterMemento> toggleMementosList = Lists.newArrayList(model.getToggleMementosList());
+ for (ObjectAdapterMemento oam : toggleMementosList) {
+ // just requesting the adapter will sync the OAM's version with the objectstore
+ oam.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
+ }
+
+ // discard any adapters that might have been deleted
+ model.setObject(persistentAdaptersWithin(model.getObject()));
+
+ // attempt to preserve the toggled adapters
+ final List<ObjectAdapter> adapters = model.getObject();
+ model.clearToggleMementosList();
+ for (ObjectAdapterMemento oam : toggleMementosList) {
+ final ObjectAdapter objectAdapter = oam.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
+ if(adapters.contains(objectAdapter)) {
+ // in case it has been deleted...
+ model.toggleSelectionOn(objectAdapter);
+ }
+ }
+ }
+
+ private List<ObjectAdapter> persistentAdaptersWithin(List<ObjectAdapter> adapters) {
+ return Lists.newArrayList(Iterables.filter(adapters, new Predicate<ObjectAdapter>() {
+ @Override
+ public boolean apply(ObjectAdapter input) {
+ return !input.isTransient() && !input.isDestroyed();
+ }
+ }));
+ }
+
+ };
+ link.add(new JGrowlBehaviour());
+
+ final boolean explorationOrPrototype = ObjectAction.Utils.isExplorationOrPrototype(objectAction);
+ final String actionIdentifier = ObjectAction.Utils.actionIdentifierFor(objectAction);
+ final String description = ObjectAction.Utils.descriptionOf(objectAction);
+ final String cssClass = ObjectAction.Utils.cssClassFor(objectAction, null);
+ final String cssClassFa = ObjectAction.Utils.cssClassFaFor(objectAction);
+ final CssClassFaPosition cssClassFaPosition = ObjectAction.Utils.cssClassFaPositionFor(objectAction);
+ final ActionLayout.Position position = ObjectAction.Utils.actionLayoutPositionOf(objectAction);
+
+ return new LinkAndLabel(link, objectAction.getName(), null, description, false, explorationOrPrototype, actionIdentifier, cssClass, cssClassFa, cssClassFaPosition, position);
+ }
+
+
+ ///////////////////////////////////////////////////////
+ // Dependencies (from context)
+ ///////////////////////////////////////////////////////
+
+ public AuthenticationSession getAuthenticationSession() {
+ final AuthenticationSessionProvider asa = (AuthenticationSessionProvider) Session.get();
+ return asa.getAuthenticationSession();
+ }
+
+ protected MessageBroker getMessageBroker() {
+ return getAuthenticationSession().getMessageBroker();
+ }
+
+ protected ServicesInjector getServicesInjector() {
+ return IsisContext.getPersistenceSession().getServicesInjector();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsProvider.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsProvider.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsProvider.java
new file mode 100644
index 0000000..39f2b96
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.collection.bulk;
+
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
+
+public interface BulkActionsProvider {
+
+ void configureBulkActions(ObjectAdapterToggleboxColumn toggleboxColumn);
+
+ ObjectAdapterToggleboxColumn createToggleboxColumn();
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/count/CollectionCountProvider.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/count/CollectionCountProvider.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/count/CollectionCountProvider.java
new file mode 100644
index 0000000..0ff411f
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/count/CollectionCountProvider.java
@@ -0,0 +1,21 @@
+/**
+ * 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.collection.count;
+
+public interface CollectionCountProvider {
+ Integer getCount();
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
new file mode 100644
index 0000000..a600923
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
@@ -0,0 +1,169 @@
+/*
+ * 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.collection.selector;
+
+import java.io.Serializable;
+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.Component;
+import org.apache.wicket.model.IModel;
+import org.apache.isis.applib.annotation.Render;
+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.UiHintContainer;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.CollectionContentsAsAjaxTablePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.multiple.CollectionContentsMultipleViewsPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsAsUnresolvedPanelFactory;
+
+public class CollectionSelectorHelper implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ static final String UIHINT_EVENT_VIEW_KEY = "view";
+
+ private final EntityCollectionModel model;
+ private final List<ComponentFactory> componentFactories;
+
+ public CollectionSelectorHelper(
+ final EntityCollectionModel model,
+ final ComponentFactoryRegistry componentFactoryRegistry) {
+ this.model = model;
+ this.componentFactories = locateComponentFactories(componentFactoryRegistry);
+ }
+
+ private List<ComponentFactory> locateComponentFactories(ComponentFactoryRegistry componentFactoryRegistry) {
+ final List<ComponentFactory> componentFactories = componentFactoryRegistry.findComponentFactories(ComponentType.COLLECTION_CONTENTS, model);
+ List<ComponentFactory> otherFactories = Lists.newArrayList(Collections2.filter(componentFactories, new Predicate<ComponentFactory>() {
+ @Override
+ public boolean apply(final ComponentFactory input) {
+ return input.getClass() != CollectionContentsMultipleViewsPanelFactory.class;
+ }
+ }));
+ return ordered(otherFactories);
+ }
+
+ public List<ComponentFactory> getComponentFactories() {
+ return componentFactories;
+ }
+
+ public int honourViewHintElseDefault(final Component component) {
+ // honour hints ...
+ final UiHintContainer hintContainer = getUiHintContainer(component);
+ if(hintContainer != null) {
+ String viewStr = hintContainer.getHint(component, UIHINT_EVENT_VIEW_KEY);
+ 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();
+ if(hintContainer != null) {
+ hintContainer.setHint(component, UIHINT_EVENT_VIEW_KEY, ""+initialFactory);
+ // don't broadcast (no AjaxRequestTarget, still configuring initial setup)
+ }
+ return initialFactory;
+ }
+
+ //region > helpers
+
+ /**
+ * 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.
+ */
+ private int determineInitialFactory() {
+ 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 static List<ComponentFactory> ordered(List<ComponentFactory> componentFactories) {
+ return orderAjaxTableToEnd(componentFactories);
+ }
+
+ 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 UiHintContainer getUiHintContainer(final Component component) {
+ return UiHintContainer.Util.hintContainerOf(component, EntityModel.class);
+ }
+
+
+ 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() == Render.Type.EAGERLY;
+ }
+
+ //endregion
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.html
new file mode 100644
index 0000000..8bec51a
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.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-sm btn-info">
+ <span wicket:id="viewButtonIcon" class="ViewLinkItem"></span>
+ <span wicket:id="viewButtonTitle" class="ViewLinkItemTitle"></span>
+ </button>
+ <button type="button" class="btn btn-sm 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/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
new file mode 100644
index 0000000..02aa720
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.collection.selector;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
+
+import java.util.List;
+import org.apache.wicket.AttributeModifier;
+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.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.core.commons.lang.StringExtensions;
+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.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+/**
+ * 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 CollectionSelectorPanel
+ extends PanelAbstract<EntityCollectionModel> implements UiHintPathSignificant {
+
+ private static final long serialVersionUID = 1L;
+
+ 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_VIEW_BUTTON_TITLE = "viewButtonTitle";
+ private static final String ID_VIEW_BUTTON_ICON = "viewButtonIcon";
+
+ private final CollectionSelectorHelper selectorHelper;
+
+ private ComponentFactory selectedComponentFactory;
+
+ public CollectionSelectorPanel(final String id, final EntityCollectionModel model) {
+ super(id, model);
+ selectorHelper = new CollectionSelectorHelper(model, getComponentFactoryRegistry());
+ }
+
+ /**
+ * Build UI only after added to parent.
+ */
+ public void onInitialize() {
+ super.onInitialize();
+ addDropdown();
+ }
+
+
+
+ private void addDropdown() {
+ final List<ComponentFactory> componentFactories = selectorHelper.getComponentFactories();
+ final int selected = selectorHelper.honourViewHintElseDefault(this);
+
+ // selector
+ if (componentFactories.size() <= 1) {
+ permanentlyHide(ID_VIEWS);
+ } else {
+ final Model<ComponentFactory> componentFactoryModel = new Model<>();
+
+ this.selectedComponentFactory = componentFactories.get(selected);
+ componentFactoryModel.setObject(this.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) {
+ CollectionSelectorPanel linksSelectorPanel = CollectionSelectorPanel.this;
+ linksSelectorPanel.setViewHintAndBroadcast(underlyingViewNum, target);
+
+ linksSelectorPanel.selectedComponentFactory = componentFactory;
+ target.add(linksSelectorPanel, 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 != CollectionSelectorPanel.this.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("     ");
+ 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);
+ }
+ }
+
+
+ protected void setViewHintAndBroadcast(int viewNum, AjaxRequestTarget target) {
+ final UiHintContainer uiHintContainer = getUiHintContainer(getModel().isParented()? EntityModel.class: EntityCollectionModel.class);
+ if(uiHintContainer == null) {
+ return;
+ }
+ uiHintContainer.setHint(CollectionSelectorPanel.this, CollectionSelectorHelper.UIHINT_EVENT_VIEW_KEY, ""+viewNum);
+ send(getPage(), Broadcast.EXACT, new IsisUiHintEvent(uiHintContainer, target));
+ }
+}
+
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorProvider.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorProvider.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorProvider.java
new file mode 100644
index 0000000..340cad2
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorProvider.java
@@ -0,0 +1,46 @@
+/*
+ * 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.collection.selector;
+
+import org.apache.wicket.Component;
+
+public interface CollectionSelectorProvider {
+ CollectionSelectorPanel getSelectorDropdownPanel();
+
+ public static class Util {
+
+ /**
+ * Searches up the component hierarchy looking for a parent that implements
+ * {@link org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorProvider}.
+ *
+ * @return the panel, or null (if there are no alternative views)
+ */
+ public static CollectionSelectorPanel getCollectionSelectorProvider(Component component) {
+ while(component != null) {
+ if(component instanceof CollectionSelectorProvider) {
+ final CollectionSelectorPanel selectorDropdownPanelIfAny = ((CollectionSelectorProvider) component).getSelectorDropdownPanel();
+ return selectorDropdownPanelIfAny;
+ }
+ component = component.getParent();
+ }
+ throw new IllegalStateException("Could not locate parent that implements CollectionSelectorProvider");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/UNUSED_CollectionSelectorPanel.css
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/UNUSED_CollectionSelectorPanel.css b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/UNUSED_CollectionSelectorPanel.css
new file mode 100644
index 0000000..8c3902e
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/UNUSED_CollectionSelectorPanel.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/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.html
new file mode 100644
index 0000000..cf45f34
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.html
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html xmlns:wicket="http://wicket.apache.org">
+ <body>
+ <wicket:panel>
+ <div class="collectionContentsAsAjaxTablePanel collectionContentsComponentType">
+ <div class="clearfix"></div>
+ <div class="table-responsive">
+ <table class="contents table table-striped table-condensed table-hover table-bordered" cellspacing="0" wicket:id="table">[table]</table>
+ </div>
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/99094b7e/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
new file mode 100644
index 0000000..a589269
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import java.util.List;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.Model;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.filter.Filters;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
+import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.wicket.model.common.OnConcurrencyExceptionHandler;
+import org.apache.isis.viewer.wicket.model.hints.UiHintPathSignificant;
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.ui.components.collection.bulk.BulkActionsProvider;
+import org.apache.isis.viewer.wicket.ui.components.collection.count.CollectionCountProvider;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ColumnAbstract;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterPropertyColumn;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterTitleColumn;
+import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * {@link PanelAbstract Panel} that represents a {@link EntityCollectionModel
+ * collection of entity}s rendered using {@link AjaxFallbackDefaultDataTable}.
+ */
+public class CollectionContentsAsAjaxTablePanel extends PanelAbstract<EntityCollectionModel> implements CollectionCountProvider , UiHintPathSignificant {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_TABLE = "table";
+
+ private IsisAjaxFallbackDataTable<ObjectAdapter,String> dataTable;
+
+
+ public CollectionContentsAsAjaxTablePanel(final String id, final EntityCollectionModel model) {
+ super(id, model);
+ }
+
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
+ buildGui();
+ }
+
+ private void buildGui() {
+
+ final List<IColumn<ObjectAdapter,String>> columns = Lists.newArrayList();
+
+ // bulkactions
+ final BulkActionsProvider bulkActionsProvider = getBulkActionsProvider();
+
+ ObjectAdapterToggleboxColumn toggleboxColumn = null;
+ if(bulkActionsProvider != null) {
+
+ toggleboxColumn = bulkActionsProvider.createToggleboxColumn();
+ if(toggleboxColumn != null) {
+ columns.add(toggleboxColumn);
+ }
+ bulkActionsProvider.configureBulkActions(toggleboxColumn);
+ }
+
+ final EntityCollectionModel model = getModel();
+ addTitleColumn(columns, model.getParentObjectAdapterMemento(), getSettings().getMaxTitleLengthInStandaloneTables(), getSettings().getMaxTitleLengthInStandaloneTables());
+ addPropertyColumnsIfRequired(columns);
+
+ final SortableDataProvider<ObjectAdapter,String> dataProvider = new CollectionContentsSortableDataProvider(model);
+ dataTable = new IsisAjaxFallbackDataTable<>(ID_TABLE, columns, dataProvider, model.getPageSize());
+ addOrReplace(dataTable);
+ dataTable.honourHints();
+
+ if(toggleboxColumn != null) {
+ final OnConcurrencyExceptionHandler handler2 = new OnConcurrencyExceptionHandler() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onConcurrencyException(
+ final Component context,
+ final ObjectAdapter selectedAdapter,
+ final ConcurrencyException ex,
+ final AjaxRequestTarget ajaxRequestTarget) {
+
+ // this causes the row to be repainted
+ // but it isn't possible (yet) to raise any warning
+ // because that only gets flushed on page refresh.
+ //
+
+ // perhaps something to tackle in a separate ticket....
+ ajaxRequestTarget.add(dataTable);
+ }
+ };
+ toggleboxColumn.setOnConcurrencyExceptionHandler(handler2);
+ }
+ }
+
+ private BulkActionsProvider getBulkActionsProvider() {
+ Component component = this;
+ while(component != null) {
+ if(component instanceof BulkActionsProvider) {
+ return (BulkActionsProvider) component;
+ }
+ component = component.getParent();
+ }
+ return null;
+ }
+
+
+
+ private void addTitleColumn(final List<IColumn<ObjectAdapter,String>> columns, ObjectAdapterMemento parentAdapterMementoIfAny, int maxTitleParented, int maxTitleStandalone) {
+ int maxTitleLength = getModel().isParented()? maxTitleParented: maxTitleStandalone;
+ columns.add(new ObjectAdapterTitleColumn(parentAdapterMementoIfAny, maxTitleLength));
+ }
+
+ private void addPropertyColumnsIfRequired(final List<IColumn<ObjectAdapter,String>> columns) {
+ final ObjectSpecification typeOfSpec = getModel().getTypeOfSpecification();
+
+ final Where whereContext =
+ getModel().isParented()
+ ? Where.PARENTED_TABLES
+ : Where.STANDALONE_TABLES;
+
+ final ObjectSpecification parentSpecIfAny =
+ getModel().isParented()
+ ? getModel().getParentObjectAdapterMemento().getObjectAdapter(ConcurrencyChecking.NO_CHECK).getSpecification()
+ : null;
+
+ @SuppressWarnings("unchecked")
+ final Filter<ObjectAssociation> filter = Filters.and(
+ ObjectAssociation.Filters.PROPERTIES,
+ ObjectAssociation.Filters.staticallyVisible(whereContext),
+ associationDoesNotReferenceParent(parentSpecIfAny));
+
+ final List<? extends ObjectAssociation> propertyList = typeOfSpec.getAssociations(Contributed.INCLUDED, filter);
+ for (final ObjectAssociation property : propertyList) {
+ final ColumnAbstract<ObjectAdapter> nopc = createObjectAdapterPropertyColumn(property);
+ columns.add(nopc);
+ }
+ }
+
+ static Filter<ObjectAssociation> associationDoesNotReferenceParent(final ObjectSpecification parentSpec) {
+ if(parentSpec == null) {
+ return Filters.any();
+ }
+ return new Filter<ObjectAssociation>() {
+ @Override
+ public boolean accept(ObjectAssociation association) {
+ final HiddenFacet facet = association.getFacet(HiddenFacet.class);
+ if(facet == null) {
+ return true;
+ }
+ if (facet.where() != Where.REFERENCES_PARENT) {
+ return true;
+ }
+ final ObjectSpecification assocSpec = association.getSpecification();
+ final boolean associationSpecIsOfParentSpec = parentSpec.isOfType(assocSpec);
+ final boolean isVisible = !associationSpecIsOfParentSpec;
+ return isVisible;
+ }
+ };
+ }
+
+ private ObjectAdapterPropertyColumn createObjectAdapterPropertyColumn(final ObjectAssociation property) {
+
+ final NamedFacet facet = property.getFacet(NamedFacet.class);
+ final boolean escaped = facet == null || facet.escaped();
+
+ return new ObjectAdapterPropertyColumn(Model.of(property.getName()), property.getId(), property.getId(), escaped);
+ }
+
+
+
+ @Override
+ protected void onModelChanged() {
+ buildGui();
+ }
+
+ @Override
+ public Integer getCount() {
+ final EntityCollectionModel model = getModel();
+ return model.getCount();
+ }
+
+
+ //region > dependencies
+
+ @Inject
+ private WicketViewerSettings settings;
+ protected WicketViewerSettings getSettings() {
+ return settings;
+ }
+
+ //endregion
+
+}