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/06 18:42:18 UTC

[46/52] [partial] ISIS-188: moving framework/ subdirs up to parent

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormSpecification.java
new file mode 100644
index 0000000..b96dc58
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormSpecification.java
@@ -0,0 +1,43 @@
+/*
+ *  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.form;
+
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.FieldLabelsDecorator;
+
+public class FormSpecification extends AbstractFormSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return super.canDisplay(requirement) && !requirement.is(ViewRequirement.SUBVIEW);
+    }
+
+    @Override
+    protected void init() {
+        addSubviewDecorator(new FieldLabelsDecorator());
+        addViewDecorator(new IconBorder.Factory());
+    }
+
+    @Override
+    public String getName() {
+        return "Form";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormWithDetailSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormWithDetailSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormWithDetailSpecification.java
new file mode 100644
index 0000000..5cbbe92
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/FormWithDetailSpecification.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.form;
+
+import java.util.List;
+
+import org.apache.isis.applib.filter.Filter;
+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.OneToOneAssociation;
+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.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.border.SelectObjectBorder;
+import org.apache.isis.viewer.dnd.view.composite.MasterDetailPanel;
+
+public class FormWithDetailSpecification implements ViewSpecification {
+    private final FormSpecification leftHandSideSpecification;
+
+    public FormWithDetailSpecification() {
+        leftHandSideSpecification = new FormSpecification();
+        leftHandSideSpecification.addSubviewDecorator(new SelectObjectBorder.Factory());
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isObject() && requirement.isOpen() && !requirement.isSubview() && containsEnoughFields(requirement.getContent());
+    }
+
+    private boolean containsEnoughFields(final Content content) {
+        final ObjectSpecification specification = content.getSpecification();
+        final List<ObjectAssociation> associations = specification.getAssociations(new Filter<ObjectAssociation>() {
+            @Override
+            public boolean accept(final ObjectAssociation t) {
+                return t.isOneToManyAssociation() || (t.isOneToOneAssociation() && !((OneToOneAssociation) t).getSpecification().isParseable());
+            }
+        });
+        return associations.size() >= 1;
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        return new MasterDetailPanel(content, this, leftHandSideSpecification);
+    }
+
+    @Override
+    public String getName() {
+        return "Form and details (experimental)";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return true;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return true;
+    }
+
+    @Override
+    public boolean isSubView() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/InternalFormSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/InternalFormSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/InternalFormSpecification.java
new file mode 100644
index 0000000..05603d2
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/InternalFormSpecification.java
@@ -0,0 +1,47 @@
+/*
+ *  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.form;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.FieldLabelsDecorator;
+
+public class InternalFormSpecification extends AbstractFormSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return super.canDisplay(requirement) && requirement.is(ViewRequirement.SUBVIEW);
+    }
+
+    @Override
+    protected void init() {
+        addSubviewDecorator(new FieldLabelsDecorator());
+        addViewDecorator(new IconBorder.Factory(Toolkit.getText(ColorsAndFonts.TEXT_NORMAL)));
+
+    }
+
+    @Override
+    public String getName() {
+        return "Internal form";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFields.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFields.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFields.java
new file mode 100644
index 0000000..4d7bacf
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFields.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.form;
+
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.composite.StandardFields;
+
+public class SummaryFields extends StandardFields {
+
+    @Override
+    protected int collectionRequirement() {
+        return ViewRequirement.NONE;
+    }
+
+    @Override
+    protected boolean include(final Content content, final int sequence) {
+        return sequence < 4 && content.getAdapter() != null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFormSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFormSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFormSpecification.java
new file mode 100644
index 0000000..ac2cc27
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/form/SummaryFormSpecification.java
@@ -0,0 +1,60 @@
+/*
+ *  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.form;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+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.border.BackgroundBorder;
+import org.apache.isis.viewer.dnd.view.border.EmptyBorder;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.border.LineBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+
+public class SummaryFormSpecification extends AbstractFormSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isObject() && !requirement.isTextParseable() && requirement.hasReference() && requirement.isOpen() && requirement.isSubview() && requirement.isFixed();
+    }
+
+    @Override
+    protected void init() {
+        addViewDecorator(new IconBorder.Factory());
+        addViewDecorator(new CompositeViewDecorator() {
+            @Override
+            public View decorate(final View view, final Axes axes) {
+                return new EmptyBorder(3, new BackgroundBorder(new LineBorder(1, 8, new EmptyBorder(3, view))));
+            }
+        });
+    }
+
+    @Override
+    protected ViewFactory createFieldFactory() {
+        return new SummaryFields();
+    }
+
+    @Override
+    public String getName() {
+        return "Summary";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/grid/GridSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/grid/GridSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/grid/GridSpecification.java
new file mode 100644
index 0000000..c3896ac
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/grid/GridSpecification.java
@@ -0,0 +1,114 @@
+/*
+ *  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.grid;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.form.AbstractFormSpecification;
+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.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.EmptyBorder;
+import org.apache.isis.viewer.dnd.view.composite.CollectionElementBuilder;
+import org.apache.isis.viewer.dnd.view.composite.ColumnLayout;
+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.content.FieldContent;
+
+public class GridSpecification extends CompositeViewSpecification {
+
+    public GridSpecification() {
+        builder = new CollectionElementBuilder(new AbstractFormSpecification() {
+            @Override
+            public String getName() {
+                return "";
+            }
+
+            @Override
+            protected void init() {
+                super.init();
+                addSubviewDecorator(new SubviewDecorator() {
+                    @Override
+                    public ViewAxis createAxis(final Content content) {
+                        return null;
+                    }
+
+                    @Override
+                    public View decorate(final Axes axes, final View view) {
+                        return new EmptyBorder(0, 0, 5, 0, view);
+                    }
+                });
+            }
+        });
+
+        addViewDecorator(new ColumnLabelBorder.Factory());
+    }
+
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new ColumnLayout(true);
+    }
+
+    @Override
+    public String getName() {
+        return "Grid (experimental)";
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isCollection() && requirement.isOpen();
+    }
+}
+
+class ColumnLabelBorder extends AbstractBorder {
+
+    public static class Factory implements CompositeViewDecorator {
+        @Override
+        public View decorate(final View view, final Axes axes) {
+            return new ColumnLabelBorder(view);
+        }
+    }
+
+    protected ColumnLabelBorder(final View view) {
+        super(view);
+        left = 100;
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        final View subview = getSubviews()[0];
+
+        final int top = subview.getPadding().getTop();
+        for (final View view : subview.getSubviews()) {
+            final String fieldName = ((FieldContent) view.getContent()).getFieldName();
+            canvas.drawText(fieldName + ":", 0, view.getLocation().getY() + top + view.getBaseline(), Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1), Toolkit.getText(ColorsAndFonts.TEXT_LABEL));
+            // canvas.drawRectangle(0, view.getLocation().getY() + top, 80, 10,
+            // Toolkit.getColor("primary1"));
+        }
+
+        super.draw(canvas);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/AboutView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/AboutView.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/AboutView.java
new file mode 100644
index 0000000..2e9beb1
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/AboutView.java
@@ -0,0 +1,171 @@
+/*
+ *  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.help;
+
+import org.apache.isis.core.runtime.about.AboutIsis;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.ImageFactory;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.window.SubviewFocusManager;
+
+public class AboutView extends AbstractView {
+    private static final int MAX_WIDTH = 300;
+    private final int linePadding = -2;
+    private final int noticePadding = 45;
+    private final int margin = 14;
+    private final Image image;
+    private final int left;
+    private final FocusManager focusManager;
+
+    public AboutView() {
+        super(new NullContent());
+        image = ImageFactory.getInstance().loadImage(AboutIsis.getImageName());
+        left = noticePadding;
+        setContent(new NullContent(AboutIsis.getFrameworkName()));
+
+        focusManager = new SubviewFocusManager(this);
+    }
+
+    @Override
+    public FocusManager getFocusManager() {
+        return focusManager;
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        super.draw(canvas);
+
+        final Text titleStyle = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+        final Text normalStyle = Toolkit.getText(ColorsAndFonts.TEXT_LABEL);
+        final Color color = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+
+        clearBackground(canvas, Toolkit.getColor(ColorsAndFonts.COLOR_WHITE));
+        canvas.drawRectangleAround(getBounds(), Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3));
+
+        if (showingImage()) {
+            canvas.drawImage(image, margin, margin);
+        }
+
+        int line = margin + image.getHeight() + noticePadding + normalStyle.getAscent();
+
+        // application details
+        String text = AboutIsis.getApplicationName();
+        if (text != null) {
+            canvas.drawText(text, left, line, MAX_WIDTH, color, titleStyle);
+            line += titleStyle.stringHeight(text, MAX_WIDTH) + titleStyle.getLineSpacing() + linePadding;
+        }
+        text = AboutIsis.getApplicationCopyrightNotice();
+        if (text != null) {
+            canvas.drawText(text, left, line, MAX_WIDTH, color, normalStyle);
+            line += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+        }
+        text = AboutIsis.getApplicationVersion();
+        if (text != null) {
+            canvas.drawText(text, left, line, MAX_WIDTH, color, normalStyle);
+            line += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+            line += 2 * normalStyle.getLineHeight();
+        }
+
+        // framework details
+        text = AboutIsis.getFrameworkName();
+        canvas.drawText(text, left, line, MAX_WIDTH, color, titleStyle);
+        line += titleStyle.stringHeight(text, MAX_WIDTH) + titleStyle.getLineSpacing() + linePadding;
+
+        text = AboutIsis.getFrameworkCopyrightNotice();
+        canvas.drawText(text, left, line, MAX_WIDTH, color, normalStyle);
+        line += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+
+        canvas.drawText(frameworkVersion(), left, line, MAX_WIDTH, color, normalStyle);
+
+    }
+
+    private String frameworkVersion() {
+        return AboutIsis.getFrameworkVersion();
+    }
+
+    private boolean showingImage() {
+        return image != null;
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        final Text titleStyle = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+        final Text normalStyle = Toolkit.getText(ColorsAndFonts.TEXT_LABEL);
+
+        int height = 0;
+
+        String text = AboutIsis.getFrameworkName();
+        height += titleStyle.stringHeight(text, MAX_WIDTH) + titleStyle.getLineSpacing() + linePadding;
+        // height += normalStyle.getLineHeight();
+        int width = titleStyle.stringWidth(text, MAX_WIDTH);
+
+        text = AboutIsis.getFrameworkCopyrightNotice();
+        height += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+        // height += normalStyle.getLineHeight();
+        width = Math.max(width, normalStyle.stringWidth(text, MAX_WIDTH));
+
+        text = frameworkVersion();
+        height += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+        // height += normalStyle.getLineHeight();
+        width = Math.max(width, normalStyle.stringWidth(text, MAX_WIDTH));
+
+        text = AboutIsis.getApplicationName();
+        if (text != null) {
+            height += titleStyle.stringHeight(text, MAX_WIDTH) + titleStyle.getLineSpacing() + linePadding;
+            // height += normalStyle.getLineHeight();
+            width = Math.max(width, titleStyle.stringWidth(text, MAX_WIDTH));
+        }
+        text = AboutIsis.getApplicationCopyrightNotice();
+        if (text != null) {
+            height += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+            // height += normalStyle.getLineHeight();
+            width = Math.max(width, normalStyle.stringWidth(text, MAX_WIDTH));
+        }
+        text = AboutIsis.getApplicationVersion();
+        if (text != null) {
+            height += normalStyle.stringHeight(text, MAX_WIDTH) + normalStyle.getLineSpacing() + linePadding;
+            // height += normalStyle.getLineHeight();
+            width = Math.max(width, normalStyle.stringWidth(text, MAX_WIDTH));
+        }
+
+        height += noticePadding;
+
+        if (showingImage()) {
+            height += image.getHeight();
+            width = Math.max(image.getWidth(), width);
+        }
+
+        return new Size(margin + width + margin, margin + height + margin);
+    }
+
+    @Override
+    public void firstClick(final Click click) {
+        // dispose();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/ExternalHelpViewerProgram.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/ExternalHelpViewerProgram.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/ExternalHelpViewerProgram.java
new file mode 100644
index 0000000..ec05f71
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/ExternalHelpViewerProgram.java
@@ -0,0 +1,48 @@
+/*
+ *  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.help;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+public class ExternalHelpViewerProgram implements HelpViewer {
+    private static final Logger LOG = Logger.getLogger(ExternalHelpViewerProgram.class);
+    private final String program;
+
+    public ExternalHelpViewerProgram(final String program) {
+        this.program = program;
+    }
+
+    @Override
+    public void open(final Location location, final String name, final String description, final String help) {
+        final String exec = program + " " + help;
+        try {
+            Runtime.getRuntime().exec(exec);
+            LOG.debug("executing '" + exec + "'");
+        } catch (final IOException e) {
+            throw new IsisException("faile to execute '" + exec + "'", e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpView.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpView.java
new file mode 100644
index 0000000..62cc21d
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpView.java
@@ -0,0 +1,98 @@
+/*
+ *  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.help;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.text.TextBlockTarget;
+import org.apache.isis.viewer.dnd.view.text.TextContent;
+
+public class HelpView extends AbstractView implements TextBlockTarget {
+    private static final int HEIGHT = 350;
+    private static final int WIDTH = 400;
+    private static final int MAX_TEXT_WIDTH = 375;
+    private final TextContent content;
+
+    public HelpView(final String name, final String description, final String help) {
+        super(new NullContent());
+        final String text = (name == null || name.trim().equals("") ? "" : (name + "\n")) + (description == null || description.trim().equals("") ? "" : (description + "\n")) + (help == null ? "" : help);
+        content = new TextContent(this, 10, TextContent.WRAPPING);
+        content.setText(text);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        int x = 0;
+        int y = 0;
+        final int xEntent = getSize().getWidth() - 1;
+        final int yExtent = getSize().getHeight() - 1;
+
+        final int arc = 9;
+        canvas.drawSolidRectangle(x + 2, y + 2, xEntent - 4, yExtent - 4, Toolkit.getColor(ColorsAndFonts.COLOR_WHITE));
+        final Color black = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+        canvas.drawRoundedRectangle(x, y++, xEntent, yExtent, arc, arc, black);
+        canvas.drawRoundedRectangle(x + 1, y++, xEntent - 2, yExtent - 2, arc, arc, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2));
+        canvas.drawRoundedRectangle(x + 2, y++, xEntent - 4, yExtent - 4, arc, arc, black);
+
+        x += 10;
+        y += ViewConstants.VPADDING;
+        y += Toolkit.getText(ColorsAndFonts.TEXT_TITLE).getTextHeight();
+        canvas.drawText("Help", x, y, black, Toolkit.getText(ColorsAndFonts.TEXT_TITLE));
+
+        final String[] lines = content.getDisplayLines();
+        for (final String line : lines) {
+            y += Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getLineHeight();
+            canvas.drawText(line, x, y, MAX_TEXT_WIDTH, black, Toolkit.getText(ColorsAndFonts.TEXT_NORMAL));
+        }
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        final int height = Math.min(HEIGHT, availableSpace.getHeight());
+        final int width = Math.min(WIDTH, availableSpace.getWidth());
+        return new Size(width, height);
+    }
+
+    /**
+     * Removes the help view when clicked on.
+     */
+    @Override
+    public void firstClick(final Click click) {
+        getViewManager().clearOverlayView(this);
+    }
+
+    @Override
+    public int getMaxFieldWidth() {
+        return WIDTH - 20;
+    }
+
+    @Override
+    public Text getText() {
+        return Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpViewer.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpViewer.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpViewer.java
new file mode 100644
index 0000000..05f378d
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/HelpViewer.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.help;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+
+/**
+ * A HelpSystem is used to launch the help system and bring up contextual help.
+ */
+public interface HelpViewer {
+
+    void open(Location location, String name, String description, String help);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/InternalHelpViewer.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/InternalHelpViewer.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/InternalHelpViewer.java
new file mode 100644
index 0000000..d5cf93c
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/help/InternalHelpViewer.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.help;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Viewer;
+
+public class InternalHelpViewer implements HelpViewer {
+    private final Viewer viewer;
+
+    public InternalHelpViewer(final Viewer viewer) {
+        this.viewer = viewer;
+    }
+
+    @Override
+    public void open(final Location location, final String name, final String description, final String help) {
+        viewer.clearAction();
+
+        final View helpView = new HelpView(name, description, help);
+        location.add(20, 20);
+        helpView.setLocation(location);
+
+        viewer.setOverlayView(helpView);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramAxis.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramAxis.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramAxis.java
new file mode 100644
index 0000000..48339ea
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramAxis.java
@@ -0,0 +1,68 @@
+/*
+ *  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.histogram;
+
+import java.util.List;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+
+class HistogramAxis implements ViewAxis {
+    private final ObjectAssociation fields[];
+    private final double maxValues[];
+    private final int noBars;
+
+    public HistogramAxis(final Content content) {
+        final List<? extends ObjectAssociation> associationList = HistogramSpecification.availableFields((CollectionContent) content);
+        noBars = associationList.size();
+        fields = new ObjectAssociation[noBars];
+        maxValues = new double[noBars];
+        int i = 0;
+        for (final ObjectAssociation association : associationList) {
+            fields[i++] = association;
+        }
+    }
+
+    public double getLengthFor(final Content content, final int fieldNo) {
+        return NumberAdapters.doubleValue(fields[fieldNo], fields[fieldNo].get(content.getAdapter())) / maxValues[fieldNo];
+    }
+
+    public void determineMaximum(final Content content) {
+        int i = 0;
+        for (final ObjectAssociation field : fields) {
+            maxValues[i] = 0;
+            final CollectionFacet collectionFacet = content.getAdapter().getSpecification().getFacet(CollectionFacet.class);
+            for (final ObjectAdapter element : collectionFacet.iterable(content.getAdapter())) {
+                final ObjectAdapter value = field.get(element);
+                final double doubleValue = NumberAdapters.doubleValue(field, value);
+                maxValues[i] = Math.max(maxValues[i], doubleValue);
+            }
+            i++;
+        }
+    }
+
+    public int getNoBars() {
+        return noBars;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramBar.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramBar.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramBar.java
new file mode 100644
index 0000000..7d64617
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramBar.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.histogram;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.ObjectView;
+
+class HistogramBar extends ObjectView {
+    private static final int colors[] = new int[] { 0xccccff, 0x99ff99, 0xffccff };
+    private final HistogramAxis histogramAxis;
+
+    protected HistogramBar(final Content content, final HistogramAxis histogramAxis, final ViewSpecification specification) {
+        super(content, specification);
+        this.histogramAxis = histogramAxis;
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        super.draw(canvas);
+        int y = 0;
+        final int height = (getSize().getHeight() - 5) / histogramAxis.getNoBars();
+        final Text text = Toolkit.getText(ColorsAndFonts.TEXT_LABEL);
+        final Color color = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1);
+        canvas.drawText(getContent().title(), 0, height / 2 + text.getAscent() / 2, color, text);
+
+        for (int i = 0; i < histogramAxis.getNoBars(); i++) {
+            final double length = (getSize().getWidth() - 160) * histogramAxis.getLengthFor(getContent(), i);
+            canvas.drawSolidRectangle(160, y, (int) length, height, Toolkit.getColor(colors[i % colors.length]));
+            canvas.drawRectangle(160, y, (int) length, height, Toolkit.getColor(ColorsAndFonts.COLOR_BLACK));
+            y += height + 2;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramLayout.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramLayout.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramLayout.java
new file mode 100644
index 0000000..91fba77
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramLayout.java
@@ -0,0 +1,56 @@
+/*
+ *  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.histogram;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+
+public class HistogramLayout implements Layout {
+    private final int width = 500;
+    private final int barHeight = 24;
+
+    @Override
+    public void layout(final View view, final Size maximumSize) {
+        final HistogramAxis axis = view.getViewAxes().getAxis(HistogramAxis.class);
+        axis.determineMaximum(view.getContent());
+        final int noBars = axis.getNoBars();
+        final int height = barHeight * noBars;
+        final View[] subviews = view.getSubviews();
+        int y = ViewConstants.VPADDING;
+        for (final View bar : subviews) {
+            bar.setSize(new Size(width, height));
+            bar.setLocation(new Location(ViewConstants.HPADDING, y));
+            y += height;
+        }
+    }
+
+    @Override
+    public Size getRequiredSize(final View view) {
+        final HistogramAxis axis = view.getViewAxes().getAxis(HistogramAxis.class);
+        final int noBars = axis.getNoBars();
+        final View[] subviews = view.getSubviews();
+        final int graphHeight = subviews.length * barHeight * noBars + ViewConstants.VPADDING * 2;
+        return new Size(width + ViewConstants.HPADDING * 2, graphHeight);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramSpecification.java
new file mode 100644
index 0000000..c39c4bc
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/HistogramSpecification.java
@@ -0,0 +1,99 @@
+/*
+ *  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.histogram;
+
+import java.util.List;
+
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+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.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.composite.CollectionElementBuilder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+
+public class HistogramSpecification extends CompositeViewSpecification {
+
+    static List<? extends ObjectAssociation> availableFields(final CollectionContent content) {
+        List<? extends ObjectAssociation> associationList;
+        associationList = content.getElementSpecification().getAssociations(new Filter<ObjectAssociation>() {
+            @Override
+            public boolean accept(final ObjectAssociation t) {
+                return NumberAdapters.contains(t);
+            }
+        });
+        return associationList;
+    }
+
+    public HistogramSpecification() {
+        builder = new CollectionElementBuilder(new ViewFactory() {
+            @Override
+            public View createView(final Content content, final Axes axes, final int sequence) {
+                return new HistogramBar(content, axes.getAxis(HistogramAxis.class), HistogramSpecification.this);
+            }
+        });
+    }
+
+    @Override
+    public Layout createLayout(final Content content, final Axes axes) {
+        return new HistogramLayout();
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isCollection() && requirement.isOpen() && availableFields((CollectionContent) requirement.getContent()).size() > 0;
+    }
+
+    @Override
+    public void createAxes(final Content content, final Axes axes) {
+        super.createAxes(content, axes);
+        axes.add(new HistogramAxis(content));
+    }
+
+    @Override
+    public String getName() {
+        return "Histogram (experimental)";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return true;
+    }
+
+    @Override
+    public boolean isSubView() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/NumberAdapters.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/NumberAdapters.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/NumberAdapters.java
new file mode 100644
index 0000000..26ec31b
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/histogram/NumberAdapters.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.histogram;
+
+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.progmodel.facets.value.floats.FloatingPointValueFacet;
+import org.apache.isis.core.progmodel.facets.value.integer.IntegerValueFacet;
+import org.apache.isis.core.progmodel.facets.value.longs.DoubleFloatingPointValueFacet;
+import org.apache.isis.core.progmodel.facets.value.money.MoneyValueFacet;
+
+public class NumberAdapters {
+    static interface Converter {
+        double value(ObjectAdapter value);
+    }
+
+    static {
+        new Converter() {
+            @Override
+            public double value(final ObjectAdapter arg0) {
+                return 0;
+            }
+        };
+
+    }
+
+    public static boolean contains(final ObjectAssociation t) {
+        return t.getSpecification().containsFacet(IntegerValueFacet.class) || t.getSpecification().containsFacet(DoubleFloatingPointValueFacet.class) || t.getSpecification().containsFacet(FloatingPointValueFacet.class) || t.getSpecification().containsFacet(MoneyValueFacet.class);
+    }
+
+    public static double doubleValue(final ObjectAssociation field, final ObjectAdapter value) {
+        final ObjectSpecification specification = value.getSpecification();
+
+        final IntegerValueFacet intValueFacet = specification.getFacet(IntegerValueFacet.class);
+        if (intValueFacet != null) {
+            return intValueFacet.integerValue(value).doubleValue();
+        }
+
+        final DoubleFloatingPointValueFacet doubleValueFacet = specification.getFacet(DoubleFloatingPointValueFacet.class);
+        if (doubleValueFacet != null) {
+            return doubleValueFacet.doubleValue(value).doubleValue();
+        }
+
+        final FloatingPointValueFacet floatValueFacet = specification.getFacet(FloatingPointValueFacet.class);
+        if (floatValueFacet != null) {
+            return floatValueFacet.floatValue(value).doubleValue();
+        }
+
+        final MoneyValueFacet moneyValueFacet = specification.getFacet(MoneyValueFacet.class);
+        if (moneyValueFacet != null) {
+            return moneyValueFacet.getAmount(value);
+        }
+
+        return 0.0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/Icon.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/Icon.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/Icon.java
new file mode 100644
index 0000000..4d5c137
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/Icon.java
@@ -0,0 +1,165 @@
+/*
+ *  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.icon;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.ImageFactory;
+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.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.IconGraphic;
+import org.apache.isis.viewer.dnd.view.base.ObjectView;
+import org.apache.isis.viewer.dnd.view.text.ObjectTitleText;
+import org.apache.isis.viewer.dnd.view.text.TitleText;
+
+public class Icon extends ObjectView {
+    private IconGraphic icon;
+    private boolean isVertical;
+    private IconGraphic selectedGraphic;
+    private TitleText title;
+    private IconGraphic unselectedGraphic;
+
+    public Icon(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        super.draw(canvas);
+
+        ensureHasIcon();
+
+        int x = 0;
+        int y = 0;
+        icon.draw(canvas, x, getBaseline());
+        if (isVertical) {
+            final int w = title.getSize().getWidth();
+            x = (w > icon.getSize().getWidth()) ? x : getSize().getWidth() / 2 - w / 2;
+            y = icon.getSize().getHeight() + Toolkit.getText(ColorsAndFonts.TEXT_ICON).getAscent() + ViewConstants.VPADDING;
+        } else {
+            x += icon.getSize().getWidth();
+            x += ViewConstants.HPADDING;
+            y = icon.getBaseline();
+        }
+        final int maxWidth = getSize().getWidth() - x;
+        title.draw(canvas, x, y, maxWidth);
+
+        if (getState().isActive()) {
+            final Image busyImage = ImageFactory.getInstance().loadIcon("busy", 16, null);
+            canvas.drawImage(busyImage, icon.getSize().getWidth() - 16 - 4, 4);
+        }
+
+    }
+
+    private void ensureHasIcon() {
+        if (icon == null) {
+            // icon = selectedGraphic;
+        }
+    }
+
+    @Override
+    public void entered() {
+        icon = selectedGraphic;
+        markDamaged();
+        super.entered();
+    }
+
+    @Override
+    public void exited() {
+        icon = unselectedGraphic;
+        markDamaged();
+        super.exited();
+    }
+
+    @Override
+    public int getBaseline() {
+        ensureHasIcon();
+        return icon.getBaseline();
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        if (icon == null) {
+            // icon = unselectedGraphic;
+        }
+
+        final Size size = icon.getSize();
+        final Size textSize = title.getSize();
+        if (isVertical) {
+            size.extendHeight(ViewConstants.VPADDING + textSize.getHeight() + ViewConstants.VPADDING);
+            size.ensureWidth(textSize.getWidth());
+        } else {
+            size.extendWidth(ViewConstants.HPADDING);
+            size.extendWidth(textSize.getWidth());
+        }
+        return size;
+    }
+
+    /**
+     * Set up the graphic to be used when displaying the icon and the icon is
+     * selected.
+     */
+    public void setSelectedGraphic(final IconGraphic selectedGraphic) {
+        this.selectedGraphic = selectedGraphic;
+        if (unselectedGraphic == null) {
+            unselectedGraphic = selectedGraphic;
+            icon = selectedGraphic;
+        }
+    }
+
+    /**
+     * Set up the title to be used when displaying the icon.
+     */
+    public void setTitle(final ObjectTitleText text) {
+        title = text;
+    }
+
+    /**
+     * Set up the graphic to be used when displaying the icon and the icon is
+     * unselected. If this returns null the graphic will not be changed when the
+     * icon becomes unselected.
+     */
+    public void setUnselectedGraphic(final IconGraphic unselectedGraphic) {
+        this.unselectedGraphic = unselectedGraphic;
+        icon = unselectedGraphic;
+    }
+
+    /**
+     * Specifies if the graphic should be aligned vertical above the label;
+     * otherwise aligned horizontally.
+     */
+    public void setVertical(final boolean isVertical) {
+        this.isVertical = isVertical;
+    }
+
+    @Override
+    public void update(final ObjectAdapter object) {
+        final View p = getParent();
+        if (p != null) {
+            p.invalidateLayout();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconElementFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconElementFactory.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconElementFactory.java
new file mode 100644
index 0000000..4f16f27
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconElementFactory.java
@@ -0,0 +1,60 @@
+/*
+ *  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.icon;
+
+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.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.BlankView;
+
+public class IconElementFactory implements ViewFactory {
+    private final ViewSpecification objectSpec;
+    private final ViewSpecification collectionSpec;
+    private final boolean createViewsForEmptyContent;
+
+    public IconElementFactory() {
+        this(null, null, false);
+    }
+
+    public IconElementFactory(final ViewSpecification objectSpec, final ViewSpecification collectionSpec, final boolean createViewsForEmptyContent) {
+        this.objectSpec = this.objectSpec == null ? new SubviewIconSpecification() : objectSpec;
+        this.collectionSpec = this.collectionSpec == null ? new SubviewIconSpecification() : collectionSpec;
+        this.createViewsForEmptyContent = createViewsForEmptyContent;
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        if (content.isObject()) {
+            if (content.getAdapter() == null) {
+                return createViewsForEmptyContent ? new BlankView(content) : null;
+            } else {
+                return objectSpec.createView(content, axes, -1);
+            }
+        } else if (content.isCollection()) {
+            return collectionSpec.createView(content, axes, -1);
+        } else {
+            // TODO decide what to do with values: use factory, use another
+            // SubviewSpec, or ignore always
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconSpecification.java
new file mode 100644
index 0000000..9aefbc2
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/IconSpecification.java
@@ -0,0 +1,93 @@
+/*
+ *  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.icon;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+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.IconGraphic;
+import org.apache.isis.viewer.dnd.view.text.ObjectTitleText;
+
+public class IconSpecification implements ViewSpecification {
+    private final boolean isSubView;
+    private final boolean isReplaceable;
+
+    public IconSpecification() {
+        this(true, true);
+    }
+
+    IconSpecification(final boolean isSubView, final boolean isReplaceable) {
+        this.isSubView = isSubView;
+        this.isReplaceable = isReplaceable;
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isClosed() && requirement.isObject() && requirement.hasReference();
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final Text style = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+        final Icon icon = new Icon(content, this);
+        icon.setTitle(new ObjectTitleText(icon, style));
+        icon.setSelectedGraphic(new IconGraphic(icon, style));
+        return icon;
+    }
+
+    @Override
+    public String getName() {
+        return "Icon";
+    }
+
+    @Override
+    public boolean isSubView() {
+        return isSubView;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return isReplaceable;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return false;
+    }
+
+    public View decorateSubview(final View subview) {
+        return subview;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return false;
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/LargeIconSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/LargeIconSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/LargeIconSpecification.java
new file mode 100644
index 0000000..6fdb2ba
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/LargeIconSpecification.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.icon;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+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.IconGraphic;
+import org.apache.isis.viewer.dnd.view.border.ObjectBorder;
+import org.apache.isis.viewer.dnd.view.text.ObjectTitleText;
+
+public class LargeIconSpecification implements ViewSpecification {
+    private static final int DEFAULT_SIZE = 64;
+    private final int size;
+
+    public LargeIconSpecification() {
+        this(DEFAULT_SIZE);
+    }
+
+    LargeIconSpecification(final int size) {
+        this.size = size;
+    }
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isClosed() && requirement.isObject() && requirement.hasReference() && requirement.isSubview();
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final Text style = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+        final Icon icon = new Icon(content, this);
+        icon.setTitle(new ObjectTitleText(icon, style));
+        icon.setSelectedGraphic(new IconGraphic(icon, size));
+        icon.setVertical(true);
+        return new ObjectBorder(icon);
+    }
+
+    @Override
+    public String getName() {
+        return "Image";
+    }
+
+    @Override
+    public boolean isSubView() {
+        return true;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return false;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return false;
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/RootIconSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/RootIconSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/RootIconSpecification.java
new file mode 100644
index 0000000..eeba48a
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/RootIconSpecification.java
@@ -0,0 +1,80 @@
+/*
+ *  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.icon;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Placement;
+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.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractViewDecorator;
+import org.apache.isis.viewer.dnd.view.border.ObjectBorder;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+class IconOpenAction extends AbstractViewDecorator {
+    protected IconOpenAction(final View wrappedView) {
+        super(wrappedView);
+    }
+
+    @Override
+    public void viewMenuOptions(final UserActionSet menuOptions) {
+        super.viewMenuOptions(menuOptions);
+        menuOptions.add(new UserActionAbstract("Close") {
+            @Override
+            public void execute(final Workspace workspace, final View view, final Location at) {
+                getView().dispose();
+                // getWorkspace().removeObject((ObjectAdapter)
+                // view.getContent().getAdapter());
+            }
+        });
+    }
+
+    private void openIcon() {
+        getWorkspace().addWindowFor(getContent().getAdapter(), new Placement(getLocation()));
+    }
+
+    @Override
+    public void secondClick(final Click click) {
+        openIcon();
+    }
+}
+
+public class RootIconSpecification extends IconSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return super.canDisplay(requirement) && requirement.is(ViewRequirement.ROOT);
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final View icon = super.createView(content, axes, sequence);
+        return new ObjectBorder(new IconOpenAction(icon));
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/SubviewIconSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/SubviewIconSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/SubviewIconSpecification.java
new file mode 100644
index 0000000..6d0d6d0
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/icon/SubviewIconSpecification.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.icon;
+
+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.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.border.ObjectBorder;
+import org.apache.isis.viewer.dnd.view.field.OneToOneField;
+import org.apache.isis.viewer.dnd.view.lookup.OpenObjectDropDownBorder;
+
+public class SubviewIconSpecification extends IconSpecification {
+    private static final ViewSpecification spec = new IconSpecification();
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return super.canDisplay(requirement) && requirement.is(ViewRequirement.CLOSED) && requirement.is(ViewRequirement.SUBVIEW);
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final View view = super.createView(content, axes, sequence);
+        /*
+         * boolean isEditable = content instanceof OneToOneField &&
+         * ((OneToOneField) content).isEditable().isAllowed(); boolean
+         * hasOptions = content.isOptionEnabled(); if (isEditable && hasOptions)
+         * { return new OpenObjectDropDownBorder(view, spec); } return view;
+         */
+
+        if (content instanceof OneToOneField && ((OneToOneField) content).isEditable().isVetoed()) {
+            return new ObjectBorder(view);
+        } else {
+            if (content.isOptionEnabled()) {
+                return new ObjectBorder(new OpenObjectDropDownBorder(view, spec));
+            } else {
+                return new ObjectBorder(view);
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ClickImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ClickImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ClickImpl.java
new file mode 100644
index 0000000..1c4e4ec
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ClickImpl.java
@@ -0,0 +1,84 @@
+/*
+ *  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.interaction;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Offset;
+import org.apache.isis.viewer.dnd.view.Click;
+
+/**
+ * Describes a mouse click event.
+ */
+public class ClickImpl extends PointerEvent implements Click {
+    private final Location location;
+    private final Location locationWithinViewer;
+
+    /**
+     * Creates a new click event object.
+     * 
+     * @param mouseLocation
+     *            the location of the mouse relative to the viewer
+     * @param modifiers
+     *            the button and key held down during the click (@see
+     *            java.awt.event.MouseEvent)
+     */
+    public ClickImpl(final Location mouseLocation, final int modifiers) {
+        super(modifiers);
+
+        this.location = new Location(mouseLocation);
+        this.locationWithinViewer = new Location(mouseLocation);
+    }
+
+    @Override
+    public Location getLocation() {
+        return location;
+    }
+
+    @Override
+    public Location getLocationWithinViewer() {
+        return locationWithinViewer;
+    }
+
+    /**
+     * Translate the location of this event by the specified offset.
+     */
+    @Override
+    public void subtract(final int x, final int y) {
+        location.subtract(x, y);
+    }
+
+    @Override
+    public String toString() {
+        return "Click [location=" + location + "," + super.toString() + "]";
+    }
+
+    public void add(final Offset offset) {
+        location.add(offset.getDeltaX(), offset.getDeltaY());
+    }
+
+    public void subtract(final Offset offset) {
+        subtract(offset.getDeltaX(), offset.getDeltaY());
+    }
+
+    @Override
+    public void subtract(final Location location) {
+        subtract(location.getX(), location.getY());
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ContentDragImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ContentDragImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ContentDragImpl.java
new file mode 100644
index 0000000..cb5ddb7
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ContentDragImpl.java
@@ -0,0 +1,165 @@
+/*
+ *  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.interaction;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ContentDrag;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Viewer;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class ContentDragImpl extends DragImpl implements ContentDrag {
+    private final View dragView;
+    private Location location;
+    private View previousTarget;
+    private final Content sourceContent;
+    private View target;
+    private final Workspace workspace;
+    private final Location offset;
+    private final View source;
+
+    /**
+     * Creates a new drag event. The source view has its pickup(), and then,
+     * exited() methods called on it. The view returned by the pickup method
+     * becomes this event overlay view, which is moved continuously so that it
+     * tracks the pointer,
+     * 
+     * @param source
+     *            the view over which the pointer was when this event started
+     */
+    public ContentDragImpl(final View source, final Location offset, final View dragView) {
+        if (dragView == null) {
+            throw new NullPointerException();
+        }
+        workspace = source.getWorkspace();
+        sourceContent = source.getContent();
+        this.dragView = dragView;
+        this.offset = offset;
+        this.source = source.getView();
+    }
+
+    /**
+     * Cancels drag by calling dragOut() on the current target, and changes the
+     * cursor back to the default.
+     */
+    @Override
+    public void cancel(final Viewer viewer) {
+        if (target != null) {
+            target.dragOut(this);
+        }
+        viewer.clearAction();
+    }
+
+    @Override
+    public void drag(final View target, final Location location, final int mods) {
+        this.location = location;
+        this.target = target;
+        this.mods = mods;
+
+        moveDragView();
+        crossBoundary(target);
+        target.drag(this);
+    }
+
+    private void crossBoundary(final View target) {
+        if (target != previousTarget) {
+            if (previousTarget != null) {
+                previousTarget.dragOut(this);
+                previousTarget = null;
+            }
+
+            target.dragIn(this);
+            previousTarget = target;
+        }
+    }
+
+    private void moveDragView() {
+        if (dragView != null) {
+            dragView.markDamaged();
+            final Location newLocation = new Location(this.location);
+            newLocation.subtract(offset);
+            dragView.setLocation(newLocation);
+            dragView.limitBoundsWithin(workspace.getSize());
+            dragView.markDamaged();
+        }
+    }
+
+    /**
+     * Ends the drag by calling drop() on the current target, and changes the
+     * cursor back to the default.
+     */
+    @Override
+    public void end(final Viewer viewer) {
+        viewer.getSpy().addAction("drop on " + target);
+        target.drop(this);
+        viewer.clearAction();
+    }
+
+    @Override
+    public View getOverlay() {
+        return dragView;
+    }
+
+    @Override
+    public View getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the Content object from the source view.
+     */
+    @Override
+    public Content getSourceContent() {
+        return sourceContent;
+    }
+
+    @Override
+    public Location getTargetLocation() {
+        final Location location = new Location(this.location);
+        location.subtract(target.getAbsoluteLocation());
+        // location.add(-getOffset().getX(), -getOffset().getY());
+        // location.add(-getOffset().getX(), -getOffset().getY());
+
+        return location;
+    }
+
+    @Override
+    public Location getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns the current target view.
+     */
+    @Override
+    public View getTargetView() {
+        return target;
+    }
+
+    @Override
+    public String toString() {
+        return "ContentDrag [" + super.toString() + "]";
+    }
+
+    @Override
+    public void subtract(final int left, final int top) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragImpl.java
new file mode 100644
index 0000000..55a1f89
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragImpl.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.DragEvent;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Viewer;
+
+public abstract class DragImpl extends PointerEvent implements DragEvent {
+    protected DragImpl() {
+        super(0);
+    }
+
+    /**
+     * Indicates the drag has been cancelled; no action should be taken.
+     */
+    @Override
+    public abstract void cancel(final Viewer viewer);
+
+    /**
+     * Indicates that the drag state has changed.
+     */
+    @Override
+    public abstract void drag(final View target, final Location location, final int mods);
+
+    /**
+     * Indicates the drag has properly ended (the mouse button has been
+     * released)
+     * 
+     */
+    @Override
+    public abstract void end(final Viewer viewer);
+
+    @Override
+    public abstract View getOverlay();
+}