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/01/25 16:07:23 UTC
[02/50] [abbrv] isis git commit: ISIS-993: SessionScopedAttribute
factored out,
now used for the selectedItem drop-down so that the system remembers which
view to use for rendering a collection (for a particular object).
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.java
new file mode 100644
index 0000000..22c0cf9
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.java
@@ -0,0 +1,713 @@
+/*
+ * 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.entity.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.v1_0.ColumnMetadata;
+import org.apache.isis.applib.layout.v1_0.ColumnMetadata.Hint;
+import org.apache.isis.applib.layout.v1_0.TabMetadata;
+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.entity.PropUtil;
+import org.apache.isis.viewer.wicket.ui.components.entity.column.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_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 TabMetadata tabMetaDataIfAny = entityModel.getTabMetadata();
+
+ final ColumnSpans columnSpans;
+ if(tabMetaDataIfAny != null) {
+ final ColumnMetadata middle = tabMetaDataIfAny.getMiddle();
+ final ColumnMetadata right = tabMetaDataIfAny.getRight();
+ columnSpans = ColumnSpans.asSpans(
+ tabMetaDataIfAny.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, tabMetaDataIfAny, 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, tabMetaDataIfAny, 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, tabMetaDataIfAny, 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 ColumnMetadata leftColumnMetaDataIfAny = leftHint.from(tabMetaDataIfAny);
+ 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(tabMetaDataIfAny == 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 TabMetadata tabMetaDataIfAny,
+ final Hint hint) {
+ final ColumnMetadata columnMetaDataIfAny = hint.from(tabMetaDataIfAny);
+
+ final EntityModel entityModelWithHints = entityModel.cloneWithColumnMetadata(columnMetaDataIfAny, hint);
+
+ final EntityColumn columnMembers =
+ new EntityColumn("entityMembers", entityModelWithHints);
+ 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/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.properties
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsForm.properties b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/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/entity/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/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.html
new file mode 100644
index 0000000..e204c12
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.html
@@ -0,0 +1,52 @@
+<?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">
+ <form wicket:id="entityProperties" class="inputForm" role="form">
+ <div class="row">
+ <div wicket:id="leftColumn">
+ <div wicket:id="entityMembers"/>
+ <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="entityMembers"/>
+ </div>
+ <div wicket:id="rightColumn">
+ <div wicket:id="entityMembers"/>
+ </div>
+ <div wicket:id="entityCollections"></div>
+ </div>
+ <div class="row">
+ <div wicket:id="entityCollectionsOverflow"></div>
+ </div>
+ </form>
+ </div>
+ </wicket:panel>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanel.java
new file mode 100644
index 0000000..0ef00d5
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/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.entity.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.entity.editable.EntityEditablePanel;
+import org.apache.isis.viewer.wicket.ui.components.entity.tabbed.EntityTabbedPanel;
+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 EntityTabbedPanel} 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_PROPERTIES = "entityProperties";
+
+ 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_PROPERTIES, model, this);
+ addOrReplace(form);
+ } else {
+ permanentlyHide(ID_ENTITY_PROPERTIES);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/propsandcolls/EntityPropsAndCollsPanelFactory.java
new file mode 100644
index 0000000..bdaeeda
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/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.entity.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.entity.editable.EntityEditablePanel;
+import org.apache.isis.viewer.wicket.ui.components.entity.tabbed.EntityTabbedPanel;
+
+/**
+ * {@link ComponentFactory} for {@link EntityPropsAndCollsPanel}.
+ *
+ *
+ * <p>
+ * Used by both {@link EntityEditablePanel} and also {@link EntityTabbedPanel}.
+ * </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/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/selector/links/EntityLinksSelectorPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/selector/links/EntityLinksSelectorPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/selector/links/EntityLinksSelectorPanel.java
index 2bd7cf1..9bbfa11 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/selector/links/EntityLinksSelectorPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/selector/links/EntityLinksSelectorPanel.java
@@ -19,13 +19,13 @@
package org.apache.isis.viewer.wicket.ui.components.entity.selector.links;
-import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
-
import java.util.ArrayList;
import java.util.List;
+
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
+
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
@@ -40,6 +40,7 @@ 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;
@@ -56,6 +57,8 @@ import org.apache.isis.viewer.wicket.ui.util.Components;
import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
import org.apache.isis.viewer.wicket.ui.util.CssClassRemover;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
+
/**
* Provides a list of links for selecting other views that support
* {@link ComponentType#ENTITY} with a backing {@link EntityModel}.
@@ -95,14 +98,19 @@ public class EntityLinksSelectorPanel extends PanelAbstract<EntityModel> impleme
protected Component selectedComponent;
- public EntityLinksSelectorPanel(final String id, final EntityModel model, final ComponentFactory factory) {
+ public EntityLinksSelectorPanel(
+ final String id,
+ final EntityModel model,
+ final ComponentFactory factory) {
super(id, model);
this.underlyingIdPrefix = ComponentType.ENTITY.toString();
this.componentType = factory.getComponentType();
}
- protected int determineInitialFactory(List<ComponentFactory> componentFactories, IModel<?> model) {
+ protected int determineInitialFactory(
+ final List<ComponentFactory> componentFactories,
+ final IModel<?> model) {
return 0;
}
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.html
deleted file mode 100644
index 7b172aa..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.html
+++ /dev/null
@@ -1,34 +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="entityTabbed">
- <div wicket:id="entitySummary"></div>
-
- <div class="row">
- <div wicket:id="leftColumn" class = "leftColumn"/>
- <div wicket:id="middleColumn" class="middleColumn"/>
- <div wicket:id="rightColumn" class = "rightColumn"/>
- </div>
- </div>
-</wicket:panel>
-</body>
-</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.java
deleted file mode 100644
index 3f98286..0000000
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/ColumnTabGroupListColumnPanel.java
+++ /dev/null
@@ -1,113 +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.entity.tabbed;
-
-import java.util.List;
-
-import com.google.common.collect.FluentIterable;
-
-import org.apache.isis.applib.layout.v1_0.ColumnMetadata;
-import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
-import org.apache.isis.applib.layout.v1_0.TabGroupMetadata;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
-import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
-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.entity.column.EntityColumn;
-import org.apache.isis.viewer.wicket.ui.components.entity.tabgrouplist.TabGroupListPanel;
-import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
-import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
-
-/**
- * {@link PanelAbstract Panel} to represent an entity on a single page made up
- * of several <div> regions.
- */
-public class ColumnTabGroupListColumnPanel extends PanelAbstract<EntityModel> {
-
- 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";
-
- public ColumnTabGroupListColumnPanel(final String id, final EntityModel entityModel) {
- super(id, entityModel);
- buildGui();
- }
-
- private void buildGui() {
- final EntityModel model = getModel();
- final ObjectAdapter objectAdapter = model.getObject();
- final CssClassFacet facet = objectAdapter.getSpecification().getFacet(CssClassFacet.class);
- if(facet != null) {
- final String cssClass = facet.cssClass(objectAdapter);
- CssClassAppender.appendCssClassTo(this, cssClass);
- }
-
- // forces metadata to be derived && synced
- final ObjectLayoutMetadataFacet objectLayoutMetadataFacet = model.getTypeOfSpecification().getFacet(ObjectLayoutMetadataFacet.class);
- final ObjectLayoutMetadata objectLayoutMetadata = objectLayoutMetadataFacet.getMetadata();
-
-
- addOrReplace(ComponentType.ENTITY_SUMMARY, model);
-
- final int leftSpan = addColumnIfRequired(ID_LEFT_COLUMN, objectLayoutMetadata.getLeft(), ColumnMetadata.Hint.LEFT);
-
- final TabGroupListPanel middleTabs = addTabGroups(ID_MIDDLE_COLUMN, objectLayoutMetadata.getTabGroups());
-
- final int rightSpan = addColumnIfRequired(ID_RIGHT_COLUMN, objectLayoutMetadata.getRight(), ColumnMetadata.Hint.RIGHT);
-
- final int columnSpans = leftSpan + rightSpan;
- int tabGroupSpan = columnSpans < 12 ? 12 - (columnSpans) : 12;
- CssClassAppender.appendCssClassTo(middleTabs, "col-xs-" + tabGroupSpan);
-
- }
-
- private TabGroupListPanel addTabGroups(
- final String id, final List<TabGroupMetadata> tabGroupList) {
- final EntityModel model = getModel();
- final List<TabGroupMetadata> tabGroups = FluentIterable
- .from(tabGroupList)
- .filter(TabGroupMetadata.Predicates.notEmpty())
- .toList();
- final EntityModel entityModelWitHints = model.cloneWithTabGroupListMetadata(tabGroups);
- final TabGroupListPanel middleComponent = new TabGroupListPanel(id, entityModelWitHints);
- addOrReplace(middleComponent);
- return middleComponent;
- }
-
- private int addColumnIfRequired(final String id, final ColumnMetadata col, final ColumnMetadata.Hint hint) {
- if(col != null) {
- final EntityModel entityModel =
- getModel().cloneWithColumnMetadata(col, hint);
- final int span = entityModel.getColumnMetadata().getSpan();
- if(span > 0) {
- final EntityColumn entityColumn = new EntityColumn(id, entityModel, this);
- addOrReplace(entityColumn);
- CssClassAppender.appendCssClassTo(entityColumn, "col-xs-" + span);
- return span;
- }
- }
- permanentlyHide(id);
- return 0;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
new file mode 100644
index 0000000..7b172aa
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.html
@@ -0,0 +1,34 @@
+<?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="entityTabbed">
+ <div wicket:id="entitySummary"></div>
+
+ <div class="row">
+ <div wicket:id="leftColumn" class = "leftColumn"/>
+ <div wicket:id="middleColumn" class="middleColumn"/>
+ <div wicket:id="rightColumn" class = "rightColumn"/>
+ </div>
+ </div>
+</wicket:panel>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
new file mode 100644
index 0000000..8bf707f
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabbed/EntityTabbedPanel.java
@@ -0,0 +1,113 @@
+/*
+ * 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.entity.tabbed;
+
+import java.util.List;
+
+import com.google.common.collect.FluentIterable;
+
+import org.apache.isis.applib.layout.v1_0.ColumnMetadata;
+import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata;
+import org.apache.isis.applib.layout.v1_0.TabGroupMetadata;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
+import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet;
+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.entity.column.EntityColumn;
+import org.apache.isis.viewer.wicket.ui.components.entity.tabgrouplist.TabGroupListPanel;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
+
+/**
+ * {@link PanelAbstract Panel} to represent an entity on a single page made up
+ * of several <div> regions.
+ */
+public class EntityTabbedPanel extends PanelAbstract<EntityModel> {
+
+ 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";
+
+ public EntityTabbedPanel(final String id, final EntityModel entityModel) {
+ super(id, entityModel);
+ buildGui();
+ }
+
+ private void buildGui() {
+ final EntityModel model = getModel();
+ final ObjectAdapter objectAdapter = model.getObject();
+ final CssClassFacet facet = objectAdapter.getSpecification().getFacet(CssClassFacet.class);
+ if(facet != null) {
+ final String cssClass = facet.cssClass(objectAdapter);
+ CssClassAppender.appendCssClassTo(this, cssClass);
+ }
+
+ // forces metadata to be derived && synced
+ final ObjectLayoutMetadataFacet objectLayoutMetadataFacet = model.getTypeOfSpecification().getFacet(ObjectLayoutMetadataFacet.class);
+ final ObjectLayoutMetadata objectLayoutMetadata = objectLayoutMetadataFacet.getMetadata();
+
+
+ addOrReplace(ComponentType.ENTITY_SUMMARY, model);
+
+ final int leftSpan = addColumnIfRequired(ID_LEFT_COLUMN, objectLayoutMetadata.getLeft(), ColumnMetadata.Hint.LEFT);
+
+ final TabGroupListPanel middleTabs = addTabGroups(ID_MIDDLE_COLUMN, objectLayoutMetadata.getTabGroups());
+
+ final int rightSpan = addColumnIfRequired(ID_RIGHT_COLUMN, objectLayoutMetadata.getRight(), ColumnMetadata.Hint.RIGHT);
+
+ final int columnSpans = leftSpan + rightSpan;
+ int tabGroupSpan = columnSpans < 12 ? 12 - (columnSpans) : 12;
+ CssClassAppender.appendCssClassTo(middleTabs, "col-xs-" + tabGroupSpan);
+
+ }
+
+ private TabGroupListPanel addTabGroups(
+ final String id, final List<TabGroupMetadata> tabGroupList) {
+ final EntityModel model = getModel();
+ final List<TabGroupMetadata> tabGroups = FluentIterable
+ .from(tabGroupList)
+ .filter(TabGroupMetadata.Predicates.notEmpty())
+ .toList();
+ final EntityModel entityModelWitHints = model.cloneWithTabGroupListMetadata(tabGroups);
+ final TabGroupListPanel middleComponent = new TabGroupListPanel(id, entityModelWitHints);
+ addOrReplace(middleComponent);
+ return middleComponent;
+ }
+
+ private int addColumnIfRequired(final String id, final ColumnMetadata col, final ColumnMetadata.Hint hint) {
+ if(col != null) {
+ final EntityModel entityModel =
+ getModel().cloneWithColumnMetadata(col, hint);
+ final int span = entityModel.getColumnMetadata().getSpan();
+ if(span > 0) {
+ final EntityColumn entityColumn = new EntityColumn(id, entityModel);
+ addOrReplace(entityColumn);
+ CssClassAppender.appendCssClassTo(entityColumn, "col-xs-" + span);
+ return span;
+ }
+ }
+ permanentlyHide(id);
+ return 0;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/35201392/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroup/TabGroupPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroup/TabGroupPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroup/TabGroupPanel.java
index 649f6f6..601914a 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroup/TabGroupPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/tabgroup/TabGroupPanel.java
@@ -1,3 +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.entity.tabgroup;
import java.util.List;
@@ -11,22 +29,21 @@ 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.v1_0.TabMetadata;
import org.apache.isis.applib.layout.v1_0.TabGroupMetadata;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.adapter.oid.RootOid;
-import org.apache.isis.core.runtime.system.context.IsisContext;
-import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.applib.layout.v1_0.TabMetadata;
import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.util.ScopedSessionAttribute;
import org.apache.isis.viewer.wicket.ui.components.entity.tabpanel.TabPanel;
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 TabGroupMetadata tabGroup;
+ private final ScopedSessionAttribute<Integer> selectedTabInSession;
private static final String ID_TAB_GROUP = "tabGroup";
@@ -57,24 +74,21 @@ public class TabGroupPanel extends AjaxBootstrapTabbedPanel {
this.entityModel = entityModel;
this.tabGroup = entityModel.getTabGroupMetadata();
+ this.selectedTabInSession = ScopedSessionAttribute.create(entityModel, tabGroup, SESSION_ATTR_SELECTED_TAB);
- setSelectedTabFromSessionIfAny(this.tabGroup, this, entityModel);
+ setSelectedTabFromSessionIfAny(this);
}
@Override
public TabbedPanel setSelectedTab(final int index) {
- saveSelectedTabInSession(tabGroup, index, entityModel);
+ selectedTabInSession.set(index);
return super.setSelectedTab(index);
}
private void setSelectedTabFromSessionIfAny(
- final TabGroupMetadata tabGroup,
- final AjaxBootstrapTabbedPanel ajaxBootstrapTabbedPanel,
- final EntityModel entityModel) {
- final String key = buildKey(tabGroup, entityModel);
- final String value = (String) getSession().getAttribute(key);
- if (value != null) {
- final int tabIndex = Integer.parseInt(value);
+ 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.
@@ -82,22 +96,4 @@ public class TabGroupPanel extends AjaxBootstrapTabbedPanel {
}
}
}
-
- private void saveSelectedTabInSession(
- final TabGroupMetadata tabGroup,
- final int tabIndex,
- final EntityModel entityModel) {
- final String key = buildKey(tabGroup, entityModel);
- getSession().setAttribute(key, "" + tabIndex);
- }
-
- private String buildKey(final TabGroupMetadata tabGroup, final EntityModel entityModel) {
- final ObjectAdapterMemento objectAdapterMemento = entityModel.getObjectAdapterMemento();
- final RootOid oid = (RootOid) objectAdapterMemento.getObjectAdapter(
- AdapterManager.ConcurrencyChecking.NO_CHECK).getOid();
- final String key =
- IsisContext.getOidMarshaller().marshalNoVersion(oid) + ":" + tabGroup.getPath() + "#selectedTab";
- return key;
- }
-
}