You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/11/27 18:06:22 UTC

[10/15] isis git commit: ISIS-537: new @ActionLayout annotation and corresponding facet. Applies "actions-right" CSS if there are any actions associated with property that have layout to the right.

ISIS-537: new @ActionLayout annotation and corresponding facet.  Applies "actions-right" CSS if there are any actions associated with property that have layout to the right.

Refactored the call to add additionalLinks so that can obtain the list of LinkAndLabel (representing the entity actions) in order to pass into the method that adds the CSS
* that method itself has been renamed/refactored: was previously called "applyLabelAtRule(MarkupContainer)", is now called "addPositioningCssTo(MarkupContainer, List<LinkAndLabel>)"


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

Branch: refs/heads/master
Commit: 6393ac9217a3f3c5bc150e28ec54bef98cd19e5e
Parents: 6ffdaf0
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu Nov 27 11:23:06 2014 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu Nov 27 11:23:06 2014 +0000

----------------------------------------------------------------------
 .../viewer/wicket/model/links/LinkAndLabel.java | 10 ++-
 .../additionallinks/EntityActionUtil.java       | 10 +--
 .../collection/bulk/BulkActionsLinkFactory.java | 15 ++--
 .../entity/EntityActionLinkFactory.java         |  4 --
 .../components/scalars/ScalarPanelAbstract.java | 73 ++++++++++++--------
 .../scalars/ScalarPanelTextFieldAbstract.java   | 18 ++++-
 .../ScalarPanelTextFieldDatePickerAbstract.java |  2 -
 .../isisapplib/IsisBlobOrClobPanelAbstract.java | 17 ++++-
 .../scalars/primitive/BooleanPanel.java         | 15 +++-
 .../scalars/reference/ReferencePanel.java       | 15 +++-
 .../cssmenu/ActionLinkFactoryAbstract.java      | 18 ++---
 .../components/widgets/cssmenu/CssMenuItem.java | 61 ++--------------
 .../valuechoices/ValueChoicesSelect2Panel.java  | 16 ++++-
 .../wicket/ui/pages/bootstrap-overrides.css     |  4 ++
 .../viewer/wicket/ui/util/CssClassAppender.java | 16 +++++
 .../isis/applib/annotation/ActionLayout.java    | 44 ++++++++++++
 .../isis/applib/annotation/MemberOrder.java     | 17 +++--
 .../actions/layout/ActionLayoutFacet.java       | 45 ++++++++++++
 .../layout/ActionLayoutFacetAbstract.java       | 50 ++++++++++++++
 .../layout/ActionLayoutFacetAnnotation.java     | 31 +++++++++
 .../layout/ActionLayoutFacetFactory.java        | 65 +++++++++++++++++
 .../layout/ActionLayoutFacetFallback.java       | 31 +++++++++
 .../layout/ActionLayoutFacetFromProperties.java | 36 ++++++++++
 .../facets/members/order/MemberOrderFacet.java  | 13 +++-
 .../layoutmetadata/ActionLayoutFacetRepr.java   | 22 ++++++
 .../metamodel/layoutmetadata/ActionRepr.java    |  1 +
 .../json/LayoutMetadataReaderFromJson.java      |  4 ++
 .../metamodel/spec/feature/ObjectAction.java    | 54 +++++++++++++++
 .../dflt/ProgrammingModelFacetsJava5.java       |  3 +
 .../ActionLayoutAnnotationFacetFactoryTest.java | 70 +++++++++++++++++++
 30 files changed, 649 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
index a961b1f..37a4704 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
@@ -21,6 +21,7 @@ package org.apache.isis.viewer.wicket.model.links;
 import java.io.Serializable;
 
 import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.isis.applib.annotation.ActionLayout;
 
 public class LinkAndLabel implements Serializable {
     
@@ -35,6 +36,7 @@ public class LinkAndLabel implements Serializable {
     private final String actionIdentifier;
     private final String cssClass;
     private final String cssClassFa;
+    private final ActionLayout.Position position;
 
     public LinkAndLabel(
             final AbstractLink link,
@@ -45,7 +47,8 @@ public class LinkAndLabel implements Serializable {
             final boolean prototype,
             final String identifier,
             final String cssClass,
-            final String cssClassFa) {
+            final String cssClassFa,
+            final ActionLayout.Position position) {
         this.link = link;
         this.label = label;
         this.disabledReasonIfAny = disabledReasonIfAny;
@@ -55,6 +58,7 @@ public class LinkAndLabel implements Serializable {
         this.actionIdentifier = identifier;
         this.cssClass = cssClass;
         this.cssClassFa = cssClassFa;
+        this.position = position;
     }
 
     public AbstractLink getLink() {
@@ -92,4 +96,8 @@ public class LinkAndLabel implements Serializable {
     public String getCssClassFa() {
         return cssClassFa;
     }
+
+    public ActionLayout.Position getPosition() {
+        return position;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
index 3dc5598..a2ff4bc 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
@@ -53,21 +53,21 @@ public final class EntityActionUtil {
 
     private final static MemberOrderFacetComparator memberOrderFacetComparator = new MemberOrderFacetComparator(false);
 
-    public static void appendAdditionalLinksForAssociation(
+    public static List<LinkAndLabel> appendAdditionalLinksForAssociation(
             final ScalarModel scalarModel,
             final DeploymentType deploymentType,
             final String id,
             final List<LinkAndLabel> entityActionLinks) {
 
         if (scalarModel.getKind() != ScalarModel.Kind.PROPERTY) {
-            return;
+            return entityActionLinks;
         }
 
         final ObjectAdapterMemento parentMemento = scalarModel.getParentObjectAdapterMemento();
         final EntityModel parentEntityModel = new EntityModel(parentMemento);
         final OneToOneAssociation oneToOneAssociation = scalarModel.getPropertyMemento().getProperty();
 
-        appendAdditionalLinksForAssociation(
+        return appendAdditionalLinksForAssociation(
                 parentEntityModel,
                 oneToOneAssociation,
                 deploymentType,
@@ -75,7 +75,7 @@ public final class EntityActionUtil {
                 entityActionLinks);
     }
 
-    public static void appendAdditionalLinksForAssociation(
+    public static List<LinkAndLabel> appendAdditionalLinksForAssociation(
             final EntityModel entityModel,
             final ObjectAssociation association,
             final DeploymentType deploymentType,
@@ -110,6 +110,8 @@ public final class EntityActionUtil {
             }
         });
         entityActionLinks.addAll(linkAndLabels);
+
+        return entityActionLinks;
     }
 
     private static List<ObjectAction> addActions(

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
index 1627c6d..f628014 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
@@ -26,6 +26,7 @@ import org.apache.wicket.Session;
 import org.apache.wicket.markup.html.link.AbstractLink;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.Bulk.InteractionContext.InvokedAs;
 import org.apache.isis.applib.services.command.Command;
@@ -49,7 +50,6 @@ import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponse;
 import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseType;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.ActionLinkFactory;
-import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem;
 import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
 
 public final class BulkActionsLinkFactory implements ActionLinkFactory {
@@ -199,13 +199,14 @@ public final class BulkActionsLinkFactory implements ActionLinkFactory {
         };
         link.add(new JGrowlBehaviour());
 
-        final boolean explorationOrPrototype = CssMenuItem.isExplorationOrPrototype(objectAction);
-        final String actionIdentifier = CssMenuItem.actionIdentifierFor(objectAction);
-        final String description = CssMenuItem.descriptionOf(objectAction);
-        final String cssClass = CssMenuItem.cssClassFor(objectAction);
-        final String cssClassFa = CssMenuItem.cssClassFaFor(objectAction);
+        final boolean explorationOrPrototype = ObjectAction.Utils.isExplorationOrPrototype(objectAction);
+        final String actionIdentifier = ObjectAction.Utils.actionIdentifierFor(objectAction);
+        final String description = ObjectAction.Utils.descriptionOf(objectAction);
+        final String cssClass = ObjectAction.Utils.cssClassFor(objectAction);
+        final String cssClassFa = ObjectAction.Utils.cssClassFaFor(objectAction);
+        final ActionLayout.Position position = ObjectAction.Utils.actionLayoutPositionOf(objectAction);
 
-        return new LinkAndLabel(link, objectAction.getName(), null, description, false, explorationOrPrototype, actionIdentifier, cssClass, cssClassFa);
+        return new LinkAndLabel(link, objectAction.getName(), null, description, false, explorationOrPrototype, actionIdentifier, cssClass, cssClassFa, position);
     }
     
     

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
index cfafab7..17a55e4 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
@@ -84,10 +84,6 @@ public final class EntityActionLinkFactory extends ActionLinkFactoryAbstract {
     // Dependencies (from IsisContext)
     // ///////////////////////////////////////////////////////////////////
 
-    protected IsisContext getIsisContext() {
-        return IsisContext.getInstance();
-    }
-
     protected PersistenceSession getPersistenceSession() {
         return IsisContext.getPersistenceSession();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index 2d6ce7c..3aeb759 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -30,12 +30,13 @@ 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.basic.Label;
 import org.apache.wicket.markup.html.form.LabeledWebMarkupContainer;
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.Model;
+import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.actions.layout.ActionLayoutFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.propparam.labelat.LabelAtFacet;
 import org.apache.isis.core.runtime.system.DeploymentType;
@@ -43,8 +44,6 @@ 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.EntityModel.RenderingHint;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.ui.components.additionallinks.AdditionalLinksPanel;
-import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 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.CssClassAppender;
@@ -67,8 +66,8 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
 
     protected static final String ID_SCALAR_IF_COMPACT = "scalarIfCompact";
 
-    private static final String ID_ADDITIONAL_LINKS = "additionalLinks";
-    public static final String ID_ADDITIONAL_LINK = "additionalLink";
+    protected static final String ID_ADDITIONAL_LINKS = "additionalLinks";
+    protected static final String ID_ADDITIONAL_LINK = "additionalLink";
 
     private static final String ID_FEEDBACK = "feedback";
 
@@ -274,7 +273,7 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
         ScalarModel model = getModel();
         final CssClassFacet facet = model.getFacet(CssClassFacet.class);
         if(facet != null) {
-              add(new CssClassAppender(facet.value()));
+            CssClassAppender.appendCssClassTo(this, facet.value());
         }
     }
 
@@ -289,15 +288,6 @@ 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)));
     }
-    
-    protected void addAdditionalLinksTo(final MarkupContainer labelIfRegular) {
-        // find the links...
-        final List<LinkAndLabel> entityActions = Lists.newArrayList();
-
-        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
-        // ... and add them to the panel
-        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
-    }
 
 
     /**
@@ -319,33 +309,56 @@ public abstract class ScalarPanelAbstract extends PanelAbstract<ScalarModel> imp
     }
 
     /**
-     * Applies the {@literal @}{@link org.apache.isis.applib.annotation.LabelAt LabelAt} facet
+     * Applies the {@literal @}{@link org.apache.isis.applib.annotation.LabelAt LabelAt} facet and also CSS based on
+     * whether any of the associated actions have {@literal @}{@link org.apache.isis.applib.annotation.ActionLayout layout} positioned to
+     * the {@link org.apache.isis.applib.annotation.ActionLayout.Position#RIGHT right}.
      *
-     * @param scalarName The label for the input
-     * @param formGroup The form group element
+     * @param markupContainer The form group element
+     * @param entityActionLinks
      */
-    protected void applyLabelAtRule(Label scalarName, MarkupContainer formGroup) {
+    protected void addPositioningCssTo(final MarkupContainer markupContainer, final List<LinkAndLabel> entityActionLinks) {
+        CssClassAppender.appendCssClassTo(markupContainer, determineLabelAtCss(getModel()));
+        boolean actionsPositionedOnRight = hasActionsPositioned(entityActionLinks, ActionLayout.Position.RIGHT);
+        if(actionsPositionedOnRight) {
+            CssClassAppender.appendCssClassTo(markupContainer, "actions-right");
+        }
+    }
 
-        final LabelAtFacet facet = getModel().getFacet(LabelAtFacet.class);
+    private static boolean hasActionsPositioned(final List<LinkAndLabel> entityActionLinks, final ActionLayout.Position position) {
+        for (LinkAndLabel entityActionLink : entityActionLinks) {
+            if(entityActionLink.getPosition() == position) {
+                return true;
+            }
+        }
+        return false;
+    }
 
+    private static String determineLabelAtCss(ScalarModel model) {
+        final LabelAtFacet facet = model.getFacet(LabelAtFacet.class);
         if (facet != null) {
             switch (facet.value()) {
                 case LEFT:
-                    formGroup.add(new CssClassAppender("label-left"));
-                    break;
+                    return "label-left";
                 case NONE:
-                    formGroup.add(new CssClassAppender("label-none"));
-                    break;
+                    return "label-none";
                 case TOP:
-                    formGroup.add(new CssClassAppender("label-top"));
-                    break;
-                default:
-                    break;
+                    return "label-top";
+            }
+        }
+        return "label-left";
+    }
 
+    private static String determineActionLayoutCss(ScalarModel model) {
+        final ActionLayoutFacet facet = model.getFacet(ActionLayoutFacet.class);
+        if (facet != null) {
+            switch (facet.position()) {
+                case BELOW:
+                    return "action-below";
+                case RIGHT:
+                    return "action-right";
             }
-        } else {
-            formGroup.add(new CssClassAppender("label-left"));
         }
+        return null;
     }
 
     // //////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index d17404d..5b65910 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -20,8 +20,10 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars;
 
 import java.io.Serializable;
+import java.util.List;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
@@ -37,7 +39,10 @@ import org.apache.wicket.model.Model;
 import org.apache.isis.core.metamodel.facets.SingleIntValueFacet;
 import org.apache.isis.core.metamodel.facets.propparam.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.facets.objpropparam.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.additionallinks.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
@@ -100,7 +105,12 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
 
         final Label scalarName = new Label(ID_SCALAR_NAME, getRendering().getLabelCaption(textField));
 
-        applyLabelAtRule(scalarName, labelIfRegular);
+        // find the links...
+        final List<LinkAndLabel> entityActions = Lists.newArrayList();
+
+        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
+
+        addPositioningCssTo(labelIfRegular, entityActions);
 
         if(getModel().isRequired()) {
             final String label = scalarName.getDefaultModelObjectAsString();
@@ -117,8 +127,10 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
         }
         
         addFeedbackTo(labelIfRegular, textField);
-        addAdditionalLinksTo(labelIfRegular);
-        
+
+        // ... and add them to the panel
+        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
+
         return labelIfRegular;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldDatePickerAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldDatePickerAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldDatePickerAbstract.java
index 79c37b5..9aeb23e 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldDatePickerAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldDatePickerAbstract.java
@@ -29,7 +29,6 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
 import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.panel.Fragment;
-import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.validation.IValidatable;
 import org.apache.wicket.validation.IValidator;
@@ -40,7 +39,6 @@ import org.apache.isis.core.metamodel.facets.propparam.renderedadjusted.Rendered
 import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.datepicker.TextFieldWithDatePicker;
-import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
 /**
  * Panel for rendering scalars representing dates, along with a date picker.

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/isisapplib/IsisBlobOrClobPanelAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/isisapplib/IsisBlobOrClobPanelAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/isisapplib/IsisBlobOrClobPanelAbstract.java
index c122780..3a56411 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/isisapplib/IsisBlobOrClobPanelAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/isisapplib/IsisBlobOrClobPanelAbstract.java
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.util.List;
 import javax.activation.MimeType;
 import javax.imageio.ImageIO;
+import com.google.common.collect.Lists;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -49,7 +50,10 @@ import org.apache.isis.applib.value.Blob;
 import org.apache.isis.applib.value.NamedWithMimeType;
 import org.apache.isis.core.commons.lang.CloseableExtensions;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+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.additionallinks.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
 import org.apache.isis.viewer.wicket.ui.util.Components;
@@ -92,7 +96,12 @@ public abstract class IsisBlobOrClobPanelAbstract<T extends NamedWithMimeType> e
         final Label scalarName = new Label(ID_SCALAR_NAME, getModel().getName());
         labelIfRegular.add(scalarName);
 
-        applyLabelAtRule(scalarName, labelIfRegular);
+        // find the links...
+        final List<LinkAndLabel> entityActions = Lists.newArrayList();
+
+        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
+
+        addPositioningCssTo(labelIfRegular, entityActions);
 
         wicketImage = asWicketImage(ID_IMAGE);
         if(wicketImage != null) {
@@ -107,8 +116,10 @@ public abstract class IsisBlobOrClobPanelAbstract<T extends NamedWithMimeType> e
         
         addOrReplace(labelIfRegular);
         addFeedbackTo(labelIfRegular, fileUploadField);
-        addAdditionalLinksTo(labelIfRegular);
-        
+
+        // ... and add them to the panel
+        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
+
         return labelIfRegular;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
index 7e72963..efba774 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
@@ -22,6 +22,8 @@ package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkboxx.CheckBoxX;
 import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkboxx.CheckBoxXConfig;
 
+import java.util.List;
+import com.google.common.collect.Lists;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
@@ -30,7 +32,10 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.Model;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+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.additionallinks.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
@@ -78,12 +83,16 @@ public class BooleanPanel extends ScalarPanelAbstract {
         final Label scalarName = new Label(ID_SCALAR_NAME, getRendering().getLabelCaption(checkBox));
         labelIfRegular.add(scalarName);
 
-        applyLabelAtRule(scalarName, labelIfRegular);
+        final List<LinkAndLabel> entityActions = Lists.newArrayList();
+        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
+
+        addPositioningCssTo(labelIfRegular, entityActions);
 
         addOrReplace(labelIfRegular);
-        
         addFeedbackTo(labelIfRegular, checkBox);
-        addAdditionalLinksTo(labelIfRegular);
+
+        // ... and add them to the panel
+        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
 
         return labelIfRegular;
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
index eca7b0e..be7921f 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
@@ -42,12 +42,15 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.facets.object.autocomplete.AutoCompleteFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModelWithPending.Util;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.ObjectAdapterMementoProviderAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
@@ -126,13 +129,19 @@ public class ReferencePanel extends ScalarPanelAbstract {
         final Label scalarName = new Label(ID_SCALAR_NAME, getRendering().getLabelCaption(entityLink));
         labelIfRegular.add(scalarName);
 
-        applyLabelAtRule(scalarName, labelIfRegular);
+        // find the links...
+        final List<LinkAndLabel> entityActions = Lists.newArrayList();
+        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
+
+        addPositioningCssTo(labelIfRegular, entityActions);
 
         addOrReplace(labelIfRegular);
         
         addFeedbackTo(labelIfRegular, entityLink);
-        addAdditionalLinksTo(labelIfRegular);
-        
+
+        // ... and add them to the panel
+        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
+
         // add semantics
         entityLink.setRequired(getModel().isRequired());
         entityLink.add(new IValidator<ObjectAdapter>() {

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
index 5e41856..48eb9d2 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
@@ -36,6 +36,7 @@ import org.apache.wicket.request.IRequestHandler;
 import org.apache.wicket.util.visit.IVisit;
 import org.apache.wicket.util.visit.IVisitor;
 import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -244,14 +245,15 @@ public abstract class ActionLinkFactoryAbstract implements ActionLinkFactory {
     protected LinkAndLabel newLinkAndLabel(final ObjectAction objectAction, final AbstractLink link, final String disabledReasonIfAny) {
 
         final String label = ObjectAction.Utils.nameFor(objectAction);
-        final boolean blobOrClob = CssMenuItem.returnsBlobOrClob(objectAction);
-        final boolean prototype = CssMenuItem.isExplorationOrPrototype(objectAction);
-        final String actionIdentifier = CssMenuItem.actionIdentifierFor(objectAction);
-        final String description = CssMenuItem.descriptionOf(objectAction);
-        final String cssClass = CssMenuItem.cssClassFor(objectAction);
-        final String cssClassFa = CssMenuItem.cssClassFaFor(objectAction);
-
-        return new LinkAndLabel(link, label, disabledReasonIfAny, description, blobOrClob, prototype, actionIdentifier, cssClass, cssClassFa);
+        final boolean blobOrClob = ObjectAction.Utils.returnsBlobOrClob(objectAction);
+        final boolean prototype = ObjectAction.Utils.isExplorationOrPrototype(objectAction);
+        final String actionIdentifier = ObjectAction.Utils.actionIdentifierFor(objectAction);
+        final String description = ObjectAction.Utils.descriptionOf(objectAction);
+        final ActionLayout.Position position = ObjectAction.Utils.actionLayoutPositionOf(objectAction);
+        final String cssClass = ObjectAction.Utils.cssClassFor(objectAction);
+        final String cssClassFa = ObjectAction.Utils.cssClassFaFor(objectAction);
+
+        return new LinkAndLabel(link, label, disabledReasonIfAny, description, blobOrClob, prototype, actionIdentifier, cssClass, cssClassFa, position);
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
index b57c630..8d8c157 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuItem.java
@@ -32,19 +32,14 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.SubmitLink;
 import org.apache.wicket.markup.html.link.AbstractLink;
 import org.apache.wicket.model.Model;
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.value.Blob;
-import org.apache.isis.applib.value.Clob;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.ensure.Ensure;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.consent.Consent;
-import org.apache.isis.core.metamodel.facets.SingleStringValueFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
@@ -333,58 +328,16 @@ public class CssMenuItem implements Serializable {
                 .link(link)
                 .describedAs(descriptionIfAny)
                 .enabled(reasonDisabledIfAny)
-                .returnsBlobOrClob(returnsBlobOrClob(objectAction))
-                .prototyping(isExplorationOrPrototype(objectAction))
+                .returnsBlobOrClob(ObjectAction.Utils.returnsBlobOrClob(objectAction))
+                .prototyping(ObjectAction.Utils.isExplorationOrPrototype(objectAction))
                 .separator(separator)
-                .withActionIdentifier(actionIdentifierFor(objectAction))
-                .withCssClass(cssClassFor(objectAction))
-                .withCssClassFa(cssClassFaFor(objectAction));
+                .withActionIdentifier(ObjectAction.Utils.actionIdentifierFor(objectAction))
+                .withCssClass(ObjectAction.Utils.cssClassFor(objectAction))
+                .withCssClassFa(ObjectAction.Utils.cssClassFaFor(objectAction));
 
         return builder;
     }
 
-    public static boolean returnsBlobOrClob(final ObjectAction objectAction) {
-        boolean blobOrClob = false;
-        final ObjectSpecification returnType = objectAction.getReturnType();
-        if(returnType != null) {
-            Class<?> cls = returnType.getCorrespondingClass();
-            if (Blob.class.isAssignableFrom(cls) || Clob.class.isAssignableFrom(cls)) {
-                blobOrClob = true;
-            }
-        }
-        return blobOrClob;
-    }
-
-    public static boolean isExplorationOrPrototype(final ObjectAction action) {
-        return action.getType().isExploration() || action.getType().isPrototype();
-    }
-
-    public static String descriptionOf(ObjectAction action) {
-        return action.getDescription();
-    }
-
-
-    public static String actionIdentifierFor(final ObjectAction action) {
-        @SuppressWarnings("unused")
-        final Identifier identifier = action.getIdentifier();
-        
-        final String className = action.getOnType().getShortIdentifier();
-        final String actionId = action.getId();
-        return className + "-" + actionId;
-    }
-
-    public static String cssClassFor(final ObjectAction action) {
-        return facetValueIfAnyFor(action, CssClassFacet.class);
-    }
-
-    public static String cssClassFaFor(final ObjectAction action) {
-        return facetValueIfAnyFor(action, CssClassFaFacet.class);
-    }
-
-    private static String facetValueIfAnyFor(ObjectAction action, Class<? extends SingleStringValueFacet> x) {
-        final SingleStringValueFacet singleStringValueFacet = action.getFacet(x);
-        return singleStringValueFacet != null ? singleStringValueFacet.value() : null;
-    }
 
     /**
      * Creates a {@link Builder} for a submenu item where the provided {@link ActionLinkFactory} is able to provide the target adapter.
@@ -399,8 +352,8 @@ public class CssMenuItem implements Serializable {
         final String actionLabel = linkAndLabel.getLabel();
         Builder builder = this.newSubMenuItem(actionLabel)
                               .link(link)
-                .prototyping(linkAndLabel.isPrototype())
-                .returnsBlobOrClob(linkAndLabel.isBlobOrClob())
+                              .prototyping(linkAndLabel.isPrototype())
+                              .returnsBlobOrClob(linkAndLabel.isBlobOrClob())
                               .withFacet(objectAction.getFacet(CssClassFacet.class))
                               .withFacet(objectAction.getFacet(CssClassFaFacet.class));
         return builder;

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
index e30d698..5066334 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
@@ -34,9 +34,12 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModelWithPending;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.AdditionalLinksPanel;
+import org.apache.isis.viewer.wicket.ui.components.additionallinks.EntityActionUtil;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.ObjectAdapterMementoProviderAbstract;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
@@ -82,11 +85,18 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
         final Label scalarName = new Label(ID_SCALAR_NAME, getRendering().getLabelCaption(select2Field));
         labelIfRegular.addOrReplace(scalarName);
 
-        applyLabelAtRule(scalarName, labelIfRegular);
+        // find the links...
+        final List<LinkAndLabel> entityActions = Lists.newArrayList();
+
+        EntityActionUtil.appendAdditionalLinksForAssociation(this.scalarModel, getDeploymentType(), ID_ADDITIONAL_LINK, entityActions);
+
+        addPositioningCssTo(labelIfRegular, entityActions);
 
         addFeedbackTo(labelIfRegular, select2Field);
-        addAdditionalLinksTo(labelIfRegular);
-        
+
+        // ... and add them to the panel
+        AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ADDITIONAL_LINKS, entityActions, AdditionalLinksPanel.Style.INLINE_LIST);
+
         return labelIfRegular;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
index 3107426..3010db3 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/bootstrap-overrides.css
@@ -130,6 +130,10 @@ div.label-left .scalarValueWrapper {
     float: left;
 }
 
+div.label-left.actions-right .scalarValueWrapper {
+    width: 62%;
+}
+
 div.label-top .scalarValueWrapper,
 div.label-none .scalarValueWrapper {
     width: 99%;

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/CssClassAppender.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/CssClassAppender.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/CssClassAppender.java
index 8c4e1c0..28aeadc 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/CssClassAppender.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/CssClassAppender.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.viewer.wicket.ui.util;
 
+import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
@@ -39,6 +40,21 @@ public class CssClassAppender extends AttributeAppender {
         this(Model.of(append));
     }
 
+    /**
+     * Adds CSS class to container (providing that the class is non-null.
+     */
+    public static void appendCssClassTo(
+            final MarkupContainer markupContainer,
+            final String cssClass) {
+        if(cssClass == null) {
+            return;
+        }
+        markupContainer.add(new CssClassAppender(cssClass));
+    }
+
+    /**
+     * Utility method to sanitize string into a single CSS class.
+     */
     public static String asCssStyle(final String str) {
         return str.toLowerCase().replaceAll("[^A-Za-z0-9- ]", "").replaceAll("\\s+", "-");
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
new file mode 100644
index 0000000..0614d1b
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/ActionLayout.java
@@ -0,0 +1,44 @@
+/*
+ *  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.applib.annotation;
+
+/**
+ * Layout hints for actions.
+ */
+public @interface ActionLayout {
+
+    /**
+     * If associated with a property, indicates the positioning of the
+     * action's button relative to the property.
+     *
+     * <p>
+     * Ignored if the action has not been associated with a property.
+     * </p>
+     */
+    Position position() default Position.BELOW;
+
+    enum Position {
+        BELOW,
+        RIGHT,
+        PANEL,
+        PANEL_DROPDOWN
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/applib/src/main/java/org/apache/isis/applib/annotation/MemberOrder.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/MemberOrder.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/MemberOrder.java
index 3164278..a5b44ad 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/MemberOrder.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/MemberOrder.java
@@ -34,12 +34,21 @@ import java.lang.annotation.Target;
 public @interface MemberOrder {
 
     /**
-     * Number in Dewey Decimal format representing the order.
+     * Groups or associate members with each other.
+     *
+     * <ul>
+     *     <li>For actions, indicates the property or collection to associate.</li>
+     *     <li>For properties, indicates the property group</li>
+     *     <li>For collections, currently has no meaning</li>
+     * </ul>
      */
-    String sequence();
+    String name() default "";
 
     /**
-     * Name of the group this set should be known as.
+     * The order of this member relative to other members in the same group, in
+     * dewey-decimal notation.  For collections this is relative to each other
+     * (collections aren't grouped).
      */
-    String name() default "";
+    String sequence();
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacet.java
new file mode 100644
index 0000000..12d87e2
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacet.java
@@ -0,0 +1,45 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+
+/**
+ * The preferred mechanism for determining the order in which the members of the
+ * object should be rendered.
+ * 
+ * <p>
+ * In the standard Apache Isis Programming Model, corresponds to annotating each
+ * of the member methods with the <tt>@ActionLayout</tt>.
+ */
+public interface ActionLayoutFacet extends Facet {
+
+    /**
+     * If associated with a property, indicates the positioning of the
+     * action's button relative to the property.
+     *
+     * <p>
+     * Ignored if the action has not been associated with a property.
+     * </p>
+     */
+    public ActionLayout.Position position();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAbstract.java
new file mode 100644
index 0000000..1b8a8b52
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAbstract.java
@@ -0,0 +1,50 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+
+public abstract class ActionLayoutFacetAbstract extends FacetAbstract implements ActionLayoutFacet {
+
+    public static Class<? extends Facet> type() {
+        return ActionLayoutFacet.class;
+    }
+
+    private final ActionLayout.Position position;
+
+    public ActionLayoutFacetAbstract(final ActionLayout.Position position, final FacetHolder holder) {
+        super(type(), holder, Derivation.NOT_DERIVED);
+        this.position = position;
+    }
+
+    @Override
+    public ActionLayout.Position position() {
+        return position;
+    }
+
+    @Override
+    protected String toStringValues() {
+        return "position=" + position;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAnnotation.java
new file mode 100644
index 0000000..0ab9179
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetAnnotation.java
@@ -0,0 +1,31 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+
+public class ActionLayoutFacetAnnotation extends ActionLayoutFacetAbstract {
+
+    public ActionLayoutFacetAnnotation(final ActionLayout.Position position, final FacetHolder holder) {
+        super(position, holder);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
new file mode 100644
index 0000000..bf1b3de
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
@@ -0,0 +1,65 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import java.util.Properties;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.ContributeeMemberFacetFactory;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+
+public class ActionLayoutFacetFactory extends FacetFactoryAbstract implements ContributeeMemberFacetFactory {
+
+    public ActionLayoutFacetFactory() {
+        super(FeatureType.ACTIONS_ONLY);
+    }
+
+    @Override
+    public void process(final ProcessMethodContext processMethodContext) {
+        ActionLayoutFacet facet = createFromMetadataPropertiesIfPossible(processMethodContext);
+        if(facet == null) {
+            facet = createFromAnnotationIfPossible(processMethodContext);
+        }
+        
+        // no-op if null
+        FacetUtil.addFacet(facet);
+    }
+
+    @Override
+    public void process(ProcessContributeeMemberContext processMemberContext) {
+    }
+    
+    private static ActionLayoutFacet createFromMetadataPropertiesIfPossible(
+            final ProcessContextWithMetadataProperties<? extends FacetHolder> pcwmp) {
+        
+        final FacetHolder holder = pcwmp.getFacetHolder();
+        
+        final Properties properties = pcwmp.metadataProperties("actionLayout");
+        return properties != null ? new ActionLayoutFacetFromProperties(properties, holder) : null;
+    }
+
+    private static ActionLayoutFacetAnnotation createFromAnnotationIfPossible(final ProcessMethodContext processMethodContext) {
+        final ActionLayout annotation = Annotations.getAnnotation(processMethodContext.getMethod(), ActionLayout.class);
+        return (annotation != null) ? new ActionLayoutFacetAnnotation(annotation.position(), processMethodContext.getFacetHolder()) : null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFallback.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFallback.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFallback.java
new file mode 100644
index 0000000..d2909ad
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFallback.java
@@ -0,0 +1,31 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+
+public class ActionLayoutFacetFallback extends ActionLayoutFacetAbstract {
+
+    public ActionLayoutFacetFallback(final FacetHolder holder) {
+        super(ActionLayout.Position.BELOW, holder);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFromProperties.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFromProperties.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFromProperties.java
new file mode 100644
index 0000000..f3c7a3d
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFromProperties.java
@@ -0,0 +1,36 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import java.util.Properties;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+
+public class ActionLayoutFacetFromProperties extends ActionLayoutFacetAbstract {
+
+    public ActionLayoutFacetFromProperties(Properties properties, FacetHolder holder) {
+        super(valueFrom(properties), holder);
+    }
+
+    private static ActionLayout.Position valueFrom(Properties properties) {
+        return ActionLayout.Position.valueOf(properties.getProperty("position"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacet.java
index 80e3f57..75d0414 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/members/order/MemberOrderFacet.java
@@ -39,13 +39,22 @@ import org.apache.isis.core.metamodel.facets.object.fieldorder.FieldOrderFacet;
 public interface MemberOrderFacet extends MultipleValueFacet {
 
     /**
-     * To group members.
+     * Groups or associate members with each other.
+     *
+     * <ul>
+     *     <li>For actions, indicates the property or collection to associate.</li>
+     *     <li>For properties, indicates the property group</li>
+     *     <li>For collections, currently has no meaning</li>
+     * </ul>
      */
     public String name();
 
     /**
-     * The sequence, in dewey-decimal notation.
+     * The order of this member relative to other members in the same group, in
+     * dewey-decimal notation.  For collections this is relative to each other
+     * (collections aren't grouped).
      */
     public String sequence();
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionLayoutFacetRepr.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionLayoutFacetRepr.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionLayoutFacetRepr.java
new file mode 100644
index 0000000..61ead96
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionLayoutFacetRepr.java
@@ -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.
+ */
+package org.apache.isis.core.metamodel.layoutmetadata;
+
+
+public class ActionLayoutFacetRepr {
+    public String position;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionRepr.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionRepr.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionRepr.java
index c88d2ca..77be27c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionRepr.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/ActionRepr.java
@@ -27,4 +27,5 @@ public class ActionRepr {
     public DescribedAsFacetRepr describedAs;
     public CssClassFacetRepr cssClass;
     public CssClassFaFacetRepr cssClassFa;
+    public ActionLayoutFacetRepr actionLayout;
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/json/LayoutMetadataReaderFromJson.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/json/LayoutMetadataReaderFromJson.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/json/LayoutMetadataReaderFromJson.java
index 927cd8c..71cff36 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/json/LayoutMetadataReaderFromJson.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/layoutmetadata/json/LayoutMetadataReaderFromJson.java
@@ -238,6 +238,10 @@ public class LayoutMetadataReaderFromJson implements LayoutMetadataReader {
         if(cssClassFa != null) {
             props.setProperty(prefix +"." + actionName + ".cssClassFa.value", cssClassFa.value);
         }
+        final ActionLayoutFacetRepr actionLayout = actionRepr.actionLayout;
+        if(actionLayout != null) {
+            props.setProperty(prefix +"." + actionName + ".actionLayout.position", actionLayout.position);
+        }
     }
 
     public LayoutMetadata asLayoutMetadata(Class<?> domainClass) throws ReaderException {

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index ae99a25..db477a8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -24,6 +24,8 @@ import com.google.common.base.Functions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.ActionSemantics;
 import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.When;
@@ -38,9 +40,13 @@ import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInvocationMethod;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetFilters;
+import org.apache.isis.core.metamodel.facets.SingleStringValueFacet;
 import org.apache.isis.core.metamodel.facets.actions.bulk.BulkFacet;
+import org.apache.isis.core.metamodel.facets.actions.layout.ActionLayoutFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
+import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
+import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
 import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
 import org.apache.isis.core.metamodel.facets.object.wizard.WizardFacet;
 import org.apache.isis.core.metamodel.interactions.AccessContext;
@@ -215,6 +221,54 @@ public interface ObjectAction extends ObjectMember {
             }
             return "(no name)";
         }
+
+        public static boolean returnsBlobOrClob(final ObjectAction objectAction) {
+            boolean blobOrClob = false;
+            final ObjectSpecification returnType = objectAction.getReturnType();
+            if(returnType != null) {
+                Class<?> cls = returnType.getCorrespondingClass();
+                if (Blob.class.isAssignableFrom(cls) || Clob.class.isAssignableFrom(cls)) {
+                    blobOrClob = true;
+                }
+            }
+            return blobOrClob;
+        }
+
+        public static boolean isExplorationOrPrototype(final ObjectAction action) {
+            return action.getType().isExploration() || action.getType().isPrototype();
+        }
+
+        public static String actionIdentifierFor(final ObjectAction action) {
+            @SuppressWarnings("unused")
+            final Identifier identifier = action.getIdentifier();
+
+            final String className = action.getOnType().getShortIdentifier();
+            final String actionId = action.getId();
+            return className + "-" + actionId;
+        }
+
+        public static String descriptionOf(ObjectAction action) {
+            return action.getDescription();
+        }
+
+        public static ActionLayout.Position actionLayoutPositionOf(ObjectAction action) {
+            final ActionLayoutFacet layoutFacet = action.getFacet(ActionLayoutFacet.class);
+            return layoutFacet != null? layoutFacet.position(): ActionLayout.Position.BELOW;
+        }
+
+        public static String cssClassFaFor(final ObjectAction action) {
+            return facetValueIfAnyFor(action, CssClassFaFacet.class);
+        }
+
+        public static String cssClassFor(final ObjectAction action) {
+            return facetValueIfAnyFor(action, CssClassFacet.class);
+        }
+
+        private static String facetValueIfAnyFor(ObjectAction action, Class<? extends SingleStringValueFacet> facetType) {
+            final SingleStringValueFacet singleStringValueFacet = action.getFacet(facetType);
+            return singleStringValueFacet != null ? singleStringValueFacet.value() : null;
+        }
+
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index c8bddbf..4030f20 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -27,6 +27,7 @@ import org.apache.isis.core.metamodel.facets.actions.defaults.method.ActionDefau
 import org.apache.isis.core.metamodel.facets.actions.exploration.annotation.ExplorationFacetAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.actions.homepage.annotation.HomePageFacetAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.actions.interaction.ActionInteractionFacetFactory;
+import org.apache.isis.core.metamodel.facets.actions.layout.ActionLayoutFacetFactory;
 import org.apache.isis.core.metamodel.facets.actions.notcontributed.annotation.NotContributedFacetAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.annotation.NotInServiceMenuFacetAnnotationFactory;
 import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.method.NotInServiceMenuFacetViaMethodFactory;
@@ -403,6 +404,8 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
         addFactory(LabelAtFacetOnPropertyFactory.class);
         addFactory(LabelAtFacetOnParameterAnnotationFactory.class);
 
+        addFactory(ActionLayoutFacetFactory.class);
+
         addFactory(NamedFacetOnTypeAnnotationFactory.class);
         addFactory(NamedFacetOnMemberFactory.class);
         addFactory(NamedFacetOnParameterAnnotationFactory.class);

http://git-wip-us.apache.org/repos/asf/isis/blob/6393ac92/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
new file mode 100644
index 0000000..3af9fe1
--- /dev/null
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutAnnotationFacetFactoryTest.java
@@ -0,0 +1,70 @@
+/*
+ *  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.core.metamodel.facets.actions.layout;
+
+import java.lang.reflect.Method;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryTest;
+import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessMethodContext;
+
+public class ActionLayoutAnnotationFacetFactoryTest extends AbstractFacetFactoryTest {
+
+    public void testActionLayoutAnnotationPickedUp() {
+        final ActionLayoutFacetFactory facetFactory = new ActionLayoutFacetFactory();
+
+        class Customer {
+            @SuppressWarnings("unused")
+            @ActionLayout(position = ActionLayout.Position.PANEL)
+            public String foo() {
+                return null;
+            }
+        }
+        final Method method = findMethod(Customer.class, "foo");
+
+        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, methodRemover, facetedMethod));
+
+        final Facet facet = facetedMethod.getFacet(ActionLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof ActionLayoutFacetAnnotation);
+        final ActionLayoutFacetAnnotation actionLayoutFacetAnnotation = (ActionLayoutFacetAnnotation) facet;
+        assertEquals(ActionLayout.Position.PANEL, actionLayoutFacetAnnotation.position());
+    }
+
+    public void testActionLayoutFallbackPickedUp() {
+        final ActionLayoutFacetFactory facetFactory = new ActionLayoutFacetFactory();
+
+        class Customer {
+            @SuppressWarnings("unused")
+            // no @ActionLayout
+            public String foo() {
+                return null;
+            }
+        }
+        final Method method = findMethod(Customer.class, "foo");
+
+        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, method, methodRemover, facetedMethod));
+
+        final Facet facet = facetedMethod.getFacet(ActionLayoutFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof ActionLayoutFacetFallback);
+    }
+
+}