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 2012/12/08 15:56:01 UTC

[10/53] [partial] ISIS-188: making structure of component viewers consistent

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewAccess.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewAccess.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewAccess.java
new file mode 100644
index 0000000..3363563
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewAccess.java
@@ -0,0 +1,39 @@
+/*
+ *  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.dnd.combined;
+
+import java.util.List;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+
+public class SplitViewAccess implements ViewAxis {
+
+    private final List<ObjectAssociation> fields;
+
+    public SplitViewAccess(final List<ObjectAssociation> fields) {
+        this.fields = fields;
+    }
+
+    public List<ObjectAssociation> getFields() {
+        return fields;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewBuilder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewBuilder.java
new file mode 100644
index 0000000..63a549d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewBuilder.java
@@ -0,0 +1,73 @@
+/*
+ *  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.dnd.combined;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.composite.AbstractViewBuilder;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+class SplitViewBuilder extends AbstractViewBuilder {
+
+    private final SplitViewSpecification splitViewSpecification;
+
+    public SplitViewBuilder(final SplitViewSpecification splitViewSpecification) {
+        this.splitViewSpecification = splitViewSpecification;
+    }
+
+    @Override
+    public void createAxes(final Axes axes, final Content content) {
+        super.createAxes(axes, content);
+        axes.add(new SplitViewAccess(splitViewSpecification.determineAvailableFields(content)));
+    }
+
+    @Override
+    public void build(final View view, final Axes axes) {
+        if (view.getSubviews().length == 0) {
+            final Content content = view.getContent();
+            final Content fieldContent = splitViewSpecification.determineSecondaryContent(content);
+
+            final View form1 = splitViewSpecification.createMainView(axes, content, fieldContent);
+            view.addView(form1);
+
+            final View labelledForm = splitViewSpecification.createSecondaryView(axes, fieldContent);
+            view.addView(labelledForm);
+        }
+    }
+
+    @Override
+    public void viewMenuOptions(final UserActionSet options, final View view) {
+        super.viewMenuOptions(options, view);
+
+        final SplitViewAccess axis = view.getViewAxes().getAxis(SplitViewAccess.class);
+        for (final ObjectAssociation field : axis.getFields()) {
+            options.add(new UserActionAbstract("Select " + field.getName()) {
+                @Override
+                public void execute(final Workspace workspace, final View view, final Location at) {
+                }
+            });
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewSpecification.java
new file mode 100644
index 0000000..8c21561
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/SplitViewSpecification.java
@@ -0,0 +1,90 @@
+/*
+ *  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.dnd.combined;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+
+public abstract class SplitViewSpecification extends CompositeViewSpecification {
+
+    // REVIEW: should provide this rendering context, rather than hardcoding.
+    // the net effect currently is that class members annotated with 
+    // @Hidden(where=Where.ANYWHERE) or @Disabled(where=Where.ANYWHERE) will indeed
+    // be hidden/disabled, but will be visible/enabled (perhaps incorrectly) 
+    // for any other value for Where
+    final Where where = Where.ANYWHERE;
+
+    public SplitViewSpecification() {
+        builder = new SplitViewBuilder(this);
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        if (requirement.isObject() && requirement.is(ViewRequirement.OPEN) && !requirement.isSubview()) {
+            final Content fieldContent = determineSecondaryContent(requirement.getContent());
+            return fieldContent != null && fieldContent.getAdapter() != null;
+        } else {
+            return false;
+        }
+    }
+
+    abstract View createMainView(Axes axes, Content mainContent, final Content secondaryContent);
+
+    abstract View createSecondaryView(Axes axes, final Content fieldContent);
+
+    abstract Content determineSecondaryContent(Content content);
+
+    Content field(final ObjectAssociation field, final Content content) {
+        final ObjectSpecification spec = content.getSpecification();
+        final ObjectAdapter target = content.getAdapter();
+        return Toolkit.getContentFactory().createFieldContent(field, target);
+    }
+
+    List<ObjectAssociation> determineAvailableFields(final Content content) {
+        final ObjectSpecification spec = content.getSpecification();
+        final ObjectAdapter target = content.getAdapter();
+        final AuthenticationSession session = IsisContext.getAuthenticationSession();
+        final List<ObjectAssociation> fields = spec.getAssociations(ObjectAssociationFilters.dynamicallyVisible(session, target, where));
+        final List<ObjectAssociation> selectableFields = new ArrayList<ObjectAssociation>();
+        for (final ObjectAssociation field : fields) {
+            if (validField(field)) {
+                selectableFields.add(field);
+            }
+        }
+        return selectableFields;
+    }
+
+    abstract boolean validField(ObjectAssociation field);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/TwoPartViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/TwoPartViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/TwoPartViewSpecification.java
new file mode 100644
index 0000000..335646d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/TwoPartViewSpecification.java
@@ -0,0 +1,92 @@
+/*
+ *  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.dnd.combined;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.form.FormSpecification;
+import org.apache.isis.viewer.dnd.form.InternalFormSpecification;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.axis.LabelAxis;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.LabelBorder;
+import org.apache.isis.viewer.dnd.view.composite.ColumnLayout;
+
+public class TwoPartViewSpecification extends SplitViewSpecification {
+
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new ColumnLayout();
+    }
+
+    @Override
+    View createMainView(final Axes axes, final Content mainContent, final Content secondaryContent) {
+        final View form1 = new FormSpecification() {
+            @Override
+            protected boolean include(final Content content, final int sequence) {
+                return !secondaryContent.getId().equals(content.getId());
+            };
+        }.createView(mainContent, axes, -1);
+        return form1;
+    }
+
+    @Override
+    View createSecondaryView(final Axes axes, final Content fieldContent) {
+        final View form = new InternalFormSpecification().createView(fieldContent, axes, -1);
+        final View labelledForm = LabelBorder.createFieldLabelBorder(new LabelAxis(), form);
+        return labelledForm;
+    }
+
+    @Override
+    @Deprecated
+    Content determineSecondaryContent(final Content content) {
+        final ObjectSpecification spec = content.getSpecification();
+        final ObjectAdapter target = content.getAdapter();
+        final AuthenticationSession session = IsisContext.getAuthenticationSession();
+        final List<ObjectAssociation> fields = spec.getAssociations(ObjectAssociationFilters.dynamicallyVisible(session, target, where));
+        for (final ObjectAssociation field : fields) {
+            if (validField(field)) {
+                return Toolkit.getContentFactory().createFieldContent(field, target);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    boolean validField(final ObjectAssociation field) {
+        return field.isOneToOneAssociation() && !field.getSpecification().isParseable();
+    }
+
+    @Override
+    public String getName() {
+        return "Two part object (experimental)";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableCompositeViewBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableCompositeViewBorder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableCompositeViewBorder.java
new file mode 100644
index 0000000..32ffc80
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableCompositeViewBorder.java
@@ -0,0 +1,138 @@
+/*
+ *  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.dnd.configurable;
+
+import java.util.Enumeration;
+
+import org.apache.isis.core.commons.factory.InstanceUtil;
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.viewer.dnd.configurable.GridListSpecification.ElementFactory;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.util.Properties;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.base.UserViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class ConfigurableCompositeViewBorder extends AbstractBorder {
+
+    public static class Factory implements CompositeViewDecorator {
+        private final ElementFactory elementSpecification;
+
+        public Factory(final ElementFactory elementSpecification) {
+            this.elementSpecification = elementSpecification;
+        }
+
+        @Override
+        public View decorate(final View view, final Axes axes) {
+            final ConfigurationAxis axis = new ConfigurationAxis();
+            // TODO load previously saved settings for the type of elements
+            // axis.loadSettings(view.getContent());
+            axes.add(axis);
+            return new ConfigurableCompositeViewBorder(view, elementSpecification);
+        }
+    }
+
+    private ViewSpecification elementSpecification;
+
+    protected ConfigurableCompositeViewBorder(final View view, final ElementFactory elementFactory) {
+        super(view);
+    }
+
+    @Override
+    public void loadOptions(final Options viewOptions) {
+        super.loadOptions(viewOptions);
+        final String elementsClass = viewOptions.getString("elements");
+        if (elementsClass != null) {
+            ViewSpecification specification;
+            if (elementsClass.startsWith("user:")) {
+                final String name = elementsClass.substring("user:".length());
+                final String wrappedSpecificationClass = Properties.getUserViewSpecificationOptions(name).getString("wrapped-specification");
+                final ViewSpecification wrappedSpectification = (ViewSpecification) InstanceUtil.createInstance(wrappedSpecificationClass);
+                specification = new UserViewSpecification(wrappedSpectification, name);
+            } else {
+                specification = (ViewSpecification) InstanceUtil.createInstance(elementsClass);
+            }
+            if (specification != null) {
+                getViewAxes().getAxis(ConfigurationAxis.class).setElementSpecification(specification);
+            }
+        }
+    }
+
+    @Override
+    public void saveOptions(final Options viewOptions) {
+        super.saveOptions(viewOptions);
+        if (elementSpecification != null) {
+            final boolean isUserSpecification = elementSpecification instanceof UserViewSpecification;
+            String name;
+            if (isUserSpecification) {
+                name = "user:" + elementSpecification.getName();
+            } else {
+                name = elementSpecification.getClass().getName();
+            }
+            viewOptions.addOption("elements", name);
+        }
+    }
+
+    @Override
+    public void viewMenuOptions(final UserActionSet menuOptions) {
+        super.viewMenuOptions(menuOptions);
+        final UserActionSet subOptions = menuOptions.addNewActionSet("Elements as");
+        final View firstSubview = getSubviews()[0];
+        final int status = ViewRequirement.OPEN | ViewRequirement.CLOSED | ViewRequirement.SUBVIEW | ViewRequirement.FIXED;
+        final ViewRequirement viewRequirement = new ViewRequirement(firstSubview.getContent(), status);
+        final Enumeration<ViewSpecification> possibleViews = Toolkit.getViewFactory().availableViews(viewRequirement);
+        while (possibleViews.hasMoreElements()) {
+            addElementAsOption(subOptions, possibleViews.nextElement());
+        }
+    }
+
+    private void addElementAsOption(final UserActionSet subOptions, final ViewSpecification specification) {
+        if (specification != elementSpecification) {
+            subOptions.add(new UserActionAbstract(specification.getName()) {
+                @Override
+                public void execute(final Workspace workspace, final View view, final Location at) {
+                    replaceElementViews(specification, view);
+                }
+            });
+        }
+    }
+
+    private void replaceElementViews(final ViewSpecification specification, final View view) {
+        elementSpecification = specification;
+        removeAllSubviews(view);
+        getViewAxes().getAxis(ConfigurationAxis.class).setElementSpecification(specification);
+        invalidateContent();
+    }
+
+    private void removeAllSubviews(final View view) {
+        final View[] subviews = view.getSubviews();
+        for (final View subview : subviews) {
+            view.removeView(subview);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableFieldBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableFieldBorder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableFieldBorder.java
new file mode 100644
index 0000000..96cd86b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableFieldBorder.java
@@ -0,0 +1,154 @@
+/*
+ *  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.dnd.configurable;
+
+import java.util.Enumeration;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.SubviewDecorator;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserAction;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.ViewState;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.axis.LabelAxis;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.base.BlankView;
+import org.apache.isis.viewer.dnd.view.border.LabelBorder;
+import org.apache.isis.viewer.dnd.view.option.ReplaceViewOption;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class ConfigurableFieldBorder extends AbstractBorder {
+    public static final class Factory implements SubviewDecorator {
+        @Override
+        public ViewAxis createAxis(final Content content) {
+            return null;
+        }
+
+        @Override
+        public View decorate(final Axes axes, final View view) {
+            return new ConfigurableFieldBorder(view);
+        }
+    }
+
+    private static final int BORDER = 10;
+
+    protected ConfigurableFieldBorder(final View view) {
+        super(view);
+        right = BORDER;
+    }
+
+    @Override
+    public void viewMenuOptions(final UserActionSet menuOptions) {
+        super.viewMenuOptions(menuOptions);
+
+        menuOptions.add(new UserActionAbstract("Hide") {
+            @Override
+            public void execute(final Workspace workspace, final View view, final Location at) {
+                final View parent = wrappedView.getParent();
+                wrappedView = new BlankView(getContent());
+                wrappedView.setParent(parent);
+                wrappedView.setView(ConfigurableFieldBorder.this);
+                invalidateLayout();
+            }
+
+        });
+
+        menuOptions.add(new UserActionAbstract("Show label") {
+            @Override
+            public void execute(final Workspace workspace, final View view, final Location at) {
+                if (wrappedView instanceof LabelBorder) {
+                    wrappedView = ((LabelBorder) wrappedView).getWrapped();
+                } else {
+                    wrappedView = LabelBorder.createFieldLabelBorder(view.getParent().getViewAxes().getAxis(LabelAxis.class), wrappedView);
+                }
+                wrappedView.setView(ConfigurableFieldBorder.this);
+                getView().invalidateLayout();
+            }
+        });
+
+        replaceOptions(Toolkit.getViewFactory().availableViews(new ViewRequirement(getContent(), ViewRequirement.OPEN | ViewRequirement.CLOSED | ViewRequirement.SUBVIEW)), menuOptions); // openSubviews(content,
+                                                                                                                                                                                          // this),
+                                                                                                                                                                                          // options);
+
+    }
+
+    // TODO copied from AbstractView
+    protected void replaceOptions(final Enumeration possibleViews, final UserActionSet options) {
+        if (possibleViews.hasMoreElements()) {
+            final UserActionSet suboptions = options.addNewActionSet("Replace with");
+            while (possibleViews.hasMoreElements()) {
+                final ViewSpecification specification = (ViewSpecification) possibleViews.nextElement();
+
+                if (specification != getSpecification()) {
+                    final UserAction viewAs = new ReplaceViewOption(specification) {
+                        @Override
+                        protected void replace(final View view, final View withReplacement) {
+                            final View parent = wrappedView.getParent();
+                            wrappedView = LabelBorder.createFieldLabelBorder(view.getParent().getViewAxes().getAxis(LabelAxis.class), withReplacement);
+                            wrappedView.setParent(parent);
+                            wrappedView.setView(ConfigurableFieldBorder.this);
+                            invalidateLayout();
+                        }
+                    };
+                    suboptions.add(viewAs);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        super.draw(canvas);
+
+        final ViewState state = getState();
+        if (state.isViewIdentified()) {
+            final Size s = getSize();
+            final int xExtent = s.getWidth();
+            if (state.isViewIdentified()) {
+                canvas.drawSolidRectangle(xExtent - BORDER + 1, top, BORDER - 2, s.getHeight() - 2 * top, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3));
+            }
+        }
+    }
+
+    @Override
+    public void entered() {
+        getState().setViewIdentified();
+        wrappedView.entered();
+        markDamaged();
+    }
+
+    @Override
+    public void exited() {
+        getState().clearViewIdentified();
+        wrappedView.exited();
+        markDamaged();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableObjectViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableObjectViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableObjectViewSpecification.java
new file mode 100644
index 0000000..18e5f51
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurableObjectViewSpecification.java
@@ -0,0 +1,61 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.FieldLabelsDecorator;
+import org.apache.isis.viewer.dnd.view.composite.GridLayout;
+import org.apache.isis.viewer.dnd.view.composite.GridLayoutControlBorder;
+import org.apache.isis.viewer.dnd.view.composite.ObjectFieldBuilder;
+import org.apache.isis.viewer.dnd.view.composite.StandardFields;
+
+public class ConfigurableObjectViewSpecification extends CompositeViewSpecification {
+
+    public ConfigurableObjectViewSpecification() {
+        builder = new ObjectFieldBuilder(new StandardFields());
+        addSubviewDecorator(new FieldLabelsDecorator());
+        addSubviewDecorator(new ConfigurableFieldBorder.Factory());
+        addViewDecorator(new GridLayoutControlBorder.Factory());
+        addViewDecorator(new IconBorder.Factory());
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isObject() && requirement.isOpen() && requirement.isExpandable() && requirement.isDesign();
+    }
+
+    @Override
+    public String getName() {
+        return "Configurable (experimental)";
+    }
+
+    /*
+     * protected View decorateView(View view) { return new IconBorder(view); }
+     */
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new GridLayout();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurationAxis.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurationAxis.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurationAxis.java
new file mode 100644
index 0000000..53744d0
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ConfigurationAxis.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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+
+public class ConfigurationAxis implements ViewAxis {
+    private ViewSpecification elementSpecification;
+
+    public void setElementSpecification(final ViewSpecification elementSpecification) {
+        this.elementSpecification = elementSpecification;
+    }
+
+    public ViewSpecification getElementSpecification() {
+        return elementSpecification;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/FieldLayoutRequirement.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/FieldLayoutRequirement.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/FieldLayoutRequirement.java
new file mode 100644
index 0000000..81e4969
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/FieldLayoutRequirement.java
@@ -0,0 +1,38 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+
+public class FieldLayoutRequirement {
+    private View view;
+
+    private boolean visible;
+    private int columnSpan;
+    private int rowSpan;
+
+    private ViewSpecification spec;
+    private boolean showLabel;
+    private boolean mergeWithNext;
+
+    private boolean allowGrowing;
+    private boolean allowScrolling;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/GridListSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/GridListSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/GridListSpecification.java
new file mode 100644
index 0000000..768e81b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/GridListSpecification.java
@@ -0,0 +1,82 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.GlobalViewFactory;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.composite.CollectionElementBuilder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.GridLayout;
+import org.apache.isis.viewer.dnd.view.composite.GridLayoutControlBorder;
+
+public class GridListSpecification extends CompositeViewSpecification implements ViewFactory {
+
+    protected static class ElementFactory implements ViewFactory {
+        @Override
+        public View createView(final Content content, final Axes axes, final int sequence) {
+            final GlobalViewFactory factory = Toolkit.getViewFactory();
+
+            final ViewSpecification elementSpecification = axes.getAxis(ConfigurationAxis.class).getElementSpecification();
+            if (elementSpecification == null) {
+                final int defaultRequirement = ViewRequirement.CLOSED | ViewRequirement.SUBVIEW;
+                final ViewRequirement viewRequirement = new ViewRequirement(content, defaultRequirement);
+                return factory.createView(viewRequirement);
+            } else {
+                return elementSpecification.createView(content, axes, sequence);
+            }
+        }
+    }
+
+    public GridListSpecification() {
+        final ElementFactory factory = new ElementFactory();
+        builder = new CollectionElementBuilder(factory);
+        // TODO allow to be switched on so that user can change the view for a
+        // single element. This type of
+        // view used for an element would not be stored.
+        if (false) {
+            addSubviewDecorator(new ConfigurableFieldBorder.Factory());
+        }
+
+        addViewDecorator(new ConfigurableCompositeViewBorder.Factory(factory));
+        addViewDecorator(new GridLayoutControlBorder.Factory());
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isCollection() && requirement.isOpen() && !requirement.isSubview() && requirement.isDesign();
+    }
+
+    @Override
+    public String getName() {
+        return "Grid List";
+    }
+
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new GridLayout();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectField.java
new file mode 100644
index 0000000..468dc1c
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectField.java
@@ -0,0 +1,51 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.core.runtime.userprofile.OptionsClient;
+
+public class NewObjectField implements OptionsClient {
+
+    private final ObjectAssociation field;
+
+    public NewObjectField(final ObjectAssociation field) {
+        this.field = field;
+    }
+
+    public boolean includeLabel() {
+        return true;
+    }
+
+    public ObjectAssociation getField() {
+        return field;
+    }
+
+    @Override
+    public void loadOptions(final Options viewOptions) {
+    }
+
+    @Override
+    public void saveOptions(final Options viewOptions) {
+        viewOptions.addOption("field", field.getId());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectView.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectView.java
new file mode 100644
index 0000000..20a3975
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewObjectView.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.configurable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.axis.LabelAxis;
+import org.apache.isis.viewer.dnd.view.border.LabelBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeView;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+
+public class NewObjectView extends CompositeView {
+    StackLayout layout = new StackLayout();
+    LabelAxis labelAxis = new LabelAxis();
+    List<NewObjectField> fields = new ArrayList<NewObjectField>();
+
+    public NewObjectView(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    void addField(final NewObjectField field) {
+        fields.add(field);
+        addFieldView(field);
+        invalidateContent();
+    }
+
+    @Override
+    protected void buildView() {
+        if (getSubviews().length == 0) {
+            final ObjectAdapter object = getContent().getAdapter();
+            final List<ObjectAssociation> associations = getContent().getSpecification().getAssociations();
+
+            final ObjectAssociation field = associations.get(0);
+
+            addFieldView(object, field);
+            addFieldView(object, associations.get(2));
+        }
+    }
+
+    private void addFieldView(final ObjectAdapter object, final ObjectAssociation field) {
+        final FieldContent fieldContent = (FieldContent) Toolkit.getContentFactory().createFieldContent(field, object);
+        final ViewRequirement requirement = new ViewRequirement(fieldContent, ViewRequirement.CLOSED | ViewRequirement.SUBVIEW);
+        View fieldView = Toolkit.getViewFactory().createView(requirement);
+
+        fieldView = LabelBorder.createFieldLabelBorder(labelAxis, fieldView);
+
+        addView(fieldView);
+    }
+
+    private void addFieldView(final NewObjectField field) {
+        final ObjectAdapter object = getContent().getAdapter();
+        final FieldContent fieldContent = (FieldContent) Toolkit.getContentFactory().createFieldContent(field.getField(), object);
+        final ViewRequirement requirement = new ViewRequirement(fieldContent, ViewRequirement.CLOSED | ViewRequirement.SUBVIEW);
+        View fieldView = Toolkit.getViewFactory().createView(requirement);
+        if (field.includeLabel()) {
+            fieldView = LabelBorder.createFieldLabelBorder(labelAxis, fieldView);
+        }
+        addView(fieldView);
+    }
+
+    @Override
+    protected void doLayout(final Size maximumSize) {
+        layout.layout(this, maximumSize);
+    }
+
+    @Override
+    protected Size requiredSize(final Size availableSpace) {
+        return layout.getRequiredSize(this);
+    }
+
+    @Override
+    public void loadOptions(final Options viewOptions) {
+        final Options options = viewOptions.getOptions("fields");
+        // options.options()
+
+    }
+
+    @Override
+    public void saveOptions(final Options viewOptions) {
+        for (final NewObjectField field : fields) {
+            field.saveOptions(viewOptions.getOptions("fields"));
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewViewSpecification.java
new file mode 100644
index 0000000..0329c80
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/NewViewSpecification.java
@@ -0,0 +1,82 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+
+public class NewViewSpecification implements ViewSpecification {
+
+    protected Layout createLayout(final Content content, final Axes axes) {
+        return new StackLayout();
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isObject() && requirement.isOpen();
+    }
+
+    @Override
+    public String getName() {
+        return "Object View";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return false;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return false;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return false;
+    }
+
+    @Override
+    public boolean isSubView() {
+        return false;
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final NewObjectView view = new NewObjectView(content, this);
+        View view2 = new IconBorder(view, Toolkit.getText(ColorsAndFonts.TEXT_TITLE));
+        view2 = new ViewDesignBorder(view2, view);
+        return view2;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/Panel.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/Panel.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/Panel.java
new file mode 100644
index 0000000..d18ce22
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/Panel.java
@@ -0,0 +1,203 @@
+/*
+ *  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.dnd.configurable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.View;
+
+public class Panel {
+
+    private static enum Orientation {
+        Undefined, Horizontal, Vertical
+    };
+
+    private static interface Content {
+        public Size getRequiredSize(Size availableSpace);
+
+        public void setLocation(Location location);
+
+        public void setSize(Size size);
+
+        public void layout(Size maximumSize);
+
+        public void debug(DebugBuilder debug);
+    }
+
+    private static class ViewContent implements Content {
+        private final View view;
+
+        public ViewContent(final View view) {
+            this.view = view;
+        }
+
+        @Override
+        public Size getRequiredSize(final Size availableSpace) {
+            return view.getRequiredSize(availableSpace);
+        }
+
+        @Override
+        public void layout(final Size maximumSize) {
+            view.layout();
+        }
+
+        @Override
+        public void setLocation(final Location location) {
+            view.setLocation(location);
+        }
+
+        @Override
+        public void setSize(final Size size) {
+            view.setSize(size);
+        }
+
+        @Override
+        public void debug(final DebugBuilder debug) {
+            debug.appendln(view.toString());
+        }
+    }
+
+    private static class PanelContent implements Content {
+        private final Panel panel;
+        private Location location;
+
+        public PanelContent(final Panel panel) {
+            this.panel = panel;
+        }
+
+        @Override
+        public Size getRequiredSize(final Size availableSpace) {
+            return panel.getRequiredSize(availableSpace);
+        }
+
+        @Override
+        public void layout(final Size maximumSize) {
+            panel.layout(location, maximumSize);
+        }
+
+        @Override
+        public void setLocation(final Location location) {
+            this.location = location;
+        }
+
+        @Override
+        public void setSize(final Size size) {
+        }
+
+        @Override
+        public void debug(final DebugBuilder debug) {
+            panel.debug(debug);
+        }
+    }
+
+    private List<Content> contents = new ArrayList<Content>();
+    private Orientation orientation;
+
+    public void debug(final DebugBuilder debug) {
+        debug.appendln("orientation", orientation);
+        debug.appendln("size", getRequiredSize(Size.createMax()));
+        debug.indent();
+        for (final Content content : contents) {
+            content.debug(debug);
+        }
+        debug.unindent();
+    }
+
+    public void addView(final View view, final PanelView.Position position) {
+        if (contents.isEmpty() || position == null) {
+            addToContents(view, false);
+        } else if (position == PanelView.Position.East || position == PanelView.Position.West) {
+            if (orientation == Orientation.Undefined) {
+                orientation = Orientation.Horizontal;
+            }
+            if (orientation == Orientation.Horizontal) {
+                addToContents(view, position == PanelView.Position.West);
+            } else {
+                replaceViewsWithPanel(view, position == PanelView.Position.West);
+            }
+        } else if (position == PanelView.Position.South || position == PanelView.Position.North) {
+            if (orientation == Orientation.Undefined) {
+                orientation = Orientation.Vertical;
+            }
+            if (orientation == Orientation.Horizontal) {
+                replaceViewsWithPanel(view, position == PanelView.Position.North);
+            } else {
+                addToContents(view, position == PanelView.Position.North);
+            }
+        }
+    }
+
+    private void addToContents(final View view, final boolean atBeginning) {
+        if (atBeginning) {
+            contents.add(0, new ViewContent(view));
+        } else {
+            contents.add(new ViewContent(view));
+        }
+    }
+
+    private void replaceViewsWithPanel(final View view, final boolean atBeginning) {
+        final Panel panel = new Panel();
+        panel.contents = contents;
+        contents = new ArrayList<Content>();
+        contents.add(new PanelContent(panel));
+        addToContents(view, atBeginning);
+        panel.orientation = orientation;
+        orientation = orientation == Orientation.Horizontal ? Orientation.Vertical : Orientation.Horizontal;
+    }
+
+    public void layout(final Size maximumSize) {
+        final Location location = new Location();
+        layout(location, maximumSize);
+    }
+
+    private void layout(final Location location, final Size maximumSize) {
+        for (final Content content : contents) {
+            content.setLocation(new Location(location));
+            final Size requiredSize = content.getRequiredSize(maximumSize);
+            content.setSize(requiredSize);
+            content.layout(maximumSize);
+            if (orientation == Orientation.Horizontal) {
+                location.add(requiredSize.getWidth(), 0);
+            } else {
+                location.add(0, requiredSize.getHeight());
+            }
+        }
+    }
+
+    public Size getRequiredSize(final Size availableSpace) {
+        final Size size = new Size();
+        for (final Content content : contents) {
+            final Size requiredSize = content.getRequiredSize(availableSpace);
+            if (orientation == Orientation.Horizontal) {
+                size.extendWidth(requiredSize.getWidth());
+                size.ensureHeight(requiredSize.getHeight());
+            } else {
+                size.extendHeight(requiredSize.getHeight());
+                size.ensureWidth(requiredSize.getWidth());
+            }
+        }
+        return size;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelView.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelView.java
new file mode 100644
index 0000000..60d5de8
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelView.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.configurable;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewDrag;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.CompositeView;
+
+public class PanelView extends CompositeView {
+    public static enum Position {
+        North, South, East, West
+    };
+
+    private final Panel panel = new Panel();
+    private ViewSpecification initialViewSpecification;;
+
+    @Override
+    public void debug(final DebugBuilder debug) {
+        super.debug(debug);
+        debug.appendln("Panel");
+        debug.indent();
+        panel.debug(debug);
+        debug.unindent();
+    }
+
+    public void setInitialViewSpecification(final ViewSpecification initialViewSpecification) {
+        this.initialViewSpecification = initialViewSpecification;
+    }
+
+    public PanelView(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    @Override
+    protected void buildView() {
+        // addView(getContent(), initialViewSpecification, null);
+        final View newView = initialViewSpecification.createView(getContent(), new Axes(), 0);
+        panel.addView(newView, null);
+        addView(newView);
+    }
+
+    @Override
+    protected void doLayout(final Size maximumSize) {
+        panel.layout(maximumSize);
+    }
+
+    @Override
+    public Size requiredSize(final Size availableSpace) {
+        return panel.getRequiredSize(availableSpace);
+    }
+
+    @Override
+    public void drop(final ViewDrag drag) {
+        if (drag.getSourceView() == getView() || !contains(drag.getSourceView())) {
+            super.drop(drag);
+        } else {
+            final Location dropAt = drag.getLocation();
+            dropAt.subtract(getLocation());
+            final int x = dropAt.getX();
+            final int y = dropAt.getY();
+            final int borderWdth = 45;
+            final int left = getSize().getWidth() - borderWdth;
+            final int bottom = getSize().getHeight() - borderWdth;
+            if (y < borderWdth) {
+                addView(drag.getSourceView().getContent(), Position.North);
+            } else if (y > bottom) {
+                addView(drag.getSourceView().getContent(), Position.South);
+            } else if (x < borderWdth) {
+                addView(drag.getSourceView().getContent(), Position.West);
+            } else if (x > left) {
+                addView(drag.getSourceView().getContent(), Position.East);
+            }
+        }
+    }
+
+    public void addView(final Content content, final Position position) {
+        final ViewRequirement requirement = new ViewRequirement(content, ViewRequirement.OPEN | ViewRequirement.SUBVIEW);
+        final ViewSpecification viewSpecification = Toolkit.getViewFactory().availableViews(requirement).nextElement();
+        addView(content, viewSpecification, position);
+    }
+
+    public void addView(final Content content, final ViewSpecification specification, final Position position) {
+        final View newView = specification.createView(content, new Axes(), 0);
+        // newView = new LineBorder(newView);
+        panel.addView(newView, position);
+        addView(newView);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelViewSpecification.java
new file mode 100644
index 0000000..8ef3d32
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/PanelViewSpecification.java
@@ -0,0 +1,76 @@
+/*
+ *  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.dnd.configurable;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.form.InternalFormSpecification;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+
+public class PanelViewSpecification implements ViewSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isObject() && requirement.isOpen() && requirement.isExpandable() && requirement.isDesign();
+    }
+
+    @Override
+    public String getName() {
+        return "Panel (experimental)";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return false;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return false;
+    }
+
+    @Override
+    public boolean isSubView() {
+        return false;
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final PanelView wrappedView = new PanelView(content, this);
+        wrappedView.setInitialViewSpecification(new InternalFormSpecification());
+        final View newView = new IconBorder(wrappedView, Toolkit.getText(ColorsAndFonts.TEXT_TITLE));
+        return newView;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ViewDesignBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ViewDesignBorder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ViewDesignBorder.java
new file mode 100644
index 0000000..52bc891
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/configurable/ViewDesignBorder.java
@@ -0,0 +1,64 @@
+/*
+ *  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.dnd.configurable;
+
+import java.util.List;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class ViewDesignBorder extends AbstractBorder {
+    private final NewObjectView viewUnderControl;
+
+    protected ViewDesignBorder(final View view, final NewObjectView view2) {
+        super(view);
+        viewUnderControl = view2;
+    }
+
+    private NewObjectView getNewObjectView() {
+        return viewUnderControl;
+    }
+
+    @Override
+    public void viewMenuOptions(final UserActionSet menuOptions) {
+        super.viewMenuOptions(menuOptions);
+
+        // ObjectAdapter object = getContent().getAdapter();
+        final List<ObjectAssociation> associations = getContent().getSpecification().getAssociations();
+
+        for (final ObjectAssociation objectAssociation : associations) {
+            final ObjectAssociation f = objectAssociation;
+            final UserActionAbstract action = new UserActionAbstract("Add field " + objectAssociation.getName()) {
+
+                @Override
+                public void execute(final Workspace workspace, final View view, final Location at) {
+                    final NewObjectField field = new NewObjectField(f);
+                    getNewObjectView().addField(field);
+                }
+            };
+            menuOptions.add(action);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogFocusManager.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogFocusManager.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogFocusManager.java
new file mode 100644
index 0000000..19f425a
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogFocusManager.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.viewer.dnd.dialog;
+
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.base.AbstractFocusManager;
+import org.apache.isis.viewer.dnd.view.border.ButtonBorder;
+
+public class ActionDialogFocusManager extends AbstractFocusManager {
+    private final ButtonBorder buttonBorder;
+
+    public ActionDialogFocusManager(final ButtonBorder buttonBorder) {
+        super(buttonBorder.getView());
+        this.buttonBorder = buttonBorder;
+
+    }
+
+    @Override
+    protected View[] getChildViews() {
+        final View[] subviews = container.getSubviews();
+        final View[] buttons = buttonBorder.getButtons();
+
+        final View[] views = new View[subviews.length + buttons.length];
+        System.arraycopy(subviews, 0, views, 0, subviews.length);
+        System.arraycopy(buttons, 0, views, subviews.length, buttons.length);
+        return views;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogSpecification.java
new file mode 100644
index 0000000..53febd7
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionDialogSpecification.java
@@ -0,0 +1,204 @@
+/*
+ *  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.dnd.dialog;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.BackgroundTask;
+import org.apache.isis.viewer.dnd.view.ButtonAction;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.GlobalViewFactory;
+import org.apache.isis.viewer.dnd.view.Placement;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.action.ActionContent;
+import org.apache.isis.viewer.dnd.view.action.BackgroundWork;
+import org.apache.isis.viewer.dnd.view.action.ObjectParameter;
+import org.apache.isis.viewer.dnd.view.action.ParameterContent;
+import org.apache.isis.viewer.dnd.view.action.TextParseableParameter;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.ButtonBorder;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+import org.apache.isis.viewer.dnd.view.control.AbstractButtonAction;
+import org.apache.isis.viewer.dnd.view.control.CancelAction;
+
+public class ActionDialogSpecification extends CompositeViewSpecification {
+    private static final Logger LOG = Logger.getLogger(ActionDialogSpecification.class);
+
+    private static class DialogFormSubviews implements ViewFactory {
+
+        @Override
+        public View createView(final Content content, final Axes axes, final int fieldNumber) {
+            if (content instanceof TextParseableParameter) {
+                final GlobalViewFactory factory = Toolkit.getViewFactory();
+                return factory.createView(new ViewRequirement(content, ViewRequirement.CLOSED | ViewRequirement.SUBVIEW));
+            } else if (content instanceof ObjectParameter) {
+                final GlobalViewFactory factory = Toolkit.getViewFactory();
+                return factory.createView(new ViewRequirement(content, ViewRequirement.CLOSED | ViewRequirement.SUBVIEW));
+            }
+
+            return null;
+        }
+    }
+
+    private static class ExecuteAction extends AbstractButtonAction {
+        public ExecuteAction() {
+            this("Apply");
+        }
+
+        public ExecuteAction(final String name) {
+            super(name, true);
+        }
+
+        @Override
+        public Consent disabled(final View view) {
+            final View[] subviews = view.getSubviews();
+            final StringBuffer missingFields = new StringBuffer();
+            final StringBuffer invalidFields = new StringBuffer();
+            for (final View field : subviews) {
+                final ParameterContent content = ((ParameterContent) field.getContent());
+                final boolean isEmpty = content.getAdapter() == null;
+                if (content.isRequired() && isEmpty) {
+                    final String parameterName = content.getParameterName();
+                    if (missingFields.length() > 0) {
+                        missingFields.append(", ");
+                    }
+                    missingFields.append(parameterName);
+
+                } else if (field.getState().isInvalid()) {
+                    final String parameterName = content.getParameterName();
+                    if (invalidFields.length() > 0) {
+                        invalidFields.append(", ");
+                    }
+                    invalidFields.append(parameterName);
+                }
+            }
+            if (missingFields.length() > 0) {
+                // TODO: move logic into Facet
+                return new Veto(String.format("Fields needed: %s", missingFields));
+            }
+            if (invalidFields.length() > 0) {
+                // TODO: move logic into Facet
+                return new Veto(String.format("Invalid fields: %s", invalidFields));
+            }
+
+            final ActionContent actionContent = ((ActionContent) view.getContent());
+            return actionContent.disabled();
+        }
+
+        @Override
+        public void execute(final Workspace workspace, final View view, final Location at) {
+            final BackgroundTask task = new BackgroundTask() {
+                @Override
+                public void execute() {
+                    final ActionContent actionContent = ((ActionContent) view.getContent());
+                    final ObjectAdapter result = actionContent.execute();
+                    LOG.debug("action invoked with result " + result);
+                    if (result != null) {
+                        view.objectActionResult(result, new Placement(view.getAbsoluteLocation()));
+                    }
+                    view.getViewManager().disposeUnneededViews();
+                    view.getFeedbackManager().showMessagesAndWarnings();
+                }
+
+                @Override
+                public String getName() {
+                    return ((ActionContent) view.getContent()).getActionName();
+                }
+
+                @Override
+                public String getDescription() {
+                    return "Running action " + getName() + " on  " + view.getContent().getAdapter();
+                }
+            };
+            LOG.debug("  ... created task " + task);
+
+            BackgroundWork.runTaskInBackground(view, task);
+        }
+
+        protected void move(final Location at) {
+            at.move(30, 60);
+        }
+    }
+
+    private static class ExecuteAndCloseAction extends ExecuteAction {
+        public ExecuteAndCloseAction() {
+            super("OK");
+        }
+
+        @Override
+        public void execute(final Workspace workspace, final View view, final Location at) {
+            LOG.debug("executing action " + this);
+            view.dispose();
+            LOG.debug("  ... disposed view, now executing");
+            super.execute(workspace, view, at);
+            view.getViewManager().setKeyboardFocus(workspace);
+            // view.getViewManager().clearKeyboardFocus();
+        }
+
+        @Override
+        protected void move(final Location at) {
+        }
+    }
+
+    public ActionDialogSpecification() {
+        builder = new ActionFieldBuilder(new DialogFormSubviews());
+        addSubviewDecorator(new ParametersLabelDecorator());
+        addViewDecorator(new CompositeViewDecorator() {
+            @Override
+            public View decorate(final View view, final Axes axes) {
+                // TODO reintroduce the 'Apply' notion, but under control from
+                // the method declaration
+                final ButtonAction[] actions = new ButtonAction[] { new ExecuteAndCloseAction(), new CancelAction() };
+                final ButtonBorder buttonBorder = new ButtonBorder(actions, new IconBorder(view, Toolkit.getText(ColorsAndFonts.TEXT_TITLE_SMALL)));
+                buttonBorder.setFocusManager(new ActionDialogFocusManager(buttonBorder));
+                return buttonBorder;
+            }
+        });
+    }
+
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new StackLayout();
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.getContent() instanceof ActionContent;
+    }
+
+    @Override
+    public String getName() {
+        return "Action Dialog";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionFieldBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionFieldBuilder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionFieldBuilder.java
new file mode 100644
index 0000000..9107dee
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/dialog/ActionFieldBuilder.java
@@ -0,0 +1,110 @@
+/*
+ *  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.dnd.dialog;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.action.ActionContent;
+import org.apache.isis.viewer.dnd.view.action.ObjectParameter;
+import org.apache.isis.viewer.dnd.view.action.ObjectParameterImpl;
+import org.apache.isis.viewer.dnd.view.action.ParameterContent;
+import org.apache.isis.viewer.dnd.view.action.TextParseableParameter;
+import org.apache.isis.viewer.dnd.view.composite.AbstractViewBuilder;
+
+public class ActionFieldBuilder extends AbstractViewBuilder {
+    private static final Logger LOG = Logger.getLogger(ActionFieldBuilder.class);
+    private final ViewFactory subviewDesign;
+
+    public ActionFieldBuilder(final ViewFactory subviewDesign) {
+        this.subviewDesign = subviewDesign;
+    }
+
+    @Override
+    public void build(final View view, final Axes axes) {
+        Assert.assertEquals(view.getView(), view);
+
+        final ActionContent actionContent = ((ActionContent) view.getContent());
+        if (view.getSubviews().length == 0) {
+            initialBuild(view, actionContent);
+        } else {
+            updateBuild(view, actionContent);
+        }
+
+    }
+
+    private View createFieldView(final View view, final ParameterContent parameter, final int sequence) {
+        final View fieldView = subviewDesign.createView(parameter, null, sequence);
+        if (fieldView == null) {
+            throw new IsisException("All parameters must be shown");
+        }
+        return fieldView;
+    }
+
+    private void initialBuild(final View view, final ActionContent actionContent) {
+        LOG.debug("build new view " + view + " for " + actionContent);
+        final int noParameters = actionContent.getNoParameters();
+        View focusOn = null;
+        for (int f = 0; f < noParameters; f++) {
+            final ParameterContent parameter = actionContent.getParameterContent(f);
+            final View fieldView = createFieldView(view, parameter, f);
+            final View decoratedSubview = decorateSubview(view.getViewAxes(), fieldView);
+            view.addView(decoratedSubview);
+
+            // set focus to first value field
+            if (focusOn == null && parameter instanceof TextParseableParameter && fieldView.canFocus()) {
+                focusOn = decoratedSubview;
+            }
+        }
+
+        if (focusOn != null) {
+            view.getViewManager().setKeyboardFocus(focusOn);
+        }
+    }
+
+    private void updateBuild(final View view, final ActionContent actionContent) {
+        LOG.debug("rebuild view " + view + " for " + actionContent);
+        final View[] subviews = view.getSubviews();
+
+        for (int i = 0; i < subviews.length; i++) {
+            final View subview = subviews[i];
+            final Content content = subview.getContent();
+
+            final ObjectAdapter subviewsObject = subview.getContent().getAdapter();
+            final ObjectAdapter invocationsObject = ((ActionContent) view.getContent()).getParameterObject(i);
+
+            if (content instanceof ObjectParameter) {
+                if (subviewsObject != invocationsObject) {
+                    final ObjectParameter parameter = new ObjectParameterImpl((ObjectParameterImpl) content, invocationsObject);
+                    final View fieldView = createFieldView(view, parameter, i);
+                    view.replaceView(subview, decorateSubview(view.getViewAxes(), fieldView));
+                }
+            } else {
+                subview.refresh();
+            }
+        }
+    }
+}