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/17 01:46:30 UTC

[3/3] isis git commit: ISIS-993: first-cut of single-edit properties (using modal prompt dialog). Prereq for removing the FixedCol stuff.

ISIS-993: first-cut of single-edit properties (using modal prompt dialog).  Prereq for removing the FixedCol stuff.


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

Branch: refs/heads/ISIS-993
Commit: de3e385f02d1941a569934bdfc583c3839488b08
Parents: e57acf2
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed Feb 17 00:46:01 2016 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed Feb 17 00:46:01 2016 +0000

----------------------------------------------------------------------
 .../ComponentFactoryRegistrarDefault.java       |  14 +-
 .../hints/IsisPropertyEditCompletedEvent.java   |  46 +++
 .../viewer/wicket/model/models/EntityModel.java |  34 +--
 .../model/models/PropertyEditExecutor.java      |  35 +++
 .../viewer/wicket/model/models/ScalarModel.java |  57 ++++
 .../isis/viewer/wicket/ui/ComponentType.java    |   8 +
 .../actions/ActionParametersFormPanel.java      |   1 -
 .../property/PropertyEditFormPanel.html         |  42 +++
 .../property/PropertyEditFormPanel.java         | 199 ++++++++++++
 .../property/PropertyEditFormPanelFactory.java  |  52 ++++
 .../components/property/PropertyEditPanel.html  |  35 +++
 .../components/property/PropertyEditPanel.java  | 300 +++++++++++++++++++
 .../property/PropertyEditPanelFactory.java      |  52 ++++
 .../property/PropertyEditPromptHeaderPanel.html |  32 ++
 .../property/PropertyEditPromptHeaderPanel.java |  54 ++++
 .../components/scalars/ScalarPanelAbstract.html |   2 +-
 .../components/scalars/ScalarPanelAbstract.java |  48 ++-
 .../scalars/ScalarPanelTextFieldAbstract.java   |  11 +-
 .../wicket/ui/pages/bootstrap-overrides.css     |  12 +-
 .../ui/pages/jquery.isis.wicket.viewer.js       |  11 +
 .../java/domainapp/dom/simple/SimpleObject.java |   6 +-
 .../dom/simple/SimpleObject.layout.xml          |   1 +
 22 files changed, 1008 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index eacb114..7120113 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -39,15 +39,17 @@ import org.apache.isis.viewer.wicket.ui.components.collectioncontents.multiple.C
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.summary.CollectionContentsAsSummaryFactory;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsAsUnresolvedPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.empty.EmptyCollectionPanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.collections.EntityCollectionsPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.header.EntityHeaderPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconAndTitlePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconTitleAndCopyLinkPanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.propsandcolls.EntityPropsAndCollsPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.entity.selector.links.EntityLinksSelectorPanelFactory;
-import org.apache.isis.viewer.wicket.ui.components.layout.EntityPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.footer.FooterPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.header.HeaderPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.layout.EntityPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.collections.EntityCollectionsPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.layout.fixedcols.propsandcolls.EntityPropsAndCollsPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditFormPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisBlobPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisClobPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisColorPanelFactory;
@@ -135,6 +137,7 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
         addComponentFactoriesForActionInfo(componentFactories);
         addComponentFactoriesForAction(componentFactories);
         addComponentFactoriesForActionLink(componentFactories);
+        addComponentFactoriesForPropertyEdit(componentFactories);
         addComponentFactoriesForEntityCollection(componentFactories);
         addComponentFactoriesForEntityCollectionContents(componentFactories);
         addComponentFactoriesForEmptyCollection(componentFactories);
@@ -265,6 +268,11 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
         componentFactories.add(new StandaloneCollectionPanelFactory());
     }
 
+    protected void addComponentFactoriesForPropertyEdit(final ComponentFactoryList componentFactories) {
+        componentFactories.add(new PropertyEditPanelFactory());
+        componentFactories.add(new PropertyEditFormPanelFactory());
+    }
+
     protected void addComponentFactoriesForActionLink(final ComponentFactoryList componentFactories) {
         componentFactories.add(new ActionLinkPanelFactory());
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/hints/IsisPropertyEditCompletedEvent.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/hints/IsisPropertyEditCompletedEvent.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/hints/IsisPropertyEditCompletedEvent.java
new file mode 100644
index 0000000..77313de
--- /dev/null
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/hints/IsisPropertyEditCompletedEvent.java
@@ -0,0 +1,46 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.viewer.wicket.model.hints;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+
+/**
+ *
+ */
+public class IsisPropertyEditCompletedEvent extends IsisEventLetterAbstract {
+
+    private final ScalarModel scalarModel;
+    private final Form<?> form;
+
+    public IsisPropertyEditCompletedEvent(ScalarModel scalarModel, AjaxRequestTarget target, Form<?> form) {
+        super(target);
+        this.scalarModel = scalarModel;
+        this.form = form;
+    }
+
+    public ScalarModel getScalarModel() {
+        return scalarModel;
+    }
+
+    public Form<?> getForm() {
+        return form;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index b26529b..47e8315 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -38,13 +38,11 @@ import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.core.runtime.services.memento.MementoServiceDefault;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.common.PageParametersUtils;
@@ -505,36 +503,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
     public ObjectAdapter apply() {
         ObjectAdapter adapter = getObjectAdapterMemento().getObjectAdapter(ConcurrencyChecking.CHECK);
         for (final ScalarModel scalarModel : propertyScalarModels.values()) {
-            final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty();
-
-            //
-            // previously there was a guard here to only apply changes provided:
-            //
-            // property.containsDoOpFacet(NotPersistedFacet.class) == null
-            //
-            // however, that logic is wrong; although a property may not be directly
-            // persisted so far as JDO is concerned, it may be indirectly persisted
-            // as the result of business logic in the setter.
-            //
-            // for example, see ExampleTaggableEntity (in isisaddons-module-tags).
-            //
-
-            //
-            // on the other hand, we mustn't attempt to apply changes for disabled properties...
-            // even if the property is persisted (it might be written to by an action), it is never updated by
-            // an edit.
-            //
-            // Fundamentally, then, any non-disabled property (whether persisted or not) should be updated in the
-            // Isis runtime.
-            //
-
-            if(property.containsDoOpFacet(DisabledFacet.class)) {
-                // skip, as per comments above
-                continue;
-            }
-
-            final ObjectAdapter associate = scalarModel.getObject();
-            property.set(adapter, associate, InteractionInitiatedBy.USER);
+            scalarModel.applyValue(adapter);
         }
 
         final ViewModelFacet recreatableObjectFacet = adapter.getSpecification().getFacet(ViewModelFacet.class);
@@ -553,7 +522,6 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
         return adapter;
     }
 
-
     // //////////////////////////////////////////////////////////
     // Pending
     // //////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/PropertyEditExecutor.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/PropertyEditExecutor.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/PropertyEditExecutor.java
new file mode 100644
index 0000000..ca99e4f
--- /dev/null
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/PropertyEditExecutor.java
@@ -0,0 +1,35 @@
+/*
+ *  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.model.models;
+
+import java.io.Serializable;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+
+/**
+ * Decouples the {@link ScalarModel}, which needs to delegate the actual
+ * editing of an property, from its implementor.
+ */
+public interface PropertyEditExecutor extends Serializable {
+
+    boolean editAndProcessResults(AjaxRequestTarget target, Form<?> feedbackForm);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index 1e1c85e..b465456 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -40,6 +40,7 @@ import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
 import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
@@ -767,6 +768,62 @@ public class ScalarModel extends EntityModel implements LinksProvider {
     }
 
 
+    private PropertyEditExecutor executor;
+    public PropertyEditExecutor getExecutor() {
+        return executor;
+    }
+    public void setExecutor(final PropertyEditExecutor executor) {
+        this.executor = executor;
+    }
+
+    @Override
+    public String getReasonInvalidIfAny() {
+        final OneToOneAssociation property = getPropertyMemento().getProperty();
+
+        final ObjectAdapter adapter = getParentObjectAdapterMemento().getObjectAdapter(ConcurrencyChecking.CHECK);
+
+        final ObjectAdapter associate = getObject();
+
+        final Consent validity = property.isAssociationValid(adapter, associate, InteractionInitiatedBy.USER);
+        return validity.isAllowed() ? null : validity.getReason();
+    }
+
+    public void applyValue(final ObjectAdapter adapter) {
+        final OneToOneAssociation property = getPropertyMemento().getProperty();
+
+        //
+        // previously there was a guard here to only apply changes provided:
+        //
+        // property.containsDoOpFacet(NotPersistedFacet.class) == null
+        //
+        // however, that logic is wrong; although a property may not be directly
+        // persisted so far as JDO is concerned, it may be indirectly persisted
+        // as the result of business logic in the setter.
+        //
+        // for example, see ExampleTaggableEntity (in isisaddons-module-tags).
+        //
+
+        //
+        // on the other hand, we mustn't attempt to apply changes for disabled properties...
+        // even if the property is persisted (it might be written to by an action), it is never updated by
+        // an edit.
+        //
+        // Fundamentally, then, any non-disabled property (whether persisted or not) should be updated in the
+        // Isis runtime.
+        //
+
+        if(property.containsDoOpFacet(DisabledFacet.class)) {
+            // skip, as per comments above
+            return;
+        }
+
+        final ObjectAdapter associate = getObject();
+        property.set(adapter, associate, InteractionInitiatedBy.USER);
+    }
+
+
+
+
     // //////////////////////////////////////
 
     /**

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentType.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentType.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentType.java
index a4e8865..b55e74e 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentType.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentType.java
@@ -95,6 +95,10 @@ public enum ComponentType {
      */
     PARAMETERS,
     /**
+     * The edit form (property value and buttons) of an property.
+     */
+    PROPERTY_EDIT_FORM,
+    /**
      * Info details for an action, eg to display the target, a resubmit button,
      * any description or help text, and so on.
      */
@@ -104,6 +108,10 @@ public enum ComponentType {
      */
     ACTION_PROMPT,
     /**
+     * Used to display a single property for editing.
+     */
+    PROPERTY_EDIT_PROMPT,
+    /**
      * Top-level component for rendering a standalone collection (ie as returned by
      * an action).
      */

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
index d1d7020..0c31a65 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
@@ -74,7 +74,6 @@ public class ActionParametersFormPanel extends PanelAbstract<ActionModel> {
     private static final String ID_ACTION_PARAMETERS = "parameters";
 
     private final ActionExecutor actionExecutor;
-    //private final ActionPrompt actionPromptIfAny;
 
     public ActionParametersFormPanel(final String id, final ActionModel model) {
         super(id, model);

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.html
new file mode 100644
index 0000000..352c214
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.html
@@ -0,0 +1,42 @@
+<?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="propertyEditForm inputForm">
+                <form wicket:id="inputForm" method="post" class="form-horizontal propertyEditForm">
+                    <fieldset class="inputFormTable parameters">
+                        <div wicket:id="property" class="property">
+                          <div wicket:id="scalarNameAndValue">[scalar]</div>
+                        </div>
+                        <span wicket:id="feedback"></span>
+                        <div class="buttons">
+                            <input type="submit" wicket:id="okButton" value="OK" class="ok btn btn-sm btn-primary"/>
+                            <input type="submit" wicket:id="cancelButton" value="Cancel" class="cancel btn btn-sm btn-default"/>
+                        </div>
+                    </fieldset>
+                </form>
+            </div>
+        </wicket:panel>
+    </body>
+</html>
+
+
+

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
new file mode 100644
index 0000000..b51bb19
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
@@ -0,0 +1,199 @@
+/*
+ *  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.property;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.ResourceModel;
+
+import org.apache.isis.core.commons.ensure.Ensure;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.wicket.model.hints.IsisPropertyEditCompletedEvent;
+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.PropertyEditExecutor;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarModelSubscriber;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
+import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel.ScalarModelProvider;
+import org.apache.isis.viewer.wicket.ui.components.widgets.formcomponent.FormFeedbackPanel;
+import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
+import org.apache.isis.viewer.wicket.ui.errors.JGrowlUtil;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+
+/**
+ * {@link PanelAbstract Panel} to capture the arguments for an action
+ * invocation.
+ */
+public class PropertyEditFormPanel extends PanelAbstract<ScalarModel> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_OK_BUTTON = "okButton";
+    private static final String ID_CANCEL_BUTTON = "cancelButton";
+
+    private static final String ID_PROPERTY = "property";
+
+    private final PropertyEditExecutor propertyEditExecutor;
+
+    public PropertyEditFormPanel(final String id, final ScalarModel model) {
+        super(id, model);
+
+        Ensure.ensureThatArg(model.getExecutor(), is(not(nullValue())));
+
+        this.propertyEditExecutor = model.getExecutor();
+
+        buildGui();
+    }
+
+    private void buildGui() {
+        ScalarModel model = getModel();
+
+        add(new PropertyEditForm("inputForm", model));
+    }
+
+    class PropertyEditForm extends Form<ObjectAdapter> implements ScalarModelSubscriber  {
+
+        private static final long serialVersionUID = 1L;
+
+        private static final String ID_FEEDBACK = "feedback";
+        
+        private ScalarPanelAbstract propertyPanel = null;
+
+        public PropertyEditForm(final String id, final ScalarModel actionModel) {
+            super(id, actionModel);
+
+            setOutputMarkupId(true); // for ajax button
+            
+            addParameters();
+
+            FormFeedbackPanel formFeedback = new FormFeedbackPanel(ID_FEEDBACK);
+            addOrReplace(formFeedback);
+            addButtons();
+        }
+
+        private ScalarModel getScalarModel() {
+            return (ScalarModel) super.getModel();
+        }
+
+        private void addParameters() {
+            final ScalarModel scalarModel = getScalarModel();
+
+            final WebMarkupContainer container = new WebMarkupContainer(ID_PROPERTY);
+            add(container);
+
+            final Component component = getComponentFactoryRegistry().addOrReplaceComponent(container, ComponentType.SCALAR_NAME_AND_VALUE, scalarModel);
+            final ScalarPanelAbstract paramPanel = component instanceof ScalarPanelAbstract ? (ScalarPanelAbstract) component : null;
+            propertyPanel = paramPanel;
+            if(paramPanel != null) {
+                paramPanel.setOutputMarkupId(true);
+                paramPanel.notifyOnChange(this);
+            }
+        }
+
+
+        private void addButtons() {
+            AjaxButton okButton = new AjaxButton(ID_OK_BUTTON, new ResourceModel("okLabel")) {
+                private static final long serialVersionUID = 1L;
+
+                @Override
+                public void onSubmit(AjaxRequestTarget target, Form<?> form) {
+                    boolean succeeded = propertyEditExecutor.editAndProcessResults(target, form);
+                    if(succeeded) {
+                        // the Wicket ajax callbacks will have just started to hide the veil
+                        // we now show it once more, so that a veil continues to be shown until the
+                        // new page is rendered.
+                        target.appendJavaScript("isisShowVeil();\n");
+
+                        send(getPage(), Broadcast.EXACT, new IsisPropertyEditCompletedEvent(getScalarModel(), target, form));
+
+                        target.add(form);
+                    } else {
+
+                        final StringBuilder builder = new StringBuilder();
+
+                        // ensure any jGrowl errors are shown
+                        // (normally would be flushed when traverse to next page).
+                        String errorMessagesIfAny = JGrowlUtil.asJGrowlCalls(IsisContext.getMessageBroker());
+                        builder.append(errorMessagesIfAny);
+
+                        // append the JS to the response.
+                        String buf = builder.toString();
+                        target.appendJavaScript(buf);
+                        target.add(form);
+                    }
+                };
+
+                /**
+                 * On validation error
+                 */
+                @Override
+                protected void onError(AjaxRequestTarget target, Form<?> form) {
+                    super.onError(target, form);
+                    target.add(form);
+                }
+            };
+            okButton.add(new JGrowlBehaviour());
+            setDefaultButton(okButton);
+            add(okButton);
+
+            AjaxButton cancelButton = new AjaxButton(ID_CANCEL_BUTTON, new ResourceModel("cancelLabel")) {
+                private static final long serialVersionUID = 1L;
+
+                @Override
+                public void onSubmit(final AjaxRequestTarget target, Form<?> form) {
+                    final ActionPrompt actionPromptIfAny = ActionPromptProvider.Util.getFrom(PropertyEditFormPanel.this).getActionPrompt();
+                    if(actionPromptIfAny != null) {
+                        actionPromptIfAny.closePrompt(target);
+                    }
+                }
+            };
+            // so can submit with invalid content (eg mandatory params missing)
+            cancelButton.setDefaultFormProcessing(false);
+            add(cancelButton);
+
+        }
+
+        @Override
+        public void onUpdate(
+                final AjaxRequestTarget target, final ScalarModelProvider provider) {
+
+        }
+
+        public void onError(AjaxRequestTarget target, ScalarModelProvider provider) {
+            if(provider instanceof Component) {
+                // ensure that any feedback error associated with the providing component is shown.
+                target.add((Component)provider); 
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
new file mode 100644
index 0000000..50ecbf6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
@@ -0,0 +1,52 @@
+/*
+ *  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.property;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+/**
+ * {@link ComponentFactory} for {@link PropertyEditFormPanel}.
+ */
+public class PropertyEditFormPanelFactory extends ComponentFactoryAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    public PropertyEditFormPanelFactory() {
+        super(ComponentType.PROPERTY_EDIT_FORM, PropertyEditFormPanel.class);
+    }
+
+    @Override
+    public ApplicationAdvice appliesTo(final IModel<?> model) {
+        return appliesIf(model instanceof ScalarModel);
+    }
+
+    @Override
+    public Component createComponent(final String id, final IModel<?> model) {
+        final ScalarModel scalarModel = (ScalarModel) model;
+        return new PropertyEditFormPanel(id, scalarModel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.html
new file mode 100644
index 0000000..8eacbe3
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.html
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+         http://www.apache.org/licenses/LICENSE-2.0
+         
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"  
+      xml:lang="en"  
+      lang="en">
+    <body>
+        <wicket:panel>
+            <div class="propertyEditPanel propertyEditComponentType">
+                <div wicket:id="header" class="iconAndTitle panel panel-default actionPanelHeaderNew">
+                     <wicket:container wicket:id="entityIconAndTitle">[icon and title]</wicket:container>
+                </div>
+                <div wicket:id="propertyEditForm"></div>
+            </div>
+        </wicket:panel>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
new file mode 100644
index 0000000..76e48b2
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
@@ -0,0 +1,300 @@
+/*
+ *  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.property;
+
+import java.util.List;
+
+import com.google.common.base.Throwables;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.Model;
+
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.CommandContext;
+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;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+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.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.PropertyEditExecutor;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseHandlingStrategy;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+public class PropertyEditPanel extends PanelAbstract<ScalarModel>
+        implements PropertyEditExecutor {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_HEADER = "header";
+
+    private static final String ID_PROPERTY_NAME = "propertyName";
+    private static final String ID_PROPERTY = "property";
+
+    private ActionPrompt actionPrompt;
+
+    /**
+     * Gives a chance to hide the header part of this action panel, e.g. when shown in an action prompt
+     */
+    private boolean showHeader = true;
+
+    public PropertyEditPanel(final String id, final ScalarModel scalarModel) {
+        super(id, new ScalarModel(scalarModel.getParentObjectAdapterMemento(), scalarModel.getPropertyMemento()));
+        getScalarModel().setExecutor(this);
+        buildGui(getScalarModel());
+    }
+
+    /**
+     * Sets the owning action prompt (modal window), if any.
+     */
+    public void setActionPrompt(ActionPrompt actionPrompt) {
+        this.actionPrompt = actionPrompt;
+    }
+
+    @Override
+    protected void onConfigure() {
+        super.onConfigure();
+
+        buildGui(getModel());
+    }
+
+    private void buildGui(final ScalarModel scalarModel) {
+        buildGuiForParameters(scalarModel);
+    }
+
+    ScalarModel getScalarModel() {
+        return super.getModel();
+    }
+
+    public PropertyEditPanel setShowHeader(boolean showHeader) {
+        this.showHeader = showHeader;
+        return this;
+    }
+
+    private void buildGuiForParameters(final ScalarModel scalarModel) {
+
+        WebMarkupContainer header = addHeader();
+
+        ObjectAdapter targetAdapter = null;
+        try {
+            targetAdapter = scalarModel.getParentObjectAdapterMemento()
+                    .getObjectAdapter(AdapterManager.ConcurrencyChecking.CHECK);
+
+            scalarModel.toEditMode();
+
+            getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.PROPERTY_EDIT_FORM, getScalarModel());
+            getComponentFactoryRegistry().addOrReplaceComponent(header, ComponentType.ENTITY_ICON_AND_TITLE, new EntityModel(targetAdapter));
+
+            final String propertyName = getScalarModel().getPropertyMemento().getProperty().getName();
+            header.add(new Label(ID_PROPERTY_NAME, Model.of(propertyName)));
+
+        } catch (final ConcurrencyException ex) {
+
+            // second attempt should succeed, because the Oid would have
+            // been updated in the attempt
+            if (targetAdapter == null) {
+                targetAdapter = scalarModel.getParentObjectAdapterMemento()
+                        .getObjectAdapter(AdapterManager.ConcurrencyChecking.CHECK);
+            }
+
+            // page redirect/handling
+            final EntityPage entityPage = new EntityPage(targetAdapter, null);
+            setResponsePage(entityPage);
+
+            getMessageBroker().addWarning(ex.getMessage());
+        }
+    }
+
+    private WebMarkupContainer addHeader() {
+        WebMarkupContainer header = new WebMarkupContainer(ID_HEADER) {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+
+                setVisible(showHeader);
+            }
+        };
+        addOrReplace(header);
+        return header;
+    }
+
+    /**
+     * @param feedbackForm - for feedback messages.
+     * @return
+     */
+    @Override
+    public boolean editAndProcessResults(AjaxRequestTarget target, Form<?> feedbackForm) {
+
+        permanentlyHide(ComponentType.ENTITY_ICON_AND_TITLE);
+
+        ObjectAdapter targetAdapter = null;
+        try {
+            targetAdapter = getModel().getParentObjectAdapterMemento().getObjectAdapter(
+                    AdapterManager.ConcurrencyChecking.CHECK);
+
+            // no concurrency exception, so continue...
+            return editTargetAndProcessResults(targetAdapter, target, feedbackForm);
+
+        } catch (ConcurrencyException ex) {
+
+            // second attempt should succeed, because the Oid would have
+            // been updated in the attempt
+            if (targetAdapter == null) {
+                targetAdapter = getModel().getParentObjectAdapterMemento().getObjectAdapter(
+                        AdapterManager.ConcurrencyChecking.CHECK);
+            }
+
+            // page redirect/handling
+            final EntityPage entityPage = new EntityPage(targetAdapter, null);
+            setResponsePage(entityPage);
+
+            getMessageBroker().addWarning(ex.getMessage());
+            return false;
+        }
+    }
+
+
+
+    private boolean editTargetAndProcessResults(
+            final ObjectAdapter targetAdapter,
+            final AjaxRequestTarget target,
+            final Form<?> feedbackForm) {
+
+        final ScalarModel scalarModel = getScalarModel();
+
+        // validate the action parameters (if any)
+        final String invalidReasonIfAny = scalarModel.getReasonInvalidIfAny();
+
+        if (invalidReasonIfAny != null) {
+            raiseWarning(target, feedbackForm, invalidReasonIfAny);
+            return false;
+        }
+
+        final CommandContext commandContext = getServicesInjector().lookupService(CommandContext.class);
+        final Command command;
+        if (commandContext != null) {
+            command = commandContext.getCommand();
+            command.setExecutor(Command.Executor.USER);
+        } else {
+            command = null;
+        }
+
+
+        // the object store could raise an exception (eg uniqueness constraint)
+        // so we handle it here.
+        try {
+            // could be programmatic flushing, so must include in the try... finally
+
+            ObjectAdapter adapter = getScalarModel().getParentObjectAdapterMemento()
+                    .getObjectAdapter(AdapterManager.ConcurrencyChecking.CHECK);
+
+            getScalarModel().applyValue(adapter);
+
+            // flush any queued changes, so concurrency or violation exceptions (if any)
+            // will be thrown here
+            getTransactionManager().flushTransaction();
+
+            final EntityPage entityPage = new EntityPage(adapter, null);
+            setResponsePage(entityPage);
+
+            return true;
+
+        } catch (RuntimeException ex) {
+
+            String message = recognizeException(ex, target, feedbackForm);
+
+            if (message != null) {
+                // no need to add to message broker, should already have been added...
+
+                if(feedbackForm == null) {
+                    // forward on instead to void page
+                    // (otherwise, we'll have rendered an action parameters page
+                    // and so we'll be staying on that page)
+                    ActionResultResponseHandlingStrategy.REDIRECT_TO_VOID.handleResults(this, null);
+                }
+
+                return false;
+            }
+
+            // not handled, so capture and propagate
+            if(command != null) {
+                command.setException(Throwables.getStackTraceAsString(ex));
+            }
+
+            throw ex;
+        }
+    }
+
+
+    private String recognizeException(RuntimeException ex, AjaxRequestTarget target, Form<?> feedbackForm) {
+        
+        // REVIEW: this code is similar to stuff in EntityPropertiesForm, perhaps move up to superclass?
+        // REVIEW: similar code also in WebRequestCycleForIsis; combine?
+        
+        // see if the exception is recognized as being a non-serious error
+        // (nb: similar code in WebRequestCycleForIsis, as a fallback)
+        List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+        String recognizedErrorIfAny = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
+        if(recognizedErrorIfAny != null) {
+
+            // recognized
+            raiseWarning(target, feedbackForm, recognizedErrorIfAny);
+
+            getTransactionManager().getTransaction().clearAbortCause();
+            
+            // there's no need to abort the transaction, it will have already been done
+            // (in IsisTransactionManager#executeWithinTransaction(...)).
+        }
+        return recognizedErrorIfAny;
+    }
+
+    public void raiseWarning(AjaxRequestTarget target, Form<?> feedbackForm, String error) {
+        if(target != null && feedbackForm != null) {
+            target.add(feedbackForm);
+            feedbackForm.error(error);
+        } else {
+            getMessageBroker().addWarning(error);
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////
+    // Dependencies (from context)
+    ///////////////////////////////////////////////////////
+    
+    protected IsisTransactionManager getTransactionManager() {
+        return IsisContext.getTransactionManager();
+    }
+
+    protected MessageBroker getMessageBroker() {
+        return getAuthenticationSession().getMessageBroker();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
new file mode 100644
index 0000000..a5b8076
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
@@ -0,0 +1,52 @@
+/*
+ *  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.property;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+
+/**
+ * {@link ComponentFactory} for {@link PropertyEditPanel}.
+ */
+public class PropertyEditPanelFactory extends ComponentFactoryAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    public PropertyEditPanelFactory() {
+        super(ComponentType.PROPERTY_EDIT_PROMPT, PropertyEditPanel.class);
+    }
+
+    @Override
+    public ApplicationAdvice appliesTo(final IModel<?> model) {
+        return appliesIf(model instanceof ScalarModel);
+    }
+
+    @Override
+    public Component createComponent(final String id, final IModel<?> model) {
+        final ScalarModel scalarModel = (ScalarModel) model;
+        return new PropertyEditPanel(id, scalarModel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.html
new file mode 100644
index 0000000..173b259
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.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.
+-->
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:wicket="http://wicket.apache.org"
+      xml:lang="en"
+      lang="en">
+    <body>
+        <wicket:panel>
+            <div class="iconAndTitle propertyPanelHeaderNew">
+                <span wicket:enclosure="entityIconAndTitle"><span wicket:id="entityIconAndTitle">[icon and title]</span> :</span> <span wicket:id="propertyName" class="propertyName">[property name]</span>
+            </div>
+        </wicket:panel>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.java
new file mode 100644
index 0000000..f62f986
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPromptHeaderPanel.java
@@ -0,0 +1,54 @@
+/*
+ *  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.property;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.AbstractReadOnlyModel;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+
+/**
+ * A panel used as a title for the action prompts
+ */
+public class PropertyEditPromptHeaderPanel extends PanelAbstract<ScalarModel> {
+
+    private static final String ID_PROPERTY_NAME = "propertyName";
+
+    public PropertyEditPromptHeaderPanel(String id, final ScalarModel model) {
+        super(id, model);
+
+        ObjectAdapter targetAdapter =
+                model.getParentObjectAdapterMemento().getObjectAdapter(AdapterManager.ConcurrencyChecking.NO_CHECK);
+
+        getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.ENTITY_ICON_AND_TITLE, new EntityModel(targetAdapter));
+
+        add(new Label(ID_PROPERTY_NAME, new AbstractReadOnlyModel<String>() {
+            @Override
+            public String getObject() {
+                return model.getPropertyMemento().getProperty().getName();
+            }
+        }));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.html
index 4d6bd0f..e7715cd 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.html
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.html
@@ -28,7 +28,7 @@
                 <div class="form-group" wicket:id="scalarIfRegular">
                     <label wicket:id="scalarName" class="scalarName control-label">[Label text]</label>
                     <span class="scalarValueWrapper">
-                        <wicket:child/>
+                        <span class="editing"><wicket:child/><a wicket:id="editProperty" href="#" class="btn btn-link btn-xs" style="float: right;">edit</a></span>
                         <span wicket:id="feedback" class="help-block"></span>
                         <span wicket:id="associatedActionLinksBelow"></span>
                     </span>

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index a9df6fa..b3b59b1 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -25,11 +25,13 @@ import com.google.common.collect.Lists;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxEventBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
+import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.LabeledWebMarkupContainer;
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.Model;
@@ -44,11 +46,17 @@ import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
 import org.apache.isis.core.runtime.system.DeploymentType;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+import org.apache.isis.viewer.wicket.model.models.ActionPrompt;
+import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
 import org.apache.isis.viewer.wicket.model.models.EntityModel.RenderingHint;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPanel;
+import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPromptHeaderPanel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel.ScalarModelProvider;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+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;
@@ -74,6 +82,7 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
     private static final String ID_ASSOCIATED_ACTION_LINKS_BELOW = "associatedActionLinksBelow";
     private static final String ID_ASSOCIATED_ACTION_LINKS_RIGHT = "associatedActionLinksRight";
 
+    private static final String ID_EDIT_PROPERTY = "editProperty";
     private static final String ID_FEEDBACK = "feedback";
 
     public enum CompactType {
@@ -193,11 +202,13 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
                 guiForceBuilt = false;
             }
         }
+
         final ScalarModel scalarModel = getModel();
+        final String disableReasonIfAny = scalarModel.disable(getRendering().getWhere());
+
         if (scalarModel.isViewMode()) {
             onBeforeRenderWhenViewMode();
         } else {
-            final String disableReasonIfAny = scalarModel.disable(getRendering().getWhere());
             if (disableReasonIfAny != null) {
                 onBeforeRenderWhenDisabled(disableReasonIfAny);
             } else {
@@ -294,6 +305,41 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
 
     protected void addFeedbackTo(MarkupContainer markupContainer, Component component) {
         markupContainer.addOrReplace(new NotificationPanel(ID_FEEDBACK, component, new ComponentFeedbackMessageFilter(component)));
+
+        final String disableReasonIfAny = scalarModel.disable(getRendering().getWhere());
+        if (disableReasonIfAny == null && scalarModel.isViewMode()) {
+            final WebMarkupContainer editProperty = new WebMarkupContainer(ID_EDIT_PROPERTY);
+
+            editProperty.setOutputMarkupId(true);
+
+            editProperty.add(new AjaxEventBehavior("click") {
+                protected void onEvent(AjaxRequestTarget target) {
+
+                    final ActionPrompt prompt = ActionPromptProvider.Util
+                            .getFrom(ScalarPanelAbstract.this).getActionPrompt();
+
+                    PropertyEditPromptHeaderPanel titlePanel = new PropertyEditPromptHeaderPanel(prompt.getTitleId(),
+                            scalarModel);
+
+                    final PropertyEditPanel propertyEditPanel =
+                            (PropertyEditPanel) getComponentFactoryRegistry().createComponent(
+                                    ComponentType.PROPERTY_EDIT_PROMPT, prompt.getContentId(), scalarModel);
+
+                    propertyEditPanel.setShowHeader(false);
+
+                    prompt.setTitle(titlePanel, target);
+                    prompt.setPanel(propertyEditPanel, target);
+                    propertyEditPanel.setActionPrompt(prompt);
+                    prompt.showPrompt(target);
+
+                }
+            });
+
+            markupContainer.addOrReplace(editProperty);
+        } else {
+            Components.permanentlyHide(markupContainer, ID_EDIT_PROPERTY);
+        }
+
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index 61103d0..259813e 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -21,7 +21,9 @@ package org.apache.isis.viewer.wicket.ui.components.scalars;
 
 import java.io.Serializable;
 import java.util.List;
+
 import com.google.common.base.Strings;
+
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
@@ -36,11 +38,12 @@ import org.apache.wicket.model.Model;
 import org.apache.wicket.validation.IValidatable;
 import org.apache.wicket.validation.IValidator;
 import org.apache.wicket.validation.ValidationError;
+
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facets.SingleIntValueFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
-import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.EntityActionUtil;
@@ -239,6 +242,12 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
     protected void onBeforeRenderWhenViewMode() {
         super.onBeforeRenderWhenViewMode();
         textField.setEnabled(false);
+
+        final String disableReasonIfAny = scalarModel.disable(getRendering().getWhere());
+        if(disableReasonIfAny == null) {
+            CssClassAppender.appendCssClassTo(this, "editable");
+        }
+
         setTitleAttribute("");
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
index 83954d7..f7b9487 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
@@ -533,6 +533,7 @@ div.label-left label.control-label {
     text-align: left;
 }
 
+.propertyEditForm .label-left label.control-label,
 .actionParametersForm .label-left label.control-label {
     padding-left: 10px;
 }
@@ -607,7 +608,8 @@ div.label-right .scalarValueWrapper .control-label{
 /* Labels on the left/top/none END */
 
 
-.form-horizontal.actionParametersForm .form-group {
+.form-horizontal.actionParametersForm .form-group,
+.form-horizontal.propertyEditForm .form-group {
     margin-left: -5px;
 }
 
@@ -661,6 +663,7 @@ div.referencePanel.scalarNameAndValueComponentType {
     font-style: italic;
 }
 
+.propertyEditForm .buttons,
 .actionParametersForm .buttons {
     padding-top: 20px;
 }
@@ -765,4 +768,9 @@ tr.headers th form input {
 .additionalLinkListDropDown ul.dropdown-menu {
     padding-top: 0%;
     padding-bottom: 0%;
-}
\ No newline at end of file
+}
+
+/* cheap and nasty; ought really to suppress in Java code ... */
+.propertyEditForm .additionalLinkList {
+    display: none;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
index 512a499..e59913c 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
@@ -138,6 +138,17 @@ $(function() {
             $('.copyLink').css({visibility: 'hidden'});
         }
     );
+
+/*
+    $('.editing .editable').parent().hover(function () {
+        var inputEl = $(this).find("> .editable")
+        $(inputEl).css({cursor: 'pointer'})
+    },function () {
+        var inputEl = $(this).find("> .editable")
+        $(inputEl).css({cursor: 'auto'})
+    });
+*/
+
 });
 
 /**

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.java
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.java b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.java
index 706db7a..6ac1bf3 100644
--- a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.java
+++ b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.java
@@ -31,7 +31,6 @@ import org.apache.isis.applib.annotation.BookmarkPolicy;
 import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
-import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Parameter;
 import org.apache.isis.applib.annotation.ParameterLayout;
@@ -86,7 +85,7 @@ public class SimpleObject implements Comparable<SimpleObject> {
             length = NAME_LENGTH
     )
     @Property(
-            editing = Editing.DISABLED
+            //editing = Editing.DISABLED
     )
     @PropertyLayout(
             namedEscaped = false
@@ -99,6 +98,9 @@ public class SimpleObject implements Comparable<SimpleObject> {
         this.name = name;
     }
 
+    public TranslatableString validateName(final String name) {
+        return name != null && name.contains("!")? TranslatableString.tr("Exclamation mark is not allowed"): null;
+    }
 
 
     public static class UpdateNameDomainEvent extends ActionDomainEvent<SimpleObject> {}

http://git-wip-us.apache.org/repos/asf/isis/blob/de3e385f/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
index 9012b51..c0eaded 100644
--- a/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
+++ b/example/application/simpleapp/dom/src/main/java/domainapp/dom/simple/SimpleObject.layout.xml
@@ -14,6 +14,7 @@
                         <bs3:col span="12">
                             <c:fieldSet name="Properties">
                                 <c:property id="name"/>
+                                <c:property id="versionSequence"/>
                             </c:fieldSet>
                         </bs3:col>
                     </bs3:row>