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 2016/02/02 01:36:03 UTC
[06/15] isis git commit: ISIS-993: bootstrap3 layout working,
more or less. Still need to do the normalization phase.
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.html
deleted file mode 100644
index 6699518..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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 wicket:id="tabGroups">
- <div wicket:id="tabGroup">[tabbed panel will be here]</div>
- </div>
-</wicket:panel>
-</body>
-</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.java
deleted file mode 100644
index 7a07082..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupListPanel.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.layout.fixedcols;
-
-import java.util.List;
-
-import org.apache.wicket.markup.html.list.ListItem;
-import org.apache.wicket.markup.html.list.ListView;
-
-import org.apache.isis.applib.layout.fixedcols.FCTabGroup;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
-
-public class TabGroupListPanel extends PanelAbstract<EntityModel> {
-
- private static final long serialVersionUID = 1L;
-
- private static final String ID_TAB_GROUPS = "tabGroups";
-
- // the view metadata
- private final List<FCTabGroup> tabGroups;
-
- public TabGroupListPanel(final String id, final EntityModel entityModel) {
- super(id, entityModel);
-
- this.tabGroups = (List<FCTabGroup>) entityModel.getLayoutMetadata();
-
- buildGui();
- }
-
- private void buildGui() {
- final EntityModel model = getModel();
-
- final ListView<FCTabGroup> tabGroupsList = new ListView<FCTabGroup>(ID_TAB_GROUPS, this.tabGroups) {
-
- @Override
- protected void populateItem(final ListItem<FCTabGroup> item) {
-
- final FCTabGroup tabGroup = item.getModelObject();
- final EntityModel entityModelWithHints = model.cloneWithLayoutMetadata(tabGroup);
- final TabGroupPanel tabGroupPanel = new TabGroupPanel(entityModelWithHints);
- item.add(tabGroupPanel);
- }
- };
-
- add(tabGroupsList);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupPanel.java
deleted file mode 100644
index d0fe9a0..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabGroupPanel.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.layout.fixedcols;
-
-import java.util.List;
-
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Lists;
-
-import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
-import org.apache.wicket.extensions.markup.html.tabs.ITab;
-import org.apache.wicket.extensions.markup.html.tabs.TabbedPanel;
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.Model;
-
-import org.apache.isis.applib.layout.fixedcols.FCTab;
-import org.apache.isis.applib.layout.fixedcols.FCTabGroup;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
-import org.apache.isis.viewer.wicket.model.util.ScopedSessionAttribute;
-
-import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
-
-public class TabGroupPanel extends AjaxBootstrapTabbedPanel {
-
- public static final String SESSION_ATTR_SELECTED_TAB = "selectedTab";
- private final EntityModel entityModel;
- // the view metadata
- private final FCTabGroup tabGroup;
- private final ScopedSessionAttribute<Integer> selectedTabInSession;
-
- private static final String ID_TAB_GROUP = "tabGroup";
-
- private static List<ITab> tabsFor(final EntityModel entityModel) {
- final List<ITab> tabs = Lists.newArrayList();
-
- final FCTabGroup tabGroup = (FCTabGroup) entityModel.getLayoutMetadata();
- final List<FCTab> FCTabList = FluentIterable
- .from(tabGroup.getTabs())
- .filter(FCTab.Predicates.notEmpty())
- .toList();
-
- for (final FCTab FCTab : FCTabList) {
- tabs.add(new AbstractTab(Model.of(FCTab.getName())) {
- private static final long serialVersionUID1 = 1L;
-
- @Override
- public Panel getPanel(String panelId) {
- return new TabPanel(panelId, entityModel, FCTab);
- }
- });
- }
- return tabs;
- }
-
- public TabGroupPanel(final EntityModel entityModel) {
- super(ID_TAB_GROUP, tabsFor(entityModel));
-
- this.entityModel = entityModel;
- this.tabGroup = (FCTabGroup) entityModel.getLayoutMetadata();
- this.selectedTabInSession = ScopedSessionAttribute.create(entityModel, this, SESSION_ATTR_SELECTED_TAB);
-
- }
-
- @Override
- protected void onInitialize() {
- setSelectedTabFromSessionIfAny(this);
- super.onInitialize();
- }
-
- @Override
- public TabbedPanel setSelectedTab(final int index) {
- selectedTabInSession.set(index);
- return super.setSelectedTab(index);
- }
-
- private void setSelectedTabFromSessionIfAny(
- final AjaxBootstrapTabbedPanel ajaxBootstrapTabbedPanel) {
- final Integer tabIndex = selectedTabInSession.get();
- if (tabIndex != null) {
- final int numTabs = ajaxBootstrapTabbedPanel.getTabs().size();
- if (tabIndex < numTabs) {
- // to support dynamic reloading; the data in the session might not be compatible with current layout.
- ajaxBootstrapTabbedPanel.setSelectedTab(tabIndex);
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.html
deleted file mode 100644
index 111fc68..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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="tabPanel">
- <form class="inputForm" role="form">
- <div wicket:id="column">
- </div>
- </form>
- </div>
-</wicket:panel>
-</body>
-</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.java
deleted file mode 100644
index 70dcb03..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/TabPanel.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.apache.isis.viewer.wicket.ui.components.layout.fixedcols;
-
-import org.apache.isis.applib.layout.fixedcols.FCTab;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
-import org.apache.isis.viewer.wicket.ui.ComponentType;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
-
-public class TabPanel extends PanelAbstract {
-
- private static final long serialVersionUID = 1L;
-
- private static final String ID_COLUMN = "column";
-
- public TabPanel(String id, final EntityModel model, final FCTab FCTab) {
- super(id);
-
- final EntityModel modelWithTabHints = model.cloneWithLayoutMetadata(FCTab);
-
- getComponentFactoryRegistry()
- .addOrReplaceComponent(this,
- ID_COLUMN, ComponentType.ENTITY_PROPERTIES, modelWithTabHints);
-
- }
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.html
new file mode 100644
index 0000000..0e03ea9
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.html
@@ -0,0 +1,32 @@
+<?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="entityCollectionsPanel entityCollectionsComponentType">
+ <div wicket:id="collections">
+ <div wicket:id="collection">
+ [collection]
+ </div>
+ </div>
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.java
new file mode 100644
index 0000000..21c2ed0
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanel.java
@@ -0,0 +1,151 @@
+/*
+ * 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.layout.fixedcols.collections;
+
+import java.util.Comparator;
+import java.util.List;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.repeater.RepeatingView;
+
+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.applib.layout.common.CollectionLayoutData;
+import org.apache.isis.applib.layout.fixedcols.FCColumn;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.services.DeweyOrderComparator;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.entity.collection.EntityCollectionPanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * {@link PanelAbstract Panel} representing the properties of an entity, as per
+ * the provided {@link EntityModel}.
+ */
+public class EntityCollectionsPanel extends PanelAbstract<EntityModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_ENTITY_COLLECTIONS = "entityCollections";
+ private static final String ID_COLLECTIONS = "collections";
+ private static final String ID_COLLECTION = "collection";
+
+ // view metadata (if any available)
+ private final FCColumn fcColumnIfAny;
+
+ public EntityCollectionsPanel(final String id, final EntityModel entityModel) {
+ super(id, entityModel);
+
+ fcColumnIfAny = (FCColumn) entityModel.getLayoutMetadata();
+
+ buildGui();
+ }
+
+ private void buildGui() {
+ buildEntityPropertiesAndOrCollectionsGui();
+ setOutputMarkupId(true); // so can repaint via ajax
+ }
+
+ private void buildEntityPropertiesAndOrCollectionsGui() {
+ final EntityModel model = getModel();
+ final ObjectAdapter adapter = model.getObject();
+ if (adapter != null) {
+ addCollections();
+ } else {
+ permanentlyHide(ID_ENTITY_COLLECTIONS);
+ }
+ }
+
+ private void addCollections() {
+ final EntityModel entityModel = getModel();
+ final ObjectAdapter adapter = entityModel.getObject();
+
+ final Filter<ObjectAssociation> filter;
+ if (fcColumnIfAny != null) {
+ final ImmutableList<String> collectionIds = FluentIterable
+ .from(fcColumnIfAny.getCollections())
+ .transform(CollectionLayoutData.Functions.id())
+ .toList();
+ filter = new Filter<ObjectAssociation>() {
+ @Override
+ public boolean accept(final ObjectAssociation objectAssociation) {
+ return collectionIds.contains(objectAssociation.getId());
+ }
+ };
+ } else {
+ filter = Filters.any();
+ }
+
+ final List<ObjectAssociation> associations = visibleCollections(adapter, filter);
+ associations.sort(new Comparator<ObjectAssociation>() {
+ private final DeweyOrderComparator deweyOrderComparator = new DeweyOrderComparator();
+ @Override
+ public int compare(final ObjectAssociation o1, final ObjectAssociation o2) {
+ final MemberOrderFacet o1Facet = o1.getFacet(MemberOrderFacet.class);
+ final MemberOrderFacet o2Facet = o2.getFacet(MemberOrderFacet.class);
+ return o1Facet == null? +1:
+ o2Facet == null? -1:
+ deweyOrderComparator.compare(o1Facet.sequence(), o2Facet.sequence());
+ }
+ });
+
+ final RepeatingView collectionRv = new RepeatingView(ID_COLLECTIONS);
+ add(collectionRv);
+
+ for (final ObjectAssociation association : associations) {
+
+ final WebMarkupContainer collectionRvContainer = new WebMarkupContainer(collectionRv.newChildId());
+ collectionRv.add(collectionRvContainer);
+
+ final CollectionLayoutData collectionLayoutData = new CollectionLayoutData(association.getId());
+ final EntityModel entityModelWithCollectionLayoutMetadata =
+ entityModel.cloneWithLayoutMetadata(collectionLayoutData);
+
+ collectionRvContainer.add(new EntityCollectionPanel(ID_COLLECTION, entityModelWithCollectionLayoutMetadata));
+ }
+ }
+
+ private static List<ObjectAssociation> visibleCollections(
+ final ObjectAdapter adapter,
+ final Filter<ObjectAssociation> filter) {
+ return adapter.getSpecification().getAssociations(
+ Contributed.INCLUDED, visibleCollectionsFilter(adapter, filter));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Filter<ObjectAssociation> visibleCollectionsFilter(
+ final ObjectAdapter adapter,
+ final Filter<ObjectAssociation> filter) {
+ return Filters.and(
+ ObjectAssociation.Filters.COLLECTIONS,
+ ObjectAssociation.Filters.dynamicallyVisible(
+ adapter, InteractionInitiatedBy.USER, Where.PARENTED_TABLES),
+ filter);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanelFactory.java
new file mode 100644
index 0000000..797720b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/collections/EntityCollectionsPanelFactory.java
@@ -0,0 +1,49 @@
+/*
+ * 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.layout.fixedcols.collections;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+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.components.entity.EntityComponentFactoryAbstract;
+
+/**
+ * {@link ComponentFactory} for {@link EntityCollectionsPanel}.
+ */
+public class EntityCollectionsPanelFactory extends EntityComponentFactoryAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public EntityCollectionsPanelFactory() {
+ super(ComponentType.ENTITY_COLLECTIONS, EntityCollectionsPanel.class);
+ }
+
+ @Override
+ public Component createComponent(final String id, final IModel<?> model) {
+ final EntityModel entityModel = (EntityModel) model;
+ return new EntityCollectionsPanel(id, entityModel);
+ }
+}
+
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.html
new file mode 100644
index 0000000..44e3a23
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.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="columnMembers">
+ <div class="inputFormTable properties">
+ <div wicket:id="propertyGroup">[propertyGroup]</div>
+ </div>
+ <div wicket:id="collections"></div>
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.java
new file mode 100644
index 0000000..cfb9bfa
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/columns/EntityColumn.java
@@ -0,0 +1,190 @@
+/*
+ * 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.layout.fixedcols.columns;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.repeater.RepeatingView;
+
+import org.apache.isis.applib.layout.common.FieldSet;
+import org.apache.isis.applib.layout.common.PropertyLayoutData;
+import org.apache.isis.applib.layout.fixedcols.FCColumn;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.ObjectSpecifications;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.system.DeploymentType;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+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.layout.fixedcols.PropUtil;
+import org.apache.isis.viewer.wicket.ui.components.entity.fieldset.PropertyGroup;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.Components;
+
+/**
+ * Adds properties (in property groups) and collections to a column.
+ *
+ * <p>
+ * If {@link FCColumn} is present, then only those properties and collections for that
+ * column metadata are rendered. Otherwise the {@link MemberGroupLayoutFacet} on the
+ * {@link ObjectSpecification} in conjunction with the provided {@link FCColumn.Hint} is
+ * used to filter down to just those properties/collections in the column.
+ * </p>
+ */
+public class EntityColumn extends PanelAbstract<EntityModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_PROPERTY_GROUP = "propertyGroup";
+
+
+ // view metadata (populated for EntityTabbedPanel, absent for EntityEditablePanel)
+ private final FCColumn columnMetaDataIfAny;
+
+ // which column to render (populated for EntityEditablePanel, not required and so absent for EntityTabbedPanel)
+ final FCColumn.Hint hint;
+
+ private static FCColumn.Hint hintFrom(final EntityModel entityModel) {
+ final FCColumn fcColumn = (FCColumn) entityModel.getLayoutMetadata();
+ return fcColumn.getHint();
+ }
+
+
+ public EntityColumn(
+ final String id,
+ final EntityModel entityModel) {
+
+ this(id, entityModel, hintFrom(entityModel));
+ }
+
+ public EntityColumn(
+ final String id,
+ final EntityModel entityModel,
+ final FCColumn.Hint hint) {
+
+ super(id, entityModel);
+
+ columnMetaDataIfAny = (FCColumn) entityModel.getLayoutMetadata();
+ this.hint = hint;
+
+ buildGui();
+ }
+
+ private void buildGui() {
+ addPropertiesAndCollections(this, getModel());
+ }
+
+ private void addPropertiesAndCollections(
+ final MarkupContainer col,
+ final EntityModel entityModel) {
+ addPropertiesInColumn(col, entityModel);
+ addCollectionsIfRequired(col, entityModel);
+ }
+
+ private void addPropertiesInColumn(
+ final MarkupContainer markupContainer,
+ final EntityModel entityModel) {
+
+ final ObjectAdapter adapter = entityModel.getObject();
+ final ObjectSpecification objSpec = adapter.getSpecification();
+
+ final Map<String, List<ObjectAssociation>> associationsByGroup = PropUtil.propertiesByMemberOrder(adapter);
+
+ final RepeatingView memberGroupRv = new RepeatingView(ID_PROPERTY_GROUP);
+ markupContainer.add(memberGroupRv);
+
+ final ImmutableMap<String, FieldSet> propertyGroupMetadataByNameIfAny =
+ columnMetaDataIfAny != null
+ ? Maps.uniqueIndex(columnMetaDataIfAny.getFieldSets(), FieldSet.Util.nameOf())
+ : null;
+
+ final Collection<String> groupNames =
+ propertyGroupMetadataByNameIfAny != null
+ ? propertyGroupMetadataByNameIfAny.keySet()
+ : ObjectSpecifications.orderByMemberGroups(objSpec, associationsByGroup.keySet(), hint);
+
+ for(final String groupName: groupNames) {
+
+
+ final FieldSet fieldSet;
+ if (propertyGroupMetadataByNameIfAny != null) {
+ fieldSet = propertyGroupMetadataByNameIfAny.get(groupName);
+ }
+ else {
+ final List<ObjectAssociation> associationsInGroup = associationsByGroup.get(groupName);
+ fieldSet = new FieldSet(groupName);
+ fieldSet.setProperties(
+ FluentIterable
+ .from(associationsInGroup)
+ .transform(
+ new Function<ObjectAssociation, PropertyLayoutData>() {
+ @Override
+ public PropertyLayoutData apply(final ObjectAssociation assoc) {
+ return new PropertyLayoutData(assoc.getId());
+ }
+ }).toList());
+ }
+
+ if(fieldSet.getProperties().isEmpty()) {
+ continue;
+ }
+
+ final String id = memberGroupRv.newChildId();
+
+ final EntityModel entityModelWithHints = entityModel.cloneWithLayoutMetadata(fieldSet);
+ final WebMarkupContainer memberGroupRvContainer = new PropertyGroup(id, entityModelWithHints);
+
+ memberGroupRv.add(memberGroupRvContainer);
+ }
+ }
+
+ private void addCollectionsIfRequired(
+ final MarkupContainer column,
+ final EntityModel entityModel) {
+
+ if(columnMetaDataIfAny != null) {
+ getComponentFactoryRegistry()
+ .addOrReplaceComponent(column, "collections", ComponentType.ENTITY_COLLECTIONS, entityModel);
+ } else {
+ Components.permanentlyHide(column, "collections");
+ }
+ }
+
+
+
+ ///////////////////////////////////////////////////////
+ // Dependencies (from context)
+ ///////////////////////////////////////////////////////
+
+ protected DeploymentType getDeploymentType() {
+ return IsisContext.getDeploymentType();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.java
new file mode 100644
index 0000000..f1f2a78
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.java
@@ -0,0 +1,710 @@
+/*
+ * 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.layout.fixedcols.propsandcolls;
+
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
+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.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
+
+import org.apache.isis.applib.annotation.MemberGroupLayout.ColumnSpans;
+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.applib.layout.fixedcols.FCColumn;
+import org.apache.isis.applib.layout.fixedcols.FCColumn.Hint;
+import org.apache.isis.applib.layout.fixedcols.FCTab;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
+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.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+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.core.runtime.memento.Memento;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+import org.apache.isis.viewer.wicket.model.models.ActionPrompt;
+import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.PropUtil;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.columns.EntityColumn;
+import org.apache.isis.viewer.wicket.ui.components.widgets.formcomponent.CancelHintRequired;
+import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
+import org.apache.isis.viewer.wicket.ui.panels.FormAbstract;
+import org.apache.isis.viewer.wicket.ui.panels.IFormSubmitterWithPreValidateHook;
+import org.apache.isis.viewer.wicket.ui.util.Components;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
+import de.agilecoders.wicket.core.util.Attributes;
+
+public class EntityPropsAndCollsForm extends FormAbstract<ObjectAdapter> implements ActionPromptProvider {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_LEFT_COLUMN = "leftColumn";
+ private static final String ID_MIDDLE_COLUMN = "middleColumn";
+ private static final String ID_RIGHT_COLUMN = "rightColumn";
+
+ private static final String ID_ENTITY_COLUMN = "entityColumn";
+ private static final String ID_ENTITY_COLLECTIONS = "entityCollections";
+ private static final String ID_ENTITY_COLLECTIONS_OVERFLOW = "entityCollectionsOverflow";
+
+ private static final String ID_EDIT_BUTTON = "edit";
+ private static final String ID_OK_BUTTON = "ok";
+ private static final String ID_CANCEL_BUTTON = "cancel";
+
+ private static final String ID_FEEDBACK = "feedback";
+
+ private final Component owningPanel;
+
+ private Button editButton;
+ private Button okButton;
+ private Button cancelButton;
+
+ private NotificationPanel feedback;
+
+
+ public EntityPropsAndCollsForm(
+ final String id,
+ final EntityModel entityModel,
+ final Component owningPanel) {
+
+ super(id, entityModel);
+ this.owningPanel = owningPanel; // for repainting
+
+ buildGui();
+
+ // add any concurrency exception that might have been propagated into the entity model
+ // as a result of a previous action invocation
+ final String concurrencyExceptionIfAny = entityModel.getAndClearConcurrencyExceptionIfAny();
+ if(concurrencyExceptionIfAny != null) {
+ error(concurrencyExceptionIfAny);
+ }
+ }
+
+ private void buildGui() {
+
+ final EntityModel entityModel = (EntityModel) getModel();
+ final FCTab FCTabMetaDataIfAny = (FCTab) entityModel.getLayoutMetadata();
+
+ final ColumnSpans columnSpans;
+ if(FCTabMetaDataIfAny != null) {
+ final FCColumn middle = FCTabMetaDataIfAny.getMiddle();
+ final FCColumn right = FCTabMetaDataIfAny.getRight();
+ columnSpans = ColumnSpans.asSpans(
+ FCTabMetaDataIfAny.getLeft().getSpan(),
+ middle != null? middle.getSpan(): 0,
+ right != null? right.getSpan(): 0);
+ } else {
+ final MemberGroupLayoutFacet memberGroupLayoutFacet =
+ entityModel.getObject().getSpecification().getFacet(MemberGroupLayoutFacet.class);
+ columnSpans = memberGroupLayoutFacet.getColumnSpans();
+ }
+
+ // left column
+ // (unlike middle and right columns, the left column is always added to hold the edit buttons and feedback)
+ MarkupContainer leftColumn = new WebMarkupContainer(ID_LEFT_COLUMN);
+ add(leftColumn);
+
+ if(columnSpans.getLeft() > 0) {
+ addPropertiesAndCollections(leftColumn, entityModel, FCTabMetaDataIfAny, Hint.LEFT);
+ } else {
+ Components.permanentlyHide(this, ID_LEFT_COLUMN);
+ }
+
+ // middle column
+ MarkupContainer middleColumn;
+ if(columnSpans.getMiddle() > 0) {
+ middleColumn = new WebMarkupContainer(ID_MIDDLE_COLUMN);
+ add(middleColumn);
+ addPropertiesAndCollections(middleColumn, entityModel, FCTabMetaDataIfAny, Hint.MIDDLE);
+ } else {
+ middleColumn = null;
+ Components.permanentlyHide(this, ID_MIDDLE_COLUMN);
+ }
+
+ // right column
+ MarkupContainer rightColumn;
+ if(columnSpans.getRight() > 0) {
+ rightColumn = new WebMarkupContainer(ID_RIGHT_COLUMN);
+ add(rightColumn);
+ addPropertiesAndCollections(rightColumn, entityModel, FCTabMetaDataIfAny, Hint.RIGHT);
+ } else {
+ rightColumn = null;
+ Components.permanentlyHide(this, ID_RIGHT_COLUMN);
+ }
+
+ // column spans
+ if(columnSpans.getLeft() > 0) {
+ addClassForSpan(leftColumn, Hint.LEFT.from(columnSpans));
+ }
+ if(columnSpans.getMiddle() > 0) {
+ addClassForSpan(middleColumn, Hint.MIDDLE.from(columnSpans));
+ }
+ if(columnSpans.getRight() > 0) {
+ addClassForSpan(rightColumn, Hint.RIGHT.from(columnSpans));
+ }
+
+ // edit buttons and feedback (not supported on tabbed view)
+ final Hint leftHint = Hint.LEFT;
+ final FCColumn leftColumnMetaDataIfAny = leftHint.from(FCTabMetaDataIfAny);
+ final boolean hasProperties = leftColumnMetaDataIfAny == null && !PropUtil
+ .propertyGroupNames(entityModel, leftHint, leftColumnMetaDataIfAny).isEmpty();
+ if (hasProperties) {
+ addButtons(leftColumn);
+ addFeedbackGui(leftColumn);
+
+ } else {
+ Components.permanentlyHide(leftColumn,
+ ID_EDIT_BUTTON, ID_OK_BUTTON, ID_CANCEL_BUTTON,
+ ID_FEEDBACK);
+ }
+
+
+ // collections (only if not being added to a tab)
+ if(FCTabMetaDataIfAny == null && columnSpans.getCollections() > 0) {
+ final String idCollectionsToShow;
+ final String idCollectionsToHide;
+ int collectionSpan;
+ if (columnSpans.exceedsRow()) {
+ idCollectionsToShow = ID_ENTITY_COLLECTIONS_OVERFLOW;
+ idCollectionsToHide = ID_ENTITY_COLLECTIONS;
+ collectionSpan = 12;
+ } else {
+ idCollectionsToShow = ID_ENTITY_COLLECTIONS;
+ idCollectionsToHide = ID_ENTITY_COLLECTIONS_OVERFLOW;
+ collectionSpan = columnSpans.getCollections();
+ }
+
+ final Component collectionsColumn =
+ getComponentFactoryRegistry().addOrReplaceComponent(
+ this, idCollectionsToShow, ComponentType.ENTITY_COLLECTIONS, entityModel);
+ addClassForSpan(collectionsColumn, collectionSpan);
+
+ Components.permanentlyHide(this, idCollectionsToHide);
+ } else {
+ Components.permanentlyHide(this, ID_ENTITY_COLLECTIONS);
+ Components.permanentlyHide(this, ID_ENTITY_COLLECTIONS_OVERFLOW);
+ }
+ }
+
+ private void addPropertiesAndCollections(
+ final MarkupContainer markupContainer,
+ final EntityModel entityModel,
+ final FCTab fcTabMetaDataIfAny,
+ final Hint hint) {
+ final FCColumn columnMetaDataIfAny = hint.from(fcTabMetaDataIfAny);
+
+ final EntityModel entityModelWithHints = entityModel.cloneWithLayoutMetadata(columnMetaDataIfAny);
+
+ final EntityColumn columnMembers =
+ new EntityColumn(ID_ENTITY_COLUMN, entityModelWithHints, hint);
+ markupContainer.add(columnMembers);
+ }
+
+
+ @Override
+ protected void onComponentTag(ComponentTag tag) {
+ super.onComponentTag(tag);
+
+ Attributes.addClass(tag, "form-horizontal");
+ }
+
+ @Override
+ public ActionPrompt getActionPrompt() {
+ return ActionPromptProvider.Util.getFrom(this).getActionPrompt();
+ }
+
+ abstract class AjaxButtonWithOnError extends AjaxButton {
+
+ public AjaxButtonWithOnError(String id, IModel<String> model) {
+ super(id, model);
+ }
+
+ @Override
+ protected void onError(AjaxRequestTarget target, Form<?> form) {
+ super.onError(target, form);
+ toEditMode(target);
+ }
+
+ /**
+ * Render the 'type' attribute even for invisible buttons to avoid
+ * <a href="https://github.com/twbs/bootlint/wiki/W007">Bootlint W007</a>
+ *
+ * @param tag The component tag to render
+ * @param response The response to write to
+ */
+ // TODO mgrigorov Move this to Wicket Bootstrap project
+ @Override
+ protected void renderPlaceholderTag(ComponentTag tag, Response response) {
+ String ns = Strings.isEmpty(tag.getNamespace()) ? null : tag.getNamespace() + ':';
+
+ response.write("<");
+ if (ns != null)
+ {
+ response.write(ns);
+ }
+ response.write(tag.getName());
+ response.write(" id=\"");
+ response.write(getAjaxRegionMarkupId());
+
+ String type = tag.getAttribute("type");
+ if (!Strings.isEmpty(type)) {
+ response.write("\" type=\""+type);
+ }
+
+ response.write("\" style=\"display:none\"></");
+ if (ns != null)
+ {
+ response.write(ns);
+ }
+ response.write(tag.getName());
+ response.write(">");
+ }
+ }
+
+ public class AjaxButtonForValidate extends AjaxButtonWithOnError implements IFormSubmitterWithPreValidateHook {
+ private static final long serialVersionUID = 1L;
+ public AjaxButtonForValidate(String id, IModel<String> model) {
+ super(id, model);
+ }
+
+ @Override
+ public String preValidate() {
+ // attempt to load with concurrency checking, catching recognized exceptions
+ try {
+ getEntityModel().load(ConcurrencyChecking.CHECK); // could have also just called #getObject(), since CHECK is the default
+
+ } catch(ConcurrencyException ex){
+ String recognizedErrorMessage = recognizeException(ex);
+ if(recognizedErrorMessage == null) {
+ throw ex;
+ }
+
+ // reload
+ getEntityModel().load(ConcurrencyChecking.NO_CHECK);
+
+ getForm().clearInput();
+ getEntityModel().resetPropertyModels();
+
+ toViewMode(null);
+ toEditMode(null);
+
+ return recognizedErrorMessage;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void validate() {
+ // add in any error message that we might have recognized from above
+ EntityPropsAndCollsForm form = EntityPropsAndCollsForm.this;
+ String preValidationErrorIfAny = form.getPreValidationErrorIfAny();
+
+ if(preValidationErrorIfAny != null) {
+ feedbackOrNotifyAnyRecognizedError(preValidationErrorIfAny, form);
+ // skip validation, because would relate to old values
+
+ final EntityPage entityPage = new EntityPage(EntityPropsAndCollsForm.this.getModelObject(), null);
+ EntityPropsAndCollsForm.this.setResponsePage(entityPage);
+ } else {
+ // run Wicket's validation
+ super.validate();
+ }
+ }
+
+ @Override
+ protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
+
+ if (getForm().hasError()) {
+ // stay in edit mode
+ return;
+ }
+
+ doPreApply();
+ if (applyFormChangesElse(target)) return;
+ final Object redirectIfAny = doPostApply();
+
+ if (flushChangesElse(target)) return;
+
+
+ getEntityModel().resetPropertyModels();
+
+ toViewMode(null);
+
+ // "redirect-after-post"
+ //
+ // RequestCycle.get().getActiveRequestHandler() indicates this is handled by the ListenerInterfaceRequestHandler
+ // which renders page at end.
+ //
+ // it's necessary to zap the page parameters (so mapping is to just wicket/page?nn)
+ // otherwise (what I think happens) is that the httpServletResponse.sendRedirect ends up being to the same URL,
+ // and this is rejected as invalid either by the browser or by the servlet container (perhaps only if running remotely).
+ //
+
+ final ObjectAdapter objectAdapter;
+ if(redirectIfAny != null) {
+ objectAdapter = getPersistenceSession().adapterFor(redirectIfAny);
+ } else {
+ // we obtain the adapter from the entity model because (if a view model) then the entity model may contain
+ // a different adapter (the cloned view model) to the one with which we started with.
+ objectAdapter = getEntityModel().getObjectAdapterMemento().getObjectAdapter(ConcurrencyChecking.NO_CHECK);
+ }
+
+ final EntityPage entityPage = new EntityPage(objectAdapter, null);
+ EntityPropsAndCollsForm.this.setResponsePage(entityPage);
+ }
+
+ /**
+ * Optional hook to override.
+ *
+ * <p>
+ * If a non-null value is returned, then transition to it (ie eg the finish() transition for a wizard).
+ * </p>
+ */
+ protected void doPreApply() {
+ }
+
+ /**
+ * Optional hook to override.
+ *
+ * <p>
+ * If a non-null value is returned, then transition to it (ie eg the finish() transition for a wizard).
+ * </p>
+ */
+ protected Object doPostApply() {
+ return null;
+ }
+
+ }
+
+ abstract class AjaxButtonForCancel extends AjaxButtonWithOnError {
+
+ public AjaxButtonForCancel(String id, IModel<String> model) {
+ super(id, model);
+ setDefaultFormProcessing(false);
+ }
+ }
+
+
+ private void addButtons(MarkupContainer markupContainer) {
+
+ // edit button
+ editButton = new AjaxButtonWithOnError(ID_EDIT_BUTTON, new ResourceModel("editLabel")) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void validate() {
+
+ // same logic as in cancelButton; should this be factored out?
+ try {
+ getEntityModel().load(ConcurrencyChecking.CHECK);
+ } catch(ConcurrencyException ex) {
+ getMessageBroker().addMessage("Object changed by " + ex.getOid().getVersion().getUser() + ", automatically reloading");
+ getEntityModel().load(ConcurrencyChecking.NO_CHECK);
+ }
+
+ super.validate();
+ }
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ getEntityModel().resetPropertyModels();
+ toEditMode(target);
+ }
+
+ @Override
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
+ super.updateAjaxAttributes(attributes);
+ attributes.getAjaxCallListeners().add(new org.apache.wicket.ajax.attributes.AjaxCallListener(){
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public CharSequence getSuccessHandler(Component component) {
+ // scroll to the top of the entity panel
+ return "$('html, body').animate({"
+ + " scrollTop: $('.entityIconAndTitlePanel').offset().top"
+ + " }, 1000);";
+ }
+ });
+ }
+ };
+ editButton.add(new Label("editLabel", editButton.getModel()));
+ markupContainer.add(editButton);
+
+
+ // ok button
+ okButton = new AjaxButtonForValidate(ID_OK_BUTTON, new ResourceModel("okLabel"));
+ markupContainer.add(okButton);
+
+
+ // cancel button
+ cancelButton = new AjaxButtonForCancel(ID_CANCEL_BUTTON, new ResourceModel("cancelLabel")) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void validate() {
+
+ // same logic as in editButton; should this be factored out?
+ try {
+ getEntityModel().load(ConcurrencyChecking.CHECK);
+ } catch(ConcurrencyException ex) {
+ getMessageBroker().addMessage("Object changed by " + ex.getOid().getVersion().getUser() + ", automatically reloading");
+ getEntityModel().load(ConcurrencyChecking.NO_CHECK);
+ }
+ super.validate();
+ }
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+ Session.get().getFeedbackMessages().clear();
+ getForm().clearInput();
+ getForm().visitFormComponentsPostOrder(new IVisitor<FormComponent<?>, Void>() {
+
+ @Override
+ public void component(FormComponent<?> formComponent, IVisit<Void> visit) {
+ if (formComponent instanceof CancelHintRequired) {
+ final CancelHintRequired cancelHintRequired = (CancelHintRequired) formComponent;
+ cancelHintRequired.onCancel();
+ }
+ }
+ });
+
+ try {
+ getEntityModel().resetPropertyModels();
+ } catch(RuntimeException ex) {
+ throw ex;
+ }
+ toViewMode(target);
+ }
+ };
+
+ markupContainer.add(cancelButton);
+
+ okButton.setOutputMarkupPlaceholderTag(true);
+ editButton.setOutputMarkupPlaceholderTag(true);
+ cancelButton.setOutputMarkupPlaceholderTag(true);
+
+ // flush any JGrowl messages (typically concurrency exceptions) if they are added.
+ okButton.add(new JGrowlBehaviour());
+ editButton.add(new JGrowlBehaviour());
+ cancelButton.add(new JGrowlBehaviour());
+ }
+
+ // to perform object-level validation, we must apply the changes first
+ // contrast this with ActionPanel (for validating actionarguments) where
+ // we do the validation prior to the execution of the action
+ private boolean applyFormChangesElse(AjaxRequestTarget target) {
+ final ObjectAdapter adapter = getEntityModel().getObject();
+ final Memento snapshotToRollbackToIfInvalid = new Memento(adapter);
+
+ getEntityModel().apply();
+ final String invalidReasonIfAny = getEntityModel().getReasonInvalidIfAny();
+ if (invalidReasonIfAny != null) {
+ error(invalidReasonIfAny);
+ snapshotToRollbackToIfInvalid.recreateObject();
+ toEditMode(target);
+
+ // abort otherwise the object will have been dirtied and JDO will end up committing,
+ // possibly bumping the version and resulting in a subsequent concurrency exception.
+ IsisContext.getTransactionManager().abortTransaction();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean flushChangesElse(AjaxRequestTarget target) {
+ try {
+ this.getTransactionManager().flushTransaction();
+ } catch(RuntimeException ex) {
+
+ // There's no need to abort the transaction here, as it will have already been done
+ // (in IsisTransactionManager#executeWithinTransaction(...)).
+
+ String message = recognizeExceptionAndNotify(ex, this);
+ if(message == null) {
+ throw ex;
+ }
+
+ toEditMode(target);
+ return true;
+ }
+ return false;
+ }
+
+
+ private String recognizeExceptionAndNotify(RuntimeException ex, Component feedbackComponentIfAny) {
+
+ // see if the exception is recognized as being a non-serious error
+
+ String recognizedErrorMessageIfAny = recognizeException(ex);
+ feedbackOrNotifyAnyRecognizedError(recognizedErrorMessageIfAny, feedbackComponentIfAny);
+
+ return recognizedErrorMessageIfAny;
+ }
+
+ private void feedbackOrNotifyAnyRecognizedError(String recognizedErrorMessageIfAny, Component feedbackComponentIfAny) {
+ if(recognizedErrorMessageIfAny == null) {
+ return;
+ }
+
+ if(feedbackComponentIfAny != null) {
+ feedbackComponentIfAny.error(recognizedErrorMessageIfAny);
+ }
+ getMessageBroker().addWarning(recognizedErrorMessageIfAny);
+
+ // we clear the abort cause because we've handled rendering the exception
+ getTransactionManager().getTransaction().clearAbortCause();
+ }
+
+ private String recognizeException(RuntimeException ex) {
+
+ // REVIEW: this code is similar to stuff in EntityPropertiesForm, perhaps move up to superclass?
+ // REVIEW: similar code also in WebRequestCycleForIsis; combine?
+
+ final List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+ final String message = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+ return message;
+ }
+
+ private void requestRepaintPanel(final AjaxRequestTarget target) {
+ if (target != null) {
+ target.add(owningPanel);
+ // TODO: is it necessary to add these too?
+ target.add(editButton, okButton, cancelButton, feedback);
+ }
+ }
+
+ private EntityModel getEntityModel() {
+ return (EntityModel) getModel();
+ }
+
+ void toViewMode(final AjaxRequestTarget target) {
+
+ getEntityModel().toViewMode();
+
+ setVisible(editButton, isAnythingEditable());
+ setVisible(okButton, false);
+ setVisible(cancelButton, false);
+
+ requestRepaintPanel(target);
+ }
+
+ private void setVisible(Button b, boolean editable) {
+ if(b != null) {
+ b.setVisible(editable);
+ }
+ }
+
+ private boolean isAnythingEditable() {
+ final EntityModel entityModel = (EntityModel) getModel();
+ final ObjectAdapter adapter = entityModel.getObject();
+
+ return !enabledAssociations(adapter, adapter.getSpecification()).isEmpty();
+ }
+
+ private List<ObjectAssociation> enabledAssociations(final ObjectAdapter adapter, final ObjectSpecification objSpec) {
+ return objSpec.getAssociations(Contributed.EXCLUDED, enabledAssociationFilter(adapter));
+ }
+
+ @SuppressWarnings("unchecked")
+ private Filter<ObjectAssociation> enabledAssociationFilter(final ObjectAdapter adapter) {
+ return Filters.and(ObjectAssociation.Filters.PROPERTIES, ObjectAssociation.Filters.enabled(adapter,
+ InteractionInitiatedBy.USER, Where.OBJECT_FORMS
+ ));
+ }
+
+ private void toEditMode(final AjaxRequestTarget target) {
+ getEntityModel().toEditMode();
+
+ editButton.setVisible(false);
+ okButton.setVisible(true);
+ cancelButton.setVisible(true);
+
+ requestRepaintPanel(target);
+ }
+
+ private void addFeedbackGui(final MarkupContainer markupContainer) {
+ feedback = new NotificationPanel(ID_FEEDBACK, this, new ComponentFeedbackMessageFilter(this));
+ feedback.setOutputMarkupPlaceholderTag(true);
+ markupContainer.addOrReplace(feedback);
+
+ // to avoid potential XSS attacks, no longer escape model strings
+ // (risk is low but could just happen: error message being rendered might accidentally or deliberately contain rogue Javascript)
+ // feedback.setEscapeModelStrings(false);
+
+ final ObjectAdapter adapter = getEntityModel().getObject();
+ if (adapter == null) {
+ feedback.error("cannot locate object:" + getEntityModel().getObjectAdapterMemento().toString());
+ }
+ }
+
+
+ static void addClassForSpan(final Component component, final int numGridCols) {
+ component.add(new CssClassAppender("col-xs-"+numGridCols));
+ }
+
+
+
+ ///////////////////////////////////////////////////////
+ // Dependencies (from context)
+ ///////////////////////////////////////////////////////
+
+ protected IsisTransactionManager getTransactionManager() {
+ return IsisContext.getTransactionManager();
+ }
+
+ protected ServicesInjector getServicesInjector() {
+ return IsisContext.getPersistenceSession().getServicesInjector();
+ }
+
+ protected MessageBroker getMessageBroker() {
+ return getAuthenticationSession().getMessageBroker();
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.properties
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.properties b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.properties
new file mode 100644
index 0000000..71edcd9
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsForm.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+okLabel=OK
+cancelLabel=Cancel
+editLabel=Edit
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.html
new file mode 100644
index 0000000..449f18d
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.html
@@ -0,0 +1,54 @@
+<?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="entityPropertiesPanel entityPropertiesComponentType">
+ <!-- EntityPropsAndCollsForm:start -->
+ <form wicket:id="entityForm" class="inputForm" role="form">
+ <div class="row">
+ <div wicket:id="leftColumn">
+ <div wicket:id="entityColumn"/>
+ <div class="feedbackPanel">
+ <span wicket:id="feedback"></span>
+ </div>
+ <div class="buttons">
+ <button type="submit" class="edit btn btn-primary btn-md" wicket:id="edit"><span class="fa fa-edit"></span> <wicket:container wicket:id="editLabel"></wicket:container></button>
+ <input type="submit" class="ok btn btn-primary btn-md" wicket:id="ok"/>
+ <input type="submit" class="cancel btn btn-default btn-md" wicket:id="cancel"/>
+ </div>
+ </div>
+ <div wicket:id="middleColumn">
+ <div wicket:id="entityColumn"/>
+ </div>
+ <div wicket:id="rightColumn">
+ <div wicket:id="entityColumn"/>
+ </div>
+ <div wicket:id="entityCollections"></div>
+ </div>
+ <div class="row">
+ <div wicket:id="entityCollectionsOverflow"></div>
+ </div>
+ </form>
+ <!-- EntityPropsAndCollsForm:end -->
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.java
new file mode 100644
index 0000000..8eadd52
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanel.java
@@ -0,0 +1,67 @@
+/*
+ * 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.layout.fixedcols.propsandcolls;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.layout.fallback.EntityEditablePanel;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.FCPagePanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * {@link PanelAbstract Panel} representing the properties and collections of an entity, as per
+ * the provided {@link EntityModel}.
+ *
+ * <p>
+ * Used by both {@link FCPagePanel} and also {@link EntityEditablePanel}. In the former
+ * case the collections are never shown, and edit buttons suppressed. In the latter case the
+ * collections are shown, possibly overflowing to region below.
+ * </p>
+ */
+public class EntityPropsAndCollsPanel extends PanelAbstract<EntityModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_ENTITY_FORM = "entityForm";
+
+ private EntityPropsAndCollsForm form;
+
+ public EntityPropsAndCollsPanel(final String id, final EntityModel entityModel) {
+ super(id, entityModel);
+ buildGui();
+ form.toViewMode(null);
+ }
+
+ private void buildGui() {
+ buildEntityPropertiesAndOrCollectionsGui();
+ setOutputMarkupId(true);
+ }
+
+ private void buildEntityPropertiesAndOrCollectionsGui() {
+ final EntityModel model = getModel();
+ final ObjectAdapter adapter = model.getObject();
+ if (adapter != null) {
+ form = new EntityPropsAndCollsForm(ID_ENTITY_FORM, model, this);
+ addOrReplace(form);
+ } else {
+ permanentlyHide(ID_ENTITY_FORM);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanelFactory.java
new file mode 100644
index 0000000..ef51ee4
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/propsandcolls/EntityPropsAndCollsPanelFactory.java
@@ -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.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.propsandcolls;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+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.components.entity.EntityComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.components.layout.fallback.EntityEditablePanel;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.FCPagePanel;
+
+/**
+ * {@link ComponentFactory} for {@link EntityPropsAndCollsPanel}.
+ *
+ *
+ * <p>
+ * Used by both {@link EntityEditablePanel} and also {@link FCPagePanel}.
+ * </p>
+ */
+public class EntityPropsAndCollsPanelFactory extends EntityComponentFactoryAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public EntityPropsAndCollsPanelFactory() {
+ super(ComponentType.ENTITY_PROPERTIES, EntityPropsAndCollsPanel.class);
+ }
+
+ @Override
+ public Component createComponent(final String id, final IModel<?> model) {
+ final EntityModel entityModel = (EntityModel) model;
+ return new EntityPropsAndCollsPanel(id, entityModel);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.html
new file mode 100644
index 0000000..6699518
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html xmlns:wicket="http://wicket.apache.org">
+<body>
+<wicket:panel>
+ <div wicket:id="tabGroups">
+ <div wicket:id="tabGroup">[tabbed panel will be here]</div>
+ </div>
+</wicket:panel>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.java
new file mode 100644
index 0000000..0934f80
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabgrouplist/TabGroupListPanel.java
@@ -0,0 +1,67 @@
+/*
+ * 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.layout.fixedcols.tabgrouplist;
+
+import java.util.List;
+
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+
+import org.apache.isis.applib.layout.fixedcols.FCTabGroup;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.tabs.TabGroupPanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+public class TabGroupListPanel extends PanelAbstract<EntityModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_TAB_GROUPS = "tabGroups";
+
+ // the view metadata
+ private final List<FCTabGroup> tabGroups;
+
+ public TabGroupListPanel(final String id, final EntityModel entityModel) {
+ super(id, entityModel);
+
+ this.tabGroups = (List<FCTabGroup>) entityModel.getLayoutMetadata();
+
+ buildGui();
+ }
+
+ private void buildGui() {
+ final EntityModel model = getModel();
+
+ final ListView<FCTabGroup> tabGroupsList = new ListView<FCTabGroup>(ID_TAB_GROUPS, this.tabGroups) {
+
+ @Override
+ protected void populateItem(final ListItem<FCTabGroup> item) {
+
+ final FCTabGroup tabGroup = item.getModelObject();
+ final EntityModel entityModelWithHints = model.cloneWithLayoutMetadata(tabGroup);
+ final TabGroupPanel tabGroupPanel = new TabGroupPanel(entityModelWithHints);
+ item.add(tabGroupPanel);
+ }
+ };
+
+ add(tabGroupsList);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabGroupPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabGroupPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabGroupPanel.java
new file mode 100644
index 0000000..1e84474
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabGroupPanel.java
@@ -0,0 +1,105 @@
+/*
+ * 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.layout.fixedcols.tabs;
+
+import java.util.List;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.extensions.markup.html.tabs.TabbedPanel;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+
+import org.apache.isis.applib.layout.fixedcols.FCTab;
+import org.apache.isis.applib.layout.fixedcols.FCTabGroup;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.util.ScopedSessionAttribute;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+
+public class TabGroupPanel extends AjaxBootstrapTabbedPanel {
+
+ public static final String SESSION_ATTR_SELECTED_TAB = "selectedTab";
+
+ private final EntityModel entityModel;
+ // the view metadata
+ private final FCTabGroup tabGroup;
+
+ private final ScopedSessionAttribute<Integer> selectedTabInSession;
+
+ private static final String ID_TAB_GROUP = "tabGroup";
+
+ private static List<ITab> tabsFor(final EntityModel entityModel) {
+ final List<ITab> tabs = Lists.newArrayList();
+
+ final FCTabGroup tabGroup = (FCTabGroup) entityModel.getLayoutMetadata();
+ final List<FCTab> FCTabList = FluentIterable
+ .from(tabGroup.getTabs())
+ .filter(FCTab.Predicates.notEmpty())
+ .toList();
+
+ for (final FCTab fcTab : FCTabList) {
+ tabs.add(new AbstractTab(Model.of(fcTab.getName())) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Panel getPanel(String panelId) {
+ return new TabPanel(panelId, entityModel, fcTab);
+ }
+ });
+ }
+ return tabs;
+ }
+
+ public TabGroupPanel(final EntityModel entityModel) {
+ super(ID_TAB_GROUP, tabsFor(entityModel));
+
+ this.entityModel = entityModel;
+ this.tabGroup = (FCTabGroup) entityModel.getLayoutMetadata();
+ this.selectedTabInSession = ScopedSessionAttribute.create(entityModel, this, SESSION_ATTR_SELECTED_TAB);
+
+ }
+
+ @Override
+ protected void onInitialize() {
+ setSelectedTabFromSessionIfAny(this);
+ super.onInitialize();
+ }
+
+ @Override
+ public TabbedPanel setSelectedTab(final int index) {
+ selectedTabInSession.set(index);
+ return super.setSelectedTab(index);
+ }
+
+ private void setSelectedTabFromSessionIfAny(
+ final AjaxBootstrapTabbedPanel ajaxBootstrapTabbedPanel) {
+ final Integer tabIndex = selectedTabInSession.get();
+ if (tabIndex != null) {
+ final int numTabs = ajaxBootstrapTabbedPanel.getTabs().size();
+ if (tabIndex < numTabs) {
+ // to support dynamic reloading; the data in the session might not be compatible with current layout.
+ ajaxBootstrapTabbedPanel.setSelectedTab(tabIndex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.html
new file mode 100644
index 0000000..111fc68
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.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="tabPanel">
+ <form class="inputForm" role="form">
+ <div wicket:id="column">
+ </div>
+ </form>
+ </div>
+</wicket:panel>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/c57d8cd8/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.java
new file mode 100644
index 0000000..1dda0c6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/fixedcols/tabs/TabPanel.java
@@ -0,0 +1,24 @@
+package org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.tabs;
+
+import org.apache.isis.applib.layout.fixedcols.FCTab;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+public class TabPanel extends PanelAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ID_COLUMN = "column";
+
+ public TabPanel(String id, final EntityModel model, final FCTab fcTab) {
+ super(id);
+
+ final EntityModel modelWithTabHints = model.cloneWithLayoutMetadata(fcTab);
+
+ getComponentFactoryRegistry()
+ .addOrReplaceComponent(this,
+ ID_COLUMN, ComponentType.ENTITY_PROPERTIES, modelWithTabHints);
+
+ }
+}