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

[17/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/util/Properties.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/Properties.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/Properties.java
new file mode 100644
index 0000000..8dea790
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/Properties.java
@@ -0,0 +1,160 @@
+/*
+ *  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.util;
+
+import java.util.StringTokenizer;
+
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.commons.config.IsisConfigurationException;
+import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+
+public class Properties {
+
+    public static final String PROPERTY_BASE = ConfigurationConstants.ROOT + "viewer.dnd.";
+
+    public static Size getSize(final String name, final Size defaultSize) {
+        String initialSize = optionFor(name);
+        if (initialSize == null) {
+            initialSize = IsisContext.getConfiguration().getString(name);
+        }
+        if (initialSize != null) {
+            final StringTokenizer st = new StringTokenizer(initialSize, "x");
+            if (st.countTokens() == 2) {
+                int width = 0;
+                int height = 0;
+                width = Integer.valueOf(st.nextToken().trim()).intValue();
+                height = Integer.valueOf(st.nextToken().trim()).intValue();
+                return new Size(width, height);
+            } else {
+                throw new IsisConfigurationException("Size not specified correctly in " + name + ": " + initialSize);
+            }
+        }
+        return defaultSize;
+    }
+
+    public static void saveSizeOption(final String name, final Size size) {
+        final String value = size.getWidth() + "x" + size.getHeight();
+        IsisContext.getUserProfile().getOptions().addOption(name, value);
+    }
+
+    public static Location getLocation(final String name, final Location defaultLocation) {
+        String initialLocation = optionFor(name);
+        if (initialLocation == null) {
+            initialLocation = IsisContext.getConfiguration().getString(name);
+        }
+        if (initialLocation != null) {
+            final StringTokenizer st = new StringTokenizer(initialLocation, ",");
+            if (st.countTokens() == 2) {
+                int x = 0;
+                int y = 0;
+                x = Integer.valueOf(st.nextToken().trim()).intValue();
+                y = Integer.valueOf(st.nextToken().trim()).intValue();
+                return new Location(x, y);
+            } else {
+                throw new IsisConfigurationException("Location not specified correctly in " + name + ": " + initialLocation);
+            }
+        }
+        return defaultLocation;
+    }
+
+    private static String optionFor(final String name) {
+        return IsisContext.inSession() ? IsisContext.getUserProfile().getOptions().getString(name) : null;
+    }
+
+    public static void saveLocationOption(final String name, final Location location) {
+        final String value = location.getX() + "," + location.getY();
+        IsisContext.getUserProfile().getOptions().addOption(name, value);
+    }
+
+    public static String getString(final String name) {
+        String value = optionFor(PROPERTY_BASE + name);
+        if (value == null) {
+            value = IsisContext.getConfiguration().getString(PROPERTY_BASE + name);
+        }
+        return value;
+    }
+
+    public static void setStringOption(final String name, final String value) {
+        IsisContext.getUserProfile().getOptions().addOption(PROPERTY_BASE + name, value);
+    }
+
+    public static Options getOptions(final String name) {
+        return IsisContext.getUserProfile().getOptions().getOptions(name);
+    }
+
+    public static String getDefaultIconViewOptions() {
+        return getString("view.icon-default");
+    }
+
+    public static String getDefaultObjectViewOptions() {
+        return getString("view.object-default");
+    }
+
+    public static String getDefaultCollectionViewOptions() {
+        return getString("view.collection-default");
+    }
+
+    public static Options getViewConfigurationOptions(final ViewSpecification specification) {
+        final Options settingsOptions = getOptions("views.configuration");
+        final String specificationName = specification.getName();
+        return settingsOptions.getOptions(specificationName);
+    }
+
+    public static Options getDefaultViewOptions(final ObjectSpecification specification) {
+        final Options settingsOptions = getOptions("views.type-default");
+        String name;
+        if (specification.isParentedOrFreeCollection()) {
+            name = "collection:" + specification.getFacet(TypeOfFacet.class).valueSpec().getFullIdentifier();
+        } else {
+            name = specification.getFullIdentifier();
+        }
+        final Options viewOptions = settingsOptions.getOptions(name);
+        return viewOptions;
+    }
+
+    public static Options getUserViewSpecificationOptions(final String specificationName) {
+        final Options settingsOptions = getOptions("views.user-defined");
+        return settingsOptions.getOptions(specificationName);
+    }
+
+    public static Object loadClass(final Options viewOptions, final String name) {
+        final String specificationName = viewOptions.getString(name);
+        if (specificationName != null) {
+            try {
+                final Class<?> specificationClass = Class.forName(specificationName);
+                return specificationClass.newInstance();
+            } catch (final ClassNotFoundException e) {
+                throw new ViewerException(e);
+            } catch (final InstantiationException e) {
+                throw new ViewerException(e);
+            } catch (final IllegalAccessException e) {
+                throw new ViewerException(e);
+            }
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/ViewerException.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/ViewerException.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/ViewerException.java
new file mode 100644
index 0000000..dd3a66d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/util/ViewerException.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.util;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+
+public class ViewerException extends IsisException {
+    private static final long serialVersionUID = 1L;
+
+    public ViewerException() {
+    }
+
+    public ViewerException(final String message) {
+        super(message);
+    }
+
+    public ViewerException(final String messageFormat, final Object... args) {
+        super(messageFormat, args);
+    }
+
+    public ViewerException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public ViewerException(final Throwable cause) {
+        super(cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Axes.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Axes.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Axes.java
new file mode 100644
index 0000000..6bfea27
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Axes.java
@@ -0,0 +1,75 @@
+/*
+ *  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.view;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.util.ViewerException;
+
+public class Axes {
+    private static final Logger LOG = Logger.getLogger(Axes.class);
+    private final Map<Class<?>, ViewAxis> axes = new HashMap<Class<?>, ViewAxis>();
+
+    public void add(final ViewAxis axis) {
+        if (axis != null) {
+            final Class<? extends ViewAxis> cls = axis.getClass();
+            add(axis, cls);
+        }
+    }
+
+    public void add(final ViewAxis axis, final Class<? extends ViewAxis> cls) {
+        final ViewAxis previous = axes.put(cls, axis);
+        if (previous != null) {
+            LOG.debug(axis + " replacing " + previous);
+        } else {
+            LOG.debug("adding " + axis);
+        }
+    }
+
+    public <T extends ViewAxis> T getAxis(final Class<T> axisClass) {
+        final ViewAxis viewAxis = axes.get(axisClass);
+        if (viewAxis == null) {
+            throw new ViewerException("No axis of type " + axisClass + " in " + this);
+        }
+        return (T) viewAxis;
+    }
+
+    public boolean contains(final Class<? extends ViewAxis> axisClass) {
+        return axes.containsKey(axisClass);
+    }
+
+    public void add(final Axes axes) {
+        this.axes.putAll(axes.axes);
+    }
+
+    @Override
+    public String toString() {
+        // TODO provide flag to list as elements, rather than fields
+        final ToString s = new ToString(this);
+        for (final ViewAxis axis : axes.values()) {
+            s.append(axis.toString());
+        }
+        return s.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/BackgroundTask.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/BackgroundTask.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/BackgroundTask.java
new file mode 100644
index 0000000..0b7f5bb
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/BackgroundTask.java
@@ -0,0 +1,28 @@
+/*
+ *  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.view;
+
+public interface BackgroundTask {
+    void execute();
+
+    String getName();
+
+    String getDescription();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ButtonAction.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ButtonAction.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ButtonAction.java
new file mode 100644
index 0000000..f030197
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ButtonAction.java
@@ -0,0 +1,26 @@
+/*
+ *  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.view;
+
+public interface ButtonAction extends UserAction {
+
+    boolean isDefault();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Click.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Click.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Click.java
new file mode 100644
index 0000000..d16bcf7
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Click.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public interface Click {
+
+    Location getLocationWithinViewer();
+
+    Location getLocation();
+
+    boolean button2();
+
+    boolean button1();
+
+    boolean button3();
+
+    boolean isAlt();
+
+    boolean isShift();
+
+    boolean isCtrl();
+
+    void subtract(int left, int top);
+
+    void subtract(Location location);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Command.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Command.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Command.java
new file mode 100644
index 0000000..feff988
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Command.java
@@ -0,0 +1,30 @@
+/*
+ *  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.view;
+
+public interface Command {
+    String getDescription();
+
+    void undo();
+
+    void execute();
+
+    String getName();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/CompositeViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/CompositeViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/CompositeViewSpecification.java
new file mode 100644
index 0000000..d99660f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/CompositeViewSpecification.java
@@ -0,0 +1,24 @@
+/*
+ *  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.view;
+
+public interface CompositeViewSpecification extends ViewSpecification {
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Content.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Content.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Content.java
new file mode 100644
index 0000000..958b332
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Content.java
@@ -0,0 +1,116 @@
+/*
+ *  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.view;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.dnd.drawing.Image;
+
+public interface Content {
+
+    /**
+     * Determines if the specified content can be drop on this content.
+     */
+    Consent canDrop(Content sourceContent);
+
+    /**
+     * Allows this content to add menu options to the set of menu options the
+     * user will see for this content.
+     * 
+     * @see #viewMenuOptions(UserActionSet)
+     */
+    void contentMenuOptions(UserActionSet options);
+
+    void debugDetails(DebugBuilder debug);
+
+    /**
+     * Implements the response to the dropping of the specified content onto
+     * this content.
+     */
+    ObjectAdapter drop(Content sourceContent);
+
+    String getDescription();
+
+    String getHelp();
+
+    /**
+     * The name of the icon to use to respresent the object represented by this
+     * content.
+     */
+    String getIconName();
+
+    /**
+     * The icon to use to respresent the object represented by this content.
+     */
+    Image getIconPicture(int iconHeight);
+
+    String getId();
+
+    /**
+     * The object represented by this content.
+     */
+    ObjectAdapter getAdapter();
+
+    ObjectAdapter[] getOptions();
+
+    /**
+     * The specification of the object represented by this content.
+     */
+    ObjectSpecification getSpecification();
+
+    /**
+     * Returns true if this content represents a CollectionAdapter.
+     */
+    boolean isCollection();
+
+    /**
+     * Returns true if this content represents a ObjectAdapter.
+     */
+    boolean isObject();
+
+    /**
+     * Returns true if the object represented by this content can be persisted.
+     */
+    boolean isPersistable();
+
+    boolean isOptionEnabled();
+
+    /**
+     * Returns true if the object represented by this content is transient; has
+     * not been persisted yet.
+     */
+    boolean isTransient();
+
+    boolean isTextParseable();
+
+    String title();
+
+    /**
+     * Allows this content to add menu options to the set of menu options the
+     * user will see for this view.
+     * 
+     * @see #contentMenuOptions(UserActionSet)
+     */
+    void viewMenuOptions(UserActionSet options);
+
+    String windowTitle();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentDrag.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentDrag.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentDrag.java
new file mode 100644
index 0000000..9f4f0f0
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentDrag.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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+/**
+ * Details a drag event that affects a view's content (as opposed to the view
+ * itself).
+ */
+public interface ContentDrag extends Drag {
+
+    Content getSourceContent();
+
+    boolean isShift();
+
+    Location getTargetLocation();
+
+    Location getOffset();
+
+    void subtract(int borderWidth, int borderWidth2);
+
+    View getTargetView();
+
+    // TODO rename to getSourceView
+    View getSource();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentFactory.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentFactory.java
new file mode 100644
index 0000000..1f63aee
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ContentFactory.java
@@ -0,0 +1,30 @@
+/*
+ *  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.view;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+
+public interface ContentFactory {
+
+    Content createRootContent(ObjectAdapter object);
+
+    Content createFieldContent(ObjectAssociation field, ObjectAdapter object);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Drag.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Drag.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Drag.java
new file mode 100644
index 0000000..bc2c672
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Drag.java
@@ -0,0 +1,26 @@
+/*
+ *  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.view;
+
+/**
+ * Details a drag event - from drag start to drop,
+ */
+public interface Drag {
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragEvent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragEvent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragEvent.java
new file mode 100644
index 0000000..c6cb34c
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragEvent.java
@@ -0,0 +1,34 @@
+/*
+ *  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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public interface DragEvent {
+
+    void drag(View target, Location location, int modifiers);
+
+    void cancel(Viewer viewer);
+
+    void end(Viewer viewer);
+
+    View getOverlay();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragStart.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragStart.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragStart.java
new file mode 100644
index 0000000..e701e55
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/DragStart.java
@@ -0,0 +1,33 @@
+/*
+ *  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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public interface DragStart extends Drag {
+
+    Location getLocation();
+
+    void subtract(int left, int top);
+
+    void subtract(Location location);
+
+    boolean isCtrl();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Feedback.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Feedback.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Feedback.java
new file mode 100644
index 0000000..c2a417e
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Feedback.java
@@ -0,0 +1,78 @@
+/*
+ *  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.view;
+
+public interface Feedback {
+
+    void showException(final Throwable e);
+
+    void showArrowCursor();
+
+    void showCrosshairCursor();
+
+    void showDefaultCursor();
+
+    void showTextCursor();
+
+    void showHandCursor();
+
+    void showMoveCursor();
+
+    void showResizeDownCursor();
+
+    void showResizeDownLeftCursor();
+
+    void showResizeDownRightCursor();
+
+    void showResizeLeftCursor();
+
+    void showResizeRightCursor();
+
+    void showResizeUpCursor();
+
+    void showResizeUpLeftCursor();
+
+    void showResizeUpRightCursor();
+
+    void setBusy(final View view, BackgroundTask task);
+
+    void clearBusy(final View view);
+
+    boolean isBusy(View view);
+
+    String getStatusBarOutput();
+
+    void showMessagesAndWarnings();
+
+    void setViewDetail(String string);
+
+    void setAction(String actionText);
+
+    void addMessage(String string);
+
+    void setError(String string);
+
+    void clearAction();
+
+    void clearError();
+
+    void showBusyState(View view);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/FocusManager.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/FocusManager.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/FocusManager.java
new file mode 100644
index 0000000..8b6b531
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/FocusManager.java
@@ -0,0 +1,57 @@
+/*
+ *  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.view;
+
+/**
+ * Details where to move the focus to.
+ */
+public interface FocusManager {
+    /**
+     * The next view within the container to move the focus to; move to next
+     * field.
+     */
+    void focusNextView();
+
+    /**
+     * The previous view within the container to move the focus to; move to
+     * previous field.
+     */
+    void focusPreviousView();
+
+    /**
+     * The parent view within the container to move the focus to; move up to
+     * containing view in the hierachy.
+     */
+    void focusParentView();
+
+    /**
+     * The first child view within the container to move the focus to; move down
+     * to the first view within the current view.
+     */
+    void focusFirstChildView();
+
+    void focusLastChildView();
+
+    void focusInitialChildView();
+
+    View getFocus();
+
+    void setFocus(View view);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/GlobalViewFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/GlobalViewFactory.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/GlobalViewFactory.java
new file mode 100644
index 0000000..6d52c9f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/GlobalViewFactory.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.viewer.dnd.view;
+
+import java.util.Enumeration;
+
+import org.apache.isis.core.commons.debug.DebuggableWithTitle;
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+/*
+ * TODO this factory should always create views, not provide specifications; alternatively, this should be
+ * called something else and always return the specification The caller would then need to call the create
+ * method to create the object. The only case that would be slightly different would be the DragOutline one as
+ * the Axis is never used.
+ */
+public interface GlobalViewFactory extends DebuggableWithTitle {
+
+    void addSpecification(ViewSpecification spec);
+
+    Enumeration<ViewSpecification> availableViews(ViewRequirement viewRequirement);
+
+    Enumeration<ViewSpecification> availableDesigns(ViewRequirement viewRequirement);
+
+    View createDragViewOutline(View view);
+
+    DragEvent createDragContentOutline(View view, Location location);
+
+    View createMinimizedView(View view);
+
+    View createDialog(Content content);
+
+    View createView(ViewRequirement requirement);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpy.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpy.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpy.java
new file mode 100644
index 0000000..34e6d98
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpy.java
@@ -0,0 +1,153 @@
+/*
+ *  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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public class InteractionSpy {
+    private int actionCount;
+    private String damagedArea;
+    private int event;
+    private final String label[][] = new String[2][20];
+    private final InteractionSpyWindow spyWindow;
+    private final String[] trace = new String[60];
+    private int traceIndex;
+    private boolean isVisible;
+
+    public InteractionSpy(final InteractionSpyWindow spyWindow) {
+        this.spyWindow = spyWindow;
+    }
+
+    public void addAction(final String action) {
+        if (isVisible) {
+            set(actionCount++, "Action", action);
+        }
+    }
+
+    public void addDamagedArea(final Bounds bounds) {
+        if (isVisible) {
+            damagedArea += bounds + "; ";
+            set(7, "Damaged areas", damagedArea);
+        }
+    }
+
+    public void addTrace(final String message) {
+        if (isVisible && traceIndex < trace.length) {
+            trace[traceIndex] = message;
+            traceIndex++;
+        }
+    }
+
+    public void addTrace(final View view, final String message, final Object object) {
+        if (isVisible && traceIndex < trace.length) {
+            trace[traceIndex] = view.getClass().getName() + " " + message + ": " + object;
+            traceIndex++;
+        }
+    }
+
+    public void close() {
+        if (isVisible) {
+            spyWindow.close();
+            isVisible = false;
+        }
+    }
+
+    public void reset() {
+        if (isVisible) {
+            event++;
+            traceIndex = 0;
+            actionCount = 8;
+            damagedArea = "";
+            setDownAt(null);
+            for (int i = actionCount; i < label[0].length; i++) {
+                label[0][i] = null;
+                label[1][i] = null;
+            }
+        }
+    }
+
+    private void set(final int index, final String label, final Object debug) {
+        if (spyWindow != null) {
+            this.label[0][index] = debug == null ? null : label + ":";
+            this.label[1][index] = debug == null ? null : debug.toString();
+
+            spyWindow.display(event, this.label, trace, traceIndex);
+        }
+    }
+
+    public void setAbsoluteLocation(final Location absoluteLocation) {
+        if (isVisible) {
+            set(6, "Absolute view location", absoluteLocation);
+        }
+    }
+
+    public void setDownAt(final Location downAt) {
+        if (isVisible) {
+            set(0, "Down at", downAt);
+        }
+    }
+
+    public void setLocationInView(final Location internalLocation) {
+        if (isVisible) {
+            set(3, "Relative mouse location", internalLocation);
+        }
+    }
+
+    public void setLocationInViewer(final Location mouseLocation) {
+        if (isVisible) {
+            set(1, "Mouse location", mouseLocation);
+        }
+    }
+
+    public void setOver(final Object data) {
+        if (isVisible) {
+            set(2, "Mouse over", data);
+        }
+    }
+
+    public void setType(final ViewAreaType type) {
+        if (isVisible) {
+            set(4, "Area type", type);
+        }
+    }
+
+    public void setViewLocation(final Location locationWithinViewer) {
+        if (isVisible) {
+            set(5, "View location", locationWithinViewer);
+        }
+    }
+
+    public void open() {
+        if (!isVisible) {
+            spyWindow.open();
+            isVisible = true;
+        }
+    }
+
+    public boolean isVisible() {
+        return isVisible;
+    }
+
+    public void redraw(final String redrawArea, final int redrawCount) {
+        set(8, "Redraw", "#" + redrawCount + "  " + redrawArea);
+        damagedArea = "";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpyWindow.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpyWindow.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpyWindow.java
new file mode 100644
index 0000000..882b956
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InteractionSpyWindow.java
@@ -0,0 +1,29 @@
+/*
+ *  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.view;
+
+public interface InteractionSpyWindow {
+
+    void close();
+
+    void display(int event, String label[][], String[] trace, int traceIndex);
+
+    void open();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InternalDrag.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InternalDrag.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InternalDrag.java
new file mode 100644
index 0000000..4f1ac7f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/InternalDrag.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.viewer.dnd.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+/**
+ * Details a drag event that is internal to view.
+ */
+public interface InternalDrag extends Drag {
+    Location getLocation();
+
+    View getOverlay();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/KeyboardAction.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/KeyboardAction.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/KeyboardAction.java
new file mode 100644
index 0000000..b7eb41e
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/KeyboardAction.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.view;
+
+public interface KeyboardAction {
+    public static final int NONE = 0;
+    public static final int ABORT = 1;
+    public static final int NEXT_VIEW = 2;
+    public static final int NEXT_WINDOW = 3;
+    public static final int PREVIOUS_VIEW = 4;
+    public final static int PREVIOUS_WINDOW = 5;
+
+    int getKeyCode();
+
+    char getKeyChar();
+
+    int getModifiers();
+
+    void consume();
+
+    boolean isConsumed();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Look.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Look.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Look.java
new file mode 100644
index 0000000..97743fd
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Look.java
@@ -0,0 +1,26 @@
+/*
+ *  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.view;
+
+public interface Look {
+    void install();
+
+    String getName();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/MenuOptions.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/MenuOptions.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/MenuOptions.java
new file mode 100644
index 0000000..90d9d6f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/MenuOptions.java
@@ -0,0 +1,26 @@
+/*
+ *  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.view;
+
+public interface MenuOptions {
+
+    public abstract void menuOptions(final UserActionSet options);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ObjectContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ObjectContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ObjectContent.java
new file mode 100644
index 0000000..86f5263
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ObjectContent.java
@@ -0,0 +1,37 @@
+/*
+ *  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.view;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+
+public interface ObjectContent extends Content {
+
+    Consent canClear();
+
+    Consent canSet(final ObjectAdapter dragSource);
+
+    void clear();
+
+    ObjectAdapter getObject();
+
+    void setObject(final ObjectAdapter object);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Placement.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Placement.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Placement.java
new file mode 100644
index 0000000..18bae8d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Placement.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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+
+/**
+ * Used to determine the placement of a new view on the workspace. It can be: an
+ * absolute placement given a Location; a position relative to a given view; or
+ * in the center. A relative placement uses the PlacementStrategy to determine
+ * an optimum location.
+ */
+public class Placement {
+    private static final int ABSOLUTE = 1;
+    private static final int RELATIVE = 2;
+    public static final int CENTER = 3;
+    private static PlacementStrategy placementStrategy = new PlacementStrategyImpl();
+    private final Location location;
+    private final View relativeTo;
+    private final int position;
+
+    public Placement(final Location location) {
+        this.location = location;
+        relativeTo = null;
+        position = ABSOLUTE;
+    }
+
+    public Placement(final View relativeTo) {
+        this.relativeTo = relativeTo.getView();
+        location = null;
+        position = RELATIVE;
+    }
+
+    public Placement(final int position) {
+        this.relativeTo = null;
+        location = null;
+        this.position = position;
+    }
+
+    private Location center(final View workspace, final View view) {
+        final Size rootSize = workspace.getSize();
+        final Location location = new Location(rootSize.getWidth() / 2, rootSize.getHeight() / 2);
+        final Size dialogSize = view.getRequiredSize(new Size(rootSize));
+        location.subtract(dialogSize.getWidth() / 2, dialogSize.getHeight() / 2);
+        return location;
+    }
+
+    public void position(final Workspace workspace, final View view) {
+        switch (position) {
+        case ABSOLUTE:
+            view.setLocation(location);
+            break;
+
+        case RELATIVE:
+            view.setLocation(placementStrategy.determinePlacement(workspace, relativeTo, view));
+            break;
+
+        case CENTER:
+            view.setLocation(center(workspace, view));
+            break;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategy.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategy.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategy.java
new file mode 100644
index 0000000..24260fc
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategy.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.viewer.dnd.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+/**
+ * Determines an option location for a new view relative to an existing view,
+ * 
+ * @see Placement
+ */
+public interface PlacementStrategy {
+    Location determinePlacement(Workspace workspace, final View relativeToView, final View view);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategyImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategyImpl.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategyImpl.java
new file mode 100644
index 0000000..c368b52
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/PlacementStrategyImpl.java
@@ -0,0 +1,95 @@
+/*
+ *  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.view;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+
+// TODO move out of this package and inject it
+public class PlacementStrategyImpl implements PlacementStrategy {
+    private static final int PADDING = 10;
+
+    @Override
+    public Location determinePlacement(final Workspace workspace, final View relativeToView, final View newView) {
+        if (relativeToView == null) {
+            return new Location();
+        }
+
+        final Size workspaceSize = workspace.getSize();
+        final View rootView = rootView(workspace, relativeToView);
+        final Location rootViewLocation = rootView.getLocation();
+        final Size rootViewSize = rootView.getSize();
+        final Location newLocation = new Location(rootViewLocation);
+        final Size requiredSize = newView.getView().getRequiredSize(Size.createMax());
+
+        if (rootViewLocation.getX() + rootViewSize.getWidth() + PADDING + requiredSize.getWidth() < workspaceSize.getWidth()) {
+            newLocation.add(rootViewSize.getWidth() + PADDING, 0);
+        } else if (rootViewLocation.getY() + rootViewSize.getHeight() + PADDING + requiredSize.getHeight() < workspaceSize.getHeight()) {
+            newLocation.add(0, rootViewSize.getHeight() + PADDING);
+        } else if (requiredSize.getWidth() + PADDING < rootViewLocation.getX()) {
+            newLocation.subtract(requiredSize.getWidth() + PADDING, 0);
+        } else if (requiredSize.getHeight() + PADDING < rootViewLocation.getY()) {
+            newLocation.subtract(0, requiredSize.getHeight() + PADDING);
+        } else {
+            newLocation.add(PADDING * 6, PADDING * 6);
+        }
+
+        final int maxSpaceToLeft = workspaceSize.getWidth() - requiredSize.getWidth();
+        final int maxSpaceAbove = workspaceSize.getHeight() - requiredSize.getHeight();
+
+        ensureWidth(newLocation, maxSpaceToLeft);
+        ensureHeight(newLocation, maxSpaceAbove);
+
+        final Location firstAttempt = new Location(newLocation);
+
+        while (workspace.subviewFor(newLocation) != null && workspace.subviewFor(newLocation).getLocation().equals(newLocation)) {
+            newLocation.add(PADDING * 4, PADDING * 4);
+            ensureWidth(newLocation, maxSpaceToLeft);
+            ensureHeight(newLocation, maxSpaceAbove);
+
+            if (newLocation.equals(firstAttempt)) {
+                break;
+            }
+        }
+        return newLocation;
+    }
+
+    private void ensureHeight(final Location ofLocation, final int availableHeight) {
+        final int yoffset = availableHeight - ofLocation.getY();
+        if (yoffset < 0) {
+            ofLocation.add(0, yoffset);
+            ofLocation.setY(Math.max(0, ofLocation.getY()));
+        }
+    }
+
+    private void ensureWidth(final Location ofLocation, final int availableWifth) {
+        final int xoffset = availableWifth - ofLocation.getX();
+        if (xoffset < 0) {
+            ofLocation.add(xoffset, 0);
+            ofLocation.setX(Math.max(0, ofLocation.getX()));
+        }
+    }
+
+    private View rootView(final View workspace, final View relativeTo) {
+        final View parent = relativeTo.getParent().getView();
+        return parent == null || parent == workspace ? relativeTo : rootView(workspace, parent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Selectable.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Selectable.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Selectable.java
new file mode 100644
index 0000000..04fa82c
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Selectable.java
@@ -0,0 +1,28 @@
+/*
+ *  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.view;
+
+public interface Selectable {
+
+    int getId();
+
+    void setSelectedNode(View selectedView);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ShutdownListener.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ShutdownListener.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ShutdownListener.java
new file mode 100644
index 0000000..f6a0b33
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/ShutdownListener.java
@@ -0,0 +1,27 @@
+/*
+ *  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.view;
+
+public interface ShutdownListener {
+
+    void quit();
+
+    void logOut();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/SubviewDecorator.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/SubviewDecorator.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/SubviewDecorator.java
new file mode 100644
index 0000000..d342f22
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/SubviewDecorator.java
@@ -0,0 +1,26 @@
+/*
+ *  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.view;
+
+public interface SubviewDecorator {
+    ViewAxis createAxis(Content content);
+
+    View decorate(Axes axes, View view);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Toolkit.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Toolkit.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Toolkit.java
new file mode 100644
index 0000000..f761721
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/Toolkit.java
@@ -0,0 +1,95 @@
+/*
+ *  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.view;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+
+public abstract class Toolkit {
+    public static boolean debug = false;
+    private static Toolkit instance;
+
+    public static int defaultBaseline() {
+        return getInstance().colorsAndFonts.defaultBaseline();
+    }
+
+    public static int defaultFieldHeight() {
+        return getInstance().colorsAndFonts.defaultFieldHeight();
+    }
+
+    public static Color getColor(final int rgbColor) {
+        return getInstance().colorsAndFonts.getColor(rgbColor);
+    }
+
+    public static Color getColor(final String name) {
+        final Color color = getInstance().colorsAndFonts.getColor(name);
+        if (color == null) {
+            throw new IsisException("No such color: " + name);
+        }
+        return color;
+    }
+
+    public static ContentFactory getContentFactory() {
+        return getInstance().contentFactory;
+    }
+
+    protected static Toolkit getInstance() {
+        return instance;
+    }
+
+    public static Text getText(final String name) {
+        final Text text = getInstance().colorsAndFonts.getText(name);
+        if (text == null) {
+            throw new IsisException("No such text style: " + name);
+        }
+        return text;
+    }
+
+    public static Viewer getViewer() {
+        return getInstance().viewer;
+    }
+
+    public static Feedback getFeedbackManager() {
+        return getInstance().feedbackManager;
+    }
+
+    public static GlobalViewFactory getViewFactory() {
+        return getInstance().viewFactory;
+    }
+
+    protected ContentFactory contentFactory;
+    protected ColorsAndFonts colorsAndFonts;
+    protected Viewer viewer;
+    protected Feedback feedbackManager;
+    protected GlobalViewFactory viewFactory;
+
+    protected Toolkit() {
+        if (instance != null) {
+            throw new IllegalStateException("Toolkit already instantiated");
+        }
+        instance = this;
+        init();
+    }
+
+    protected abstract void init();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UndoStack.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UndoStack.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UndoStack.java
new file mode 100644
index 0000000..586f450
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UndoStack.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view;
+
+import java.util.Vector;
+
+public class UndoStack {
+
+    private final Vector<Command> commands = new Vector<Command>();
+
+    public void add(final Command command) {
+        commands.addElement(command);
+        command.execute();
+    }
+
+    public void undoLastCommand() {
+        final Command lastCommand = commands.lastElement();
+        lastCommand.undo();
+        commands.removeElement(lastCommand);
+    }
+
+    public String descriptionOfUndo() {
+        final Command lastCommand = commands.lastElement();
+        return lastCommand.getDescription();
+    }
+
+    public boolean isEmpty() {
+        return commands.isEmpty();
+    }
+
+    public String getNameOfUndo() {
+        final Command lastCommand = commands.lastElement();
+        return lastCommand.getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserAction.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserAction.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserAction.java
new file mode 100644
index 0000000..240492c
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserAction.java
@@ -0,0 +1,57 @@
+/*
+ *  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.view;
+
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public interface UserAction {
+
+    /**
+     * Returns the type of action: user, exploration, debug, or a set.
+     */
+    ActionType getType();
+
+    /**
+     * Indicate that this action is disabled
+     */
+    Consent disabled(View view);
+
+    /**
+     * Invoke this action.
+     */
+    void execute(Workspace workspace, View view, Location at);
+
+    /**
+     * Returns the description of the action.
+     */
+    String getDescription(View view);
+
+    /**
+     * Returns the help text for the action.
+     */
+    String getHelp(View view);
+
+    /**
+     * Returns the name of the action as the user will refer to it.
+     */
+    String getName(View view);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserActionSet.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserActionSet.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserActionSet.java
new file mode 100644
index 0000000..a3d7048
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/UserActionSet.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.viewer.dnd.view;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.dnd.drawing.Color;
+
+public interface UserActionSet extends UserAction {
+
+    void add(UserAction userAction);
+
+    void addObjectMenuOptions(ObjectAdapter object);
+
+    void addCreateOptions(ObjectSpecification specification);
+
+    UserActionSet addNewActionSet(String name);
+
+    UserActionSet addNewActionSet(String name, ActionType type);
+
+    UserAction[] getUserActions();
+
+    Color getColor();
+
+    void setColor(Color color);
+}