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

[44/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/drawing/Shape.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Shape.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Shape.java
new file mode 100644
index 0000000..bf2196d
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Shape.java
@@ -0,0 +1,102 @@
+/*
+ *  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.drawing;
+
+public class Shape {
+    int count = 0;
+    int[] x = new int[6];
+    int[] y = new int[6];
+
+    public Shape() {
+    }
+
+    public Shape(final int xOrigin, final int yOrigin) {
+        this.x[0] = xOrigin;
+        this.y[0] = yOrigin;
+        count = 1;
+    }
+
+    public Shape(final Shape shape) {
+        count = shape.count;
+        this.x = new int[count];
+        this.y = new int[count];
+        for (int i = 0; i < count; i++) {
+            this.x[i] = shape.x[i];
+            this.y[i] = shape.y[i];
+        }
+    }
+
+    public void addVector(final int width, final int height) {
+        final int x = this.x[count - 1] + width;
+        final int y = this.y[count - 1] + height;
+        addPoint(x, y);
+    }
+
+    public void addPoint(final int x, final int y) {
+        if (this.x.length == count) {
+            final int[] newX = new int[count * 2];
+            final int[] newY = new int[count * 2];
+            System.arraycopy(this.x, 0, newX, 0, count);
+            System.arraycopy(this.y, 0, newY, 0, count);
+            this.x = newX;
+            this.y = newY;
+        }
+        this.x[count] = x;
+        this.y[count] = y;
+        count++;
+    }
+
+    public int count() {
+        return count;
+    }
+
+    public int[] getX() {
+        final int[] xx = new int[count];
+        System.arraycopy(x, 0, xx, 0, count);
+        return xx;
+    }
+
+    public int[] getY() {
+        final int[] yy = new int[count];
+        System.arraycopy(y, 0, yy, 0, count);
+        return yy;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer points = new StringBuffer();
+        for (int i = 0; i < count; i++) {
+            if (i > 0) {
+                points.append("; ");
+            }
+            points.append(this.x[i]);
+            points.append(",");
+            points.append(this.y[i]);
+        }
+        return "Shape {" + points + "}";
+    }
+
+    public void translate(final int x, final int y) {
+        for (int i = 0; i < count; i++) {
+            this.x[i] += x;
+            this.y[i] += y;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Size.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Size.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Size.java
new file mode 100644
index 0000000..f5dca68
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Size.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.drawing;
+
+public class Size {
+    public static final Size createMax() {
+        return new Size(10000, 10000);
+    }
+
+    int height;
+    int width;
+
+    public Size() {
+        width = 0;
+        height = 0;
+    }
+
+    public Size(final int width, final int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    public Size(final Size size) {
+        width = size.width;
+        height = size.height;
+    }
+
+    public void contract(final int width, final int height) {
+        this.width -= width;
+        this.height -= height;
+    }
+
+    public void contract(final Size size) {
+        this.width -= size.width;
+        this.height -= size.height;
+    }
+
+    public void contractHeight(final int height) {
+        this.height -= height;
+    }
+
+    public void contract(final Padding padding) {
+        height -= padding.top + padding.bottom;
+        width -= padding.left + padding.right;
+    }
+
+    public void contractWidth(final int width) {
+        this.width -= width;
+    }
+
+    public void ensureHeight(final int height) {
+        this.height = Math.max(this.height, height);
+    }
+
+    public void ensureWidth(final int width) {
+        this.width = Math.max(this.width, width);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Size) {
+            final Size object = (Size) obj;
+
+            return object.width == this.width && object.height == this.height;
+        }
+
+        return false;
+    }
+
+    public void extend(final int width, final int height) {
+        this.width += width;
+        this.height += height;
+    }
+
+    public void extend(final Padding padding) {
+        this.width += padding.getLeftRight();
+        this.height += padding.getTopBottom();
+    }
+
+    public void extend(final Size size) {
+        this.width += size.width;
+        this.height += size.height;
+    }
+
+    public void extendHeight(final int height) {
+        this.height += height;
+    }
+
+    public void extendWidth(final int width) {
+        this.width += width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Limits the height of this Size so that if its height is greater than the
+     * specified maximum then the height is reduced to the maximum. If the
+     * height is less than maximum (or equal to it) then nothing is done.
+     */
+    public void limitHeight(final int maximum) {
+        height = Math.min(height, maximum);
+    }
+
+    /**
+     * Limits the width of this Size so that if its width is greater than the
+     * specified maximum then the width is reduced to the maximum. If the width
+     * is less than maximum (or equal to it) then nothing is done.
+     */
+    public void limitWidth(final int maximum) {
+        width = Math.min(width, maximum);
+    }
+
+    /**
+     * Limits the width and height of this Size so it is no larger than the
+     * specified maximum size.
+     * 
+     * @see #limitWidth(int)
+     * @see #limitHeight(int)
+     */
+    public void limitSize(final Size maximum) {
+        limitWidth(maximum.width);
+        limitHeight(maximum.height);
+    }
+
+    public void setHeight(final int height) {
+        this.height = height;
+    }
+
+    public void setWidth(final int width) {
+        this.width = width;
+    }
+
+    @Override
+    public String toString() {
+        return width + "x" + height;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Text.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Text.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Text.java
new file mode 100644
index 0000000..68739e7
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/drawing/Text.java
@@ -0,0 +1,85 @@
+/*
+ *  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.drawing;
+
+public interface Text {
+
+    /**
+     * Returns the width, in pixels, of the specified character.
+     */
+    int charWidth(char c);
+
+    /**
+     * Returns the height, in pixels, of the distance from the baseline to top
+     * of the tallest character (including accents that are not common in
+     * english.
+     */
+    int getAscent();
+
+    /**
+     * Returns the height, in pixels, of the distance from bottom of the lowest
+     * descending character to the baseline.
+     */
+    int getDescent();
+
+    /**
+     * Returns the mid point, in pixels, between the baseline and the top of the
+     * characters.
+     */
+    int getMidPoint();
+
+    /**
+     * Return the name of this text style.
+     */
+    String getName();
+
+    /**
+     * Returns the height, in pixels, for a normal line of text - where there is
+     * some space between two lines of text.
+     */
+    int getTextHeight();
+
+    /**
+     * Returns the sum of the text height and line spacing.
+     * 
+     * @see #getLineHeight()
+     * @see #getLineSpacing()
+     */
+    int getLineHeight();
+
+    /**
+     * Returns the number of blank vertical pixels to add between adjacent lines
+     * to give them additional spacing.
+     */
+    int getLineSpacing();
+
+    /**
+     * Returns the width of the specified in pixels.
+     */
+    int stringWidth(String text);
+
+    /**
+     * Returns the height in pixels when the specified text is wrapped at the
+     * specified width
+     */
+    int stringHeight(String text, int maxWidth);
+
+    int stringWidth(String message, int maxWidth);
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractField.java
new file mode 100644
index 0000000..9980f16
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractField.java
@@ -0,0 +1,262 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.commons.exceptions.NotYetImplementedException;
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+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.Location;
+import org.apache.isis.viewer.dnd.drawing.Padding;
+import org.apache.isis.viewer.dnd.view.BackgroundTask;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.InternalDrag;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAreaType;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.action.BackgroundWork;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+
+public abstract class AbstractField extends AbstractView {
+    protected static final int TEXT_WIDTH = 20;
+    private boolean identified;
+
+    protected AbstractField(final Content content, final ViewSpecification design) {
+        super(content, design);
+    }
+
+    @Override
+    public boolean canFocus() {
+        return canChangeValue().isAllowed();
+    }
+
+    protected boolean provideClearCopyPaste() {
+        return false;
+    }
+
+    protected Consent canClear() {
+        return Allow.DEFAULT;
+    }
+
+    protected void clear() {
+    }
+
+    protected void copyToClipboard() {
+    }
+
+    protected void pasteFromClipboard() {
+    }
+
+    /**
+     * Indicates the drag started within this view's bounds is continuing. By
+     * default does nothing.
+     */
+    @Override
+    public void drag(final InternalDrag drag) {
+    }
+
+    /**
+     * Default implementation - does nothing
+     */
+    @Override
+    public void dragCancel(final InternalDrag drag) {
+    }
+
+    /**
+     * Indicates the start of a drag within this view's bounds. By default does
+     * nothing.
+     */
+    @Override
+    public View dragFrom(final Location location) {
+        return null;
+    }
+
+    /**
+     * Indicates the drag started within this view's bounds has been finished
+     * (although the location may now be outside of its bounds). By default does
+     * nothing.
+     */
+    @Override
+    public void dragTo(final InternalDrag drag) {
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        if (getState().isActive()) {
+            clearBackground(canvas, Toolkit.getColor(ColorsAndFonts.COLOR_IDENTIFIED));
+        }
+
+        if (getState().isOutOfSynch()) {
+            clearBackground(canvas, Toolkit.getColor(ColorsAndFonts.COLOR_OUT_OF_SYNC));
+        }
+
+        if (getState().isInvalid()) {
+            final Image image = ImageFactory.getInstance().loadIcon("invalid-entry", 12, null);
+            if (image != null) {
+                canvas.drawImage(image, getSize().getWidth() - 16, 2);
+            }
+
+            // canvas.clearBackground(this,
+            // Toolkit.getColor(ColorsAndFonts.COLOR_INVALID));
+        }
+
+        super.draw(canvas);
+    }
+
+    @Override
+    public void entered() {
+        super.entered();
+        identified = true;
+        final Consent changable = canChangeValue();
+        if (changable.isVetoed()) {
+            getFeedbackManager().setViewDetail(changable.getReason());
+        }
+        markDamaged();
+    }
+
+    @Override
+    public void exited() {
+        super.exited();
+        identified = false;
+        markDamaged();
+    }
+
+    public boolean getIdentified() {
+        return identified;
+    }
+
+    @Override
+    public Padding getPadding() {
+        return new Padding(0, 0, 0, 0);
+    }
+
+    public View getRoot() {
+        throw new NotYetImplementedException();
+    }
+
+    String getSelectedText() {
+        return "";
+    }
+
+    @Override
+    public boolean hasFocus() {
+        return getViewManager().hasFocus(getView());
+    }
+
+    public boolean isEmpty() {
+        return false;
+    }
+
+    public boolean indicatesForView(final Location mouseLocation) {
+        return false;
+    }
+
+    /**
+     * Called when the user presses any key on the keyboard while this view has
+     * the focus.
+     */
+    @Override
+    public void keyPressed(final KeyboardAction key) {
+    }
+
+    /**
+     * Called when the user releases any key on the keyboard while this view has
+     * the focus.
+     */
+    @Override
+    public void keyReleased(final KeyboardAction action) {
+    }
+
+    /**
+     * Called when the user presses a non-control key (i.e. data entry keys and
+     * not shift, up-arrow etc). Such a key press will result in a prior call to
+     * <code>keyPressed</code> and a subsequent call to <code>keyReleased</code>
+     * .
+     */
+    @Override
+    public void keyTyped(final KeyboardAction action) {
+    }
+
+    @Override
+    public void contentMenuOptions(final UserActionSet options) {
+        if (provideClearCopyPaste()) {
+            options.add(new CopyValueOption(this));
+            options.add(new PasteValueOption(this));
+            options.add(new ClearValueOption(this));
+        }
+
+        super.contentMenuOptions((options));
+        options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_VALUE));
+    }
+
+    protected final void initiateSave(final boolean moveToNextField) {
+        BackgroundWork.runTaskInBackground(this, new BackgroundTask() {
+            @Override
+            public void execute() {
+                save();
+                getParent().updateView();
+                invalidateLayout();
+                if (moveToNextField) {
+                    getFocusManager().focusNextView();
+                }
+            }
+
+            @Override
+            public String getName() {
+                return "Save field";
+            }
+
+            @Override
+            public String getDescription() {
+                return "Saving " + getContent().windowTitle();
+            }
+
+        });
+    }
+
+    protected abstract void save();
+
+    @Override
+    public String toString() {
+        final ToString str = new ToString(this, getId());
+        str.append("location", getLocation());
+        final ObjectAdapter adapter = getContent().getAdapter();
+        str.append("object", adapter == null ? "" : adapter.getObject());
+        return str.toString();
+    }
+
+    @Override
+    public ViewAreaType viewAreaType(final Location mouseLocation) {
+        return ViewAreaType.INTERNAL;
+    }
+
+    @Override
+    public int getBaseline() {
+        return Toolkit.defaultBaseline();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractValueOption.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractValueOption.java
new file mode 100644
index 0000000..03f071b
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/AbstractValueOption.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.field;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public abstract class AbstractValueOption extends UserActionAbstract {
+    protected final AbstractField field;
+
+    AbstractValueOption(final AbstractField field, final String name) {
+        super(name);
+        this.field = field;
+    }
+
+    protected ObjectAdapter getValue(final View view) {
+        final TextParseableContent vc = (TextParseableContent) view.getContent();
+        final ObjectAdapter value = vc.getAdapter();
+        return value;
+    }
+
+    protected void updateParent(final View view) {
+        // have commented this out because it isn't needed; the transaction
+        // manager will do this
+        // for us on endTransaction. Still, if I'm wrong and it is needed,
+        // hopefully this
+        // comment will help...
+        // IsisContext.getObjectPersistor().objectChangedAllDirty();
+
+        view.markDamaged();
+        view.getParent().invalidateContent();
+    }
+
+    protected boolean isEmpty(final View view) {
+        return field.isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java
new file mode 100644
index 0000000..dd44730
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java
@@ -0,0 +1,158 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.progmodel.facets.value.booleans.BooleanValueFacet;
+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.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.KeyboardAction;
+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.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.AbstractFieldSpecification;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+
+/*
+ * TODO this class does not set the underlying business object  via its boolean adapter.  Need
+ * to create an content type for flags.
+ */
+public class CheckboxField extends AbstractField {
+    private static final int size = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getTextHeight();
+
+    public static class Specification extends AbstractFieldSpecification {
+        @Override
+        public boolean canDisplay(final ViewRequirement requirement) {
+            return requirement.isTextParseable() && requirement.isForValueType(BooleanValueFacet.class);
+        }
+
+        @Override
+        public View createView(final Content content, final Axes axes, final int sequence) {
+            return new CheckboxField(content, this);
+        }
+
+        @Override
+        public String getName() {
+            return "Checkbox";
+        }
+    }
+
+    public CheckboxField(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        Color color;
+        color = getIdentified() ? Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2) : null;
+        color = hasFocus() ? Toolkit.getColor(ColorsAndFonts.COLOR_IDENTIFIED) : color;
+
+        final int top = ViewConstants.VPADDING;
+        final int left = ViewConstants.HPADDING;
+        if (color != null) {
+            canvas.drawRectangle(left - 2, top - 2, size + 4, size + 4, color);
+        }
+
+        color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1);
+        canvas.drawRectangle(left, top, size, size, color);
+        if (isSet()) {
+            final Image image = ImageFactory.getInstance().loadImage("check-mark");
+            canvas.drawImage(image, 3, 3, size, size);
+        }
+    }
+
+    @Override
+    public void firstClick(final Click click) {
+        toggle();
+    }
+
+    @Override
+    public void secondClick(final Click click) {
+        // ignore
+    }
+
+    @Override
+    public void thirdClick(final Click click) {
+        // ignore
+    }
+
+    @Override
+    public void keyTyped(final KeyboardAction action) {
+        if (action.getKeyCode() == ' ') {
+            toggle();
+        } else {
+            super.keyTyped(action);
+        }
+    }
+
+    private void toggle() {
+        if (canChangeValue().isAllowed()) {
+            initiateSave(false);
+        }
+    }
+
+    @Override
+    public Consent canChangeValue() {
+        final TextParseableContent cont = (TextParseableContent) getContent();
+        return cont.isEditable();
+    }
+
+    @Override
+    public int getBaseline() {
+        return ViewConstants.VPADDING + Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getAscent();
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        return new Size(ViewConstants.HPADDING + size + ViewConstants.HPADDING, ViewConstants.VPADDING + size + ViewConstants.VPADDING);
+    }
+
+    private boolean isSet() {
+        final BooleanValueFacet booleanValueFacet = getContent().getSpecification().getFacet(BooleanValueFacet.class);
+        return booleanValueFacet.isSet(getContent().getAdapter());
+    }
+
+    @Override
+    protected void save() {
+        final BooleanValueFacet booleanValueFacet = getContent().getSpecification().getFacet(BooleanValueFacet.class);
+        final ObjectAdapter adapter = getContent().getAdapter();
+        if (adapter == null) {
+            ((TextParseableContent) getContent()).parseTextEntry("true");
+        } else {
+            booleanValueFacet.toggle(adapter);
+        }
+
+        // return parsed != null ? PersistorUtil.createAdapter(parsed) : null;
+
+        markDamaged();
+        ((TextParseableContent) getContent()).entryComplete();
+        getParent().invalidateContent();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java
new file mode 100644
index 0000000..3daa53f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java
@@ -0,0 +1,69 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class ClearValueOption extends AbstractValueOption {
+
+    public ClearValueOption(final AbstractField field) {
+        super(field, "Clear");
+    }
+
+    @Override
+    public String getDescription(final View view) {
+        return "Clear field";
+    }
+
+    @Override
+    public Consent disabled(final View view) {
+        final ObjectAdapter value = getValue(view);
+        final Consent consent = view.canChangeValue();
+        if (consent.isVetoed()) {
+            return consent;
+        }
+        final Consent canClear = field.canClear();
+        if (canClear.isVetoed()) {
+            // TODO: move logic into Facets.
+            return new Veto(String.format("Can't clear %s values", value.getSpecification().getShortIdentifier()));
+        }
+        if (value == null || isEmpty(view)) {
+            // TODO: move logic into Facets.
+            return new Veto("Field is already empty");
+        }
+        // TODO: move logic into Facets.
+        return consent.setDescription(String.format("Clear value ", value.titleString()));
+    }
+
+    @Override
+    public void execute(final Workspace frame, final View view, final Location at) {
+        field.clear();
+    }
+
+    @Override
+    public String toString() {
+        return "ClearValueOption";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java
new file mode 100644
index 0000000..986ef0f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java
@@ -0,0 +1,144 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.commons.exceptions.NotYetImplementedException;
+import org.apache.isis.core.metamodel.facets.object.parseable.InvalidEntryException;
+import org.apache.isis.core.progmodel.facets.value.color.ColorValueFacet;
+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.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.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.AbstractFieldSpecification;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+import org.apache.isis.viewer.dnd.view.lookup.OpenDropDownBorder;
+import org.apache.isis.viewer.dnd.view.lookup.OptionContent;
+
+public class ColorField extends TextParseableFieldAbstract {
+    public static class Specification extends AbstractFieldSpecification {
+
+        @Override
+        public boolean canDisplay(final ViewRequirement requirement) {
+            return requirement.isTextParseable() && requirement.isForValueType(ColorValueFacet.class);
+        }
+
+        @Override
+        public View createView(final Content content, final Axes axes, final int sequence) {
+            final ColorField field = new ColorField(content, this);
+            return new OpenDropDownBorder(field) {
+                @Override
+                protected View createDropDownView() {
+                    return new ColorFieldOverlay(field);
+                }
+
+                @Override
+                protected void setSelection(final OptionContent selectedContent) {
+                }
+            };
+        }
+
+        @Override
+        public String getName() {
+            return "Color";
+        }
+    }
+
+    private int color;
+
+    public ColorField(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        Color color;
+
+        if (hasFocus()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1);
+        } else if (getParent().getState().isObjectIdentified()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_IDENTIFIED);
+        } else if (getParent().getState().isRootViewIdentified()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY2);
+        } else {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1);
+        }
+
+        int top = 0;
+        int left = 0;
+
+        final Size size = getSize();
+        int w = size.getWidth() - 1;
+        int h = size.getHeight() - 1;
+        canvas.drawRectangle(left, top, w, h, color);
+        left++;
+        top++;
+        w -= 1;
+        h -= 1;
+        canvas.drawSolidRectangle(left, top, w, h, Toolkit.getColor(getColor()));
+    }
+
+    /*
+     * @Override public void firstClick(final Click click) { if
+     * (((TextParseableContent) getContent()).isEditable().isAllowed()) { final
+     * View overlay = new DisposeOverlay(new ColorFieldOverlay(this), new
+     * ValueDropDownAxis((TextParseableContent) getContent(), getView())); final
+     * Location location = this.getAbsoluteLocation(); // Location location =
+     * click.getLocationWithinViewer(); // TODO offset by constant amount //
+     * location.move(10, 10); overlay.setLocation(location); //
+     * overlay.setSize(overlay.getRequiredSize(new Size())); //
+     * overlay.markDamaged(); getViewManager().setOverlayView(overlay); } }
+     */
+    @Override
+    public int getBaseline() {
+        return ViewConstants.VPADDING + Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getAscent();
+    }
+
+    int getColor() {
+        final TextParseableContent content = ((TextParseableContent) getContent());
+        final ColorValueFacet col = content.getSpecification().getFacet(ColorValueFacet.class);
+        return col.colorValue(content.getAdapter());
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        return new Size(45, 15);
+    }
+
+    @Override
+    protected void save() {
+        try {
+            parseEntry("" + color);
+        } catch (final InvalidEntryException e) {
+            throw new NotYetImplementedException();
+        }
+    }
+
+    void setColor(final int color) {
+        this.color = color;
+        initiateSave(false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java
new file mode 100644
index 0000000..ab27820
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java
@@ -0,0 +1,77 @@
+/*
+ *  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.field;
+
+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.view.Click;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+
+class ColorFieldOverlay extends AbstractView {
+    private static final int colors[] = new int[] { 0xffffff, 0x0, 0x666666, 0xcccccc, // white,
+                                                                                       // black,
+                                                                                       // dark
+            // gray, light gray
+            0x000099, 0x0066cc, 0x0033ff, 0x99ccff, // blues
+            0x990000, 0xff0033, 0xcc0066, 0xff66ff, // reds
+            0x003300, 0x00ff33, 0x669933, 0xccff66 // greens
+    };
+    private static final int COLUMNS = 4;
+    private static final int ROWS = 4;
+    private static final int ROW_HEIGHT = 18;
+    private static final int COLUMN_WIDTH = 23;
+
+    private final ColorField field;
+
+    public ColorFieldOverlay(final ColorField field) {
+        super(field.getContent());
+
+        this.field = field;
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        return new Size(COLUMNS * COLUMN_WIDTH, ROWS * ROW_HEIGHT);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        canvas.drawSolidRectangle(0, 0, COLUMNS * COLUMN_WIDTH - 1, ROWS * ROW_HEIGHT - 1, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3));
+        for (int i = 0; i < colors.length; i++) {
+            final Color color = Toolkit.getColor(colors[i]);
+            final int y = i / COLUMNS * ROW_HEIGHT;
+            final int x = i % COLUMNS * COLUMN_WIDTH;
+            canvas.drawSolidRectangle(x, y, COLUMN_WIDTH - 1, ROW_HEIGHT - 1, color);
+        }
+        canvas.drawRectangle(0, 0, COLUMNS * COLUMN_WIDTH - 1, ROWS * ROW_HEIGHT - 1, Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY2));
+    }
+
+    @Override
+    public void firstClick(final Click click) {
+        final int x = click.getLocation().getX();
+        final int y = click.getLocation().getY();
+        final int color = colors[y / ROW_HEIGHT * COLUMNS + x / COLUMN_WIDTH];
+        field.setColor(color);
+        getViewManager().clearOverlayView();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java
new file mode 100644
index 0000000..b9219af
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.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.field;
+
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class CopyValueOption extends AbstractValueOption {
+
+    public CopyValueOption(final AbstractField field) {
+        super(field, "Copy");
+    }
+
+    @Override
+    public Consent disabled(final View view) {
+        if (isEmpty(view)) {
+            // TODO: move logic into Facets
+            return new Veto("Field is empty");
+        }
+        // TODO: move logic into Facets
+        return Allow.DEFAULT;
+        // return new Allow(String.format("Copy value '%s' to clipboard",
+        // field.getSelectedText()));
+    }
+
+    @Override
+    public void execute(final Workspace frame, final View view, final Location at) {
+        field.copyToClipboard();
+    }
+
+    @Override
+    public String toString() {
+        return "CopyValueOption";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java
new file mode 100644
index 0000000..5a8cc12
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java
@@ -0,0 +1,62 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.progmodel.facets.value.date.DateValueFacet;
+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.base.AbstractFieldSpecification;
+import org.apache.isis.viewer.dnd.view.border.TextFieldResizeBorder;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+import org.apache.isis.viewer.dnd.view.lookup.OpenDropDownBorder;
+import org.apache.isis.viewer.dnd.view.lookup.OptionContent;
+
+/**
+ * Creates a single line text field with the base line drawn.
+ */
+public class DateFieldSpecification extends AbstractFieldSpecification {
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isTextParseable() && requirement.isForValueType(DateValueFacet.class);
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final SingleLineTextField textField = new SingleLineTextField((TextParseableContent) content, this, true);
+        final View field = new TextFieldResizeBorder(textField);
+        return new OpenDropDownBorder(field) {
+            @Override
+            protected View createDropDownView() {
+                return DatePickerControl.getPicker(content);
+            }
+
+            @Override
+            protected void setSelection(final OptionContent selectedContent) {
+            }
+        };
+    }
+
+    @Override
+    public String getName() {
+        return "Date Field";
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java
new file mode 100644
index 0000000..2153fb5
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.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.field;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Size;
+
+public interface DatePicker {
+
+    public abstract Size getRequiredSize(Size availableSpace);
+
+    public abstract void draw(final Canvas canvas);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java
new file mode 100644
index 0000000..99f1675
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java
@@ -0,0 +1,40 @@
+/*
+ *  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.field;
+
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Look;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.look.LookFactory;
+import org.apache.isis.viewer.dnd.view.look.linux.LinuxDatePicker;
+import org.apache.isis.viewer.dnd.view.look.linux.LinuxLook;
+
+public class DatePickerControl {
+
+    private static final Look LINUX_LOOK = new LinuxLook();
+
+    public static View getPicker(final Content content) {
+        final Look look = LookFactory.getInstalledLook();
+        if (look.getClass().isInstance(LINUX_LOOK)) {
+            return new LinuxDatePicker(content);
+        }
+        return new SimpleDatePicker(content);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java
new file mode 100644
index 0000000..1f5449a
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java
@@ -0,0 +1,208 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+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.icon.IconSpecification;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ContentDrag;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Placement;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.action.ObjectParameter;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+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.field.OneToOneField;
+import org.apache.isis.viewer.dnd.view.lookup.OpenObjectDropDownBorder;
+import org.apache.isis.viewer.dnd.view.text.TitleText;
+
+public class EmptyField extends AbstractView {
+
+    public static class Specification implements ViewSpecification {
+        @Override
+        public boolean canDisplay(final ViewRequirement requirement) {
+            return requirement.isObject() && requirement.isOpen() && !requirement.isTextParseable() && !requirement.hasReference();
+        }
+
+        @Override
+        public View createView(final Content content, final Axes axes, final int sequence) {
+            final EmptyField emptyField = new EmptyField(content, this, Toolkit.getText(ColorsAndFonts.TEXT_NORMAL));
+            if ((content instanceof OneToOneField && ((OneToOneField) content).isEditable().isAllowed()) || content instanceof ObjectParameter) {
+                if (content.isOptionEnabled()) {
+                    return new ObjectBorder(new OpenObjectDropDownBorder(emptyField, new IconSpecification()));
+                } else {
+                    return new ObjectBorder(emptyField);
+                }
+            } else {
+                return emptyField;
+            }
+        }
+
+        @Override
+        public String getName() {
+            return "empty field";
+        }
+
+        @Override
+        public boolean isAligned() {
+            return false;
+        }
+
+        @Override
+        public boolean isOpen() {
+            return false;
+        }
+
+        @Override
+        public boolean isReplaceable() {
+            return true;
+        }
+
+        @Override
+        public boolean isResizeable() {
+            return false;
+        }
+
+        @Override
+        public boolean isSubView() {
+            return true;
+        }
+    }
+
+    private final IconGraphic icon;
+    private final TitleText text;
+
+    public EmptyField(final Content content, final ViewSpecification specification, final Text style) {
+        super(content, specification);
+        if (((ObjectContent) content).getObject() != null) {
+            throw new IllegalArgumentException("Content for EmptyField must be null: " + content);
+        }
+        final ObjectAdapter object = ((ObjectContent) getContent()).getObject();
+        if (object != null) {
+            throw new IllegalArgumentException("Content for EmptyField must be null: " + object);
+        }
+        icon = new IconGraphic(this, style);
+        text = new EmptyFieldTitleText(this, style);
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        super.draw(canvas);
+        int x = 0;
+        final int y = icon.getBaseline();
+        icon.draw(canvas, x, y);
+        x += icon.getSize().getWidth();
+        x += ViewConstants.HPADDING;
+
+        text.draw(canvas, x, y);
+    }
+
+    @Override
+    public int getBaseline() {
+        return icon.getBaseline();
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        final Size size = icon.getSize();
+        size.extendWidth(ViewConstants.HPADDING);
+        size.extendWidth(text.getSize().getWidth());
+        return size;
+    }
+
+    private Consent canDrop(final ObjectAdapter dragSource) {
+        final ObjectContent content = (ObjectContent) getContent();
+        return content.canSet(dragSource);
+    }
+
+    @Override
+    public void dragIn(final ContentDrag drag) {
+        final Content sourceContent = drag.getSourceContent();
+        if (sourceContent instanceof ObjectContent) {
+            final ObjectAdapter source = ((ObjectContent) sourceContent).getObject();
+            final Consent canDrop = canDrop(source);
+            if (canDrop.isAllowed()) {
+                getState().setCanDrop();
+            } else {
+                getState().setCantDrop();
+            }
+            final String actionText = canDrop.isVetoed() ? canDrop.getReason() : "Set to " + sourceContent.title();
+            getFeedbackManager().setAction(actionText);
+        } else {
+            getState().setCantDrop();
+        }
+
+        markDamaged();
+    }
+
+    @Override
+    public void dragOut(final ContentDrag drag) {
+        getState().clearObjectIdentified();
+        markDamaged();
+    }
+
+    @Override
+    public void drop(final ContentDrag drag) {
+        getState().clearViewIdentified();
+        markDamaged();
+        final ObjectAdapter target = ((ObjectContent) getParent().getContent()).getObject();
+        final Content sourceContent = drag.getSourceContent();
+        if (sourceContent instanceof ObjectContent) {
+            final ObjectAdapter source = ((ObjectContent) sourceContent).getObject();
+            setField(target, source);
+        }
+    }
+
+    /**
+     * Objects returned by menus are used to set this field before passing the
+     * call on to the parent.
+     */
+    @Override
+    public void objectActionResult(final ObjectAdapter result, final Placement placement) {
+        final ObjectAdapter target = ((ObjectContent) getParent().getContent()).getObject();
+        if (result instanceof ObjectAdapter) {
+            setField(target, result);
+        }
+        super.objectActionResult(result, placement);
+    }
+
+    private void setField(final ObjectAdapter parent, final ObjectAdapter object) {
+        if (canDrop(object).isAllowed()) {
+            ((ObjectContent) getContent()).setObject(object);
+            getParent().invalidateContent();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "EmptyField" + getId();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java
new file mode 100644
index 0000000..4cbc524
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.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.field;
+
+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.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.text.TitleText;
+
+class EmptyFieldTitleText extends TitleText {
+    private final Content content;
+
+    public EmptyFieldTitleText(final View view, final Text style) {
+        super(view, style, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2));
+        content = view.getContent();
+    }
+
+    @Override
+    protected String title() {
+        return ((ObjectContent) content).getSpecification().getSingularName();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java
new file mode 100644
index 0000000..362405f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java
@@ -0,0 +1,139 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+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.form.InternalFormSpecification;
+import org.apache.isis.viewer.dnd.list.SimpleListSpecification;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeView;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+import org.apache.isis.viewer.dnd.view.text.TitleText;
+
+public class FieldOfSpecification implements ViewSpecification {
+
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isOpen() && !requirement.isSubview() && requirement.getContent() instanceof FieldContent;
+    }
+
+    @Override
+    public String getName() {
+        return "Field Of";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return false;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return false;
+    }
+
+    @Override
+    public boolean isReplaceable() {
+        return false;
+    }
+
+    @Override
+    public boolean isResizeable() {
+        return false;
+    }
+
+    @Override
+    public boolean isSubView() {
+        return false;
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        final FieldContent fieldContent = (FieldContent) content;
+        final ObjectAdapter parent = fieldContent.getParent();
+        final Content parentContent = Toolkit.getContentFactory().createRootContent(parent);
+        View view = new InternalFieldView(parentContent, fieldContent, axes, this);
+        view = addBorder(parentContent, fieldContent, view);
+        return view;
+    }
+
+    private View addBorder(final Content parentContent, final FieldContent fieldContent, View view) {
+        final Text textStyle = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+        final Color colorStyle = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+        final TitleText titleText = new TitleText(view, textStyle, colorStyle) {
+            @Override
+            protected String title() {
+                return parentContent.title() + "/" + fieldContent.getFieldName();
+            }
+        };
+        view = new IconBorder(view, titleText, null, textStyle);
+        return view;
+    }
+
+}
+
+class InternalFieldView extends CompositeView {
+    // final View[] subviews = new View[1];
+
+    private final Content fieldContent;
+
+    public InternalFieldView(final Content content, final Content fieldContent, final Axes axes, final ViewSpecification specification) {
+        super(content, specification);
+        this.fieldContent = fieldContent;
+    }
+
+    /*
+     * public void draw(Canvas canvas) { subviews[0].draw(canvas); }
+     * 
+     * public View[] getSubviews() { return subviews; }
+     */
+    @Override
+    public Size requiredSize(final Size availableSpace) {
+        return getSubviews()[0].getRequiredSize(availableSpace);
+    }
+
+    @Override
+    protected void doLayout(final Size maximumSize) {
+        final View view = getSubviews()[0];
+        view.setSize(view.getRequiredSize(maximumSize));
+        view.layout();
+    }
+
+    @Override
+    protected void buildView() {
+        ViewSpecification internalSpecification;
+        if (fieldContent.isCollection()) {
+            internalSpecification = new SimpleListSpecification();
+        } else {
+            internalSpecification = new InternalFormSpecification();
+        }
+        addView(internalSpecification.createView(fieldContent, new Axes(), 0));
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java
new file mode 100644
index 0000000..cfbce6c
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java
@@ -0,0 +1,263 @@
+/*
+ *  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.field;
+
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.progmodel.facets.value.image.ImageValueFacet;
+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.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractFieldSpecification;
+import org.apache.isis.viewer.dnd.view.base.AwtImage;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+import org.apache.isis.viewer.dnd.view.field.OneToOneField;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class ImageField extends AbstractField {
+    public static class Specification extends AbstractFieldSpecification {
+        @Override
+        public boolean canDisplay(final ViewRequirement requirement) {
+            return requirement.isForValueType(ImageValueFacet.class);
+        }
+
+        @Override
+        public View createView(final Content content, final Axes axes, final int sequence) {
+            return new ImageField(content, this);
+        }
+
+        @Override
+        public String getName() {
+            return "Image";
+        }
+    }
+
+    private static final Logger LOG = Logger.getLogger(ImageField.class);
+    private static final MediaTracker mt = new MediaTracker(new java.awt.Canvas());
+
+    public ImageField(final Content content, final ViewSpecification specification) {
+        super(content, specification);
+    }
+
+    @Override
+    public boolean canFocus() {
+        return true;
+    }
+
+    @Override
+    public void contentMenuOptions(final UserActionSet options) {
+        super.contentMenuOptions(options);
+
+        options.add(new UserActionAbstract("Load image from file...") {
+            @Override
+            public void execute(final Workspace workspace, final View view, final Location at) {
+                final String file = getViewManager().selectFilePath("Load image", ".");
+                if (new File(file).exists()) {
+                    loadImageFromFile(file);
+                }
+            }
+        });
+    }
+
+    private void copy() {
+    }
+
+    @Override
+    public void draw(final Canvas canvas) {
+        Color color;
+
+        if (hasFocus()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1);
+        } else if (getParent().getState().isObjectIdentified()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_IDENTIFIED);
+        } else if (getParent().getState().isRootViewIdentified()) {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY2);
+        } else {
+            color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1);
+        }
+
+        int top = 0;
+        int left = 0;
+
+        final Size size = getSize();
+        int w = size.getWidth() - 1;
+        int h = size.getHeight() - 1;
+        canvas.drawRectangle(left, top, w, h, color);
+        left++;
+        top++;
+        w -= 1;
+        h -= 1;
+
+        final ObjectAdapter value = getContent().getAdapter();
+        if (value != null) {
+            final ImageValueFacet facet = value.getSpecification().getFacet(ImageValueFacet.class);
+            final java.awt.Image image = facet.getImage(value);
+            if (image != null) {
+                final Size imageSize = new Size(facet.getWidth(value), facet.getHeight(value));
+                if (imageSize.getWidth() <= w && imageSize.getHeight() <= h) {
+                    canvas.drawImage(new AwtImage(image), left, top);
+                } else {
+                    canvas.drawImage(new AwtImage(image), left, top, w, h);
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getBaseline() {
+        return ViewConstants.VPADDING + Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getAscent();
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        final ObjectAdapter value = getContent().getAdapter();
+        if (value == null) {
+            return super.getRequiredSize(availableSpace);
+        } else {
+            final ImageValueFacet facet = value.getSpecification().getFacet(ImageValueFacet.class);
+            final int width = Math.min(120, Math.max(32, facet.getWidth(value)));
+            final int height = Math.min(120, Math.max(32, facet.getHeight(value)));
+            return new Size(width, height);
+        }
+    }
+
+    @Override
+    public void keyPressed(final KeyboardAction key) {
+        if (canChangeValue().isVetoed()) {
+            return;
+        }
+
+        final int keyCode = key.getKeyCode();
+        if (keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT) {
+            return;
+        }
+
+        final int modifiers = key.getModifiers();
+        final boolean ctrl = (modifiers & InputEvent.CTRL_MASK) > 0;
+
+        switch (keyCode) {
+        case KeyEvent.VK_V:
+            if (ctrl) {
+                key.consume();
+                pasteFromClipboard();
+            }
+            break;
+        case KeyEvent.VK_C:
+            if (ctrl) {
+                key.consume();
+                copy();
+            }
+            break;
+        }
+    }
+
+    private void loadImage(final Image image) {
+        mt.addImage(image, 1);
+        try {
+            mt.waitForAll();
+        } catch (final InterruptedException e) {
+            throw new IsisException(e);
+        }
+
+        // final ObjectAdapter value = getContent().getAdapter();
+        final ImageValueFacet facet = ((FieldContent) getContent()).getSpecification().getFacet(ImageValueFacet.class);
+        final ObjectAdapter object = facet.createValue(image);
+        ((OneToOneField) getContent()).setObject(object);
+        // ((TextParseableField) getContent()).entryComplete();
+        invalidateLayout();
+    }
+
+    /*
+     * private void loadImageFromURL(final String filename) { try { final URL
+     * url = new URL("file://" + filename); final Image image =
+     * java.awt.Toolkit.getDefaultToolkit().getImage(url); loadImage(image); }
+     * catch (final MalformedURLException e) { throw new
+     * IsisException("Failed to load image from " + filename); } }
+     */
+    private void loadImageFromFile(final String filename) {
+        final Image image = java.awt.Toolkit.getDefaultToolkit().getImage(filename);
+        loadImage(image);
+    }
+
+    @Override
+    protected void pasteFromClipboard() {
+        final Clipboard cb = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
+        final Transferable content = cb.getContents(this);
+
+        try {
+            if (content.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+                // treat a string as a file
+                final String filename = (String) content.getTransferData(DataFlavor.stringFlavor);
+                LOG.debug("pasted image from " + filename);
+                loadImageFromFile("file://" + filename);
+
+            } else {
+                LOG.info("unsupported paste operation " + content);
+
+                // note java does not support transferring images from the
+                // clipboard
+                // although it has an image flavor for it !!?
+                /*
+                 * DataFlavor[] transferDataFlavors =
+                 * content.getTransferDataFlavors(); for (int i = 0; i <
+                 * transferDataFlavors.length; i++) {
+                 * LOG.debug("data transfer as " +
+                 * transferDataFlavors[i].getMimeType()); }
+                 * 
+                 * Image image = (Image)
+                 * content.getTransferData(DataFlavor.imageFlavor);
+                 * LOG.debug("pasted " + image);
+                 */
+
+            }
+
+        } catch (final Throwable e) {
+            LOG.error("invalid paste operation " + e);
+        }
+
+    }
+
+    @Override
+    protected void save() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java
new file mode 100644
index 0000000..fefd02f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java
@@ -0,0 +1,188 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+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.util.Properties;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+import org.apache.isis.viewer.dnd.view.text.TextContent;
+
+public class PasswordField extends TextField {
+    protected static final Text style = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+    private int maxTextWidth;
+    private char echoCharacter;
+
+    public PasswordField(final Content content, final ViewSpecification design) {
+        super((TextParseableContent) content, design, true, TextContent.NO_WRAPPING);
+        setMaxTextWidth(TEXT_WIDTH);
+        final String echoCharacterSetting = IsisContext.getConfiguration().getString(Properties.PROPERTY_BASE + "echo");
+        if (echoCharacterSetting == null || echoCharacterSetting.equals(" ")) {
+            echoCharacter = '*';
+        } else {
+            echoCharacter = echoCharacterSetting.charAt(0);
+        }
+    }
+
+    @Override
+    public void contentMenuOptions(final UserActionSet options) {
+        options.add(new ClearValueOption(this));
+        options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_VALUE));
+    }
+
+    @Override
+    protected boolean provideClearCopyPaste() {
+        return false;
+    }
+
+    /**
+     * Only allow deletion of last character, ie don;t allow editing of the
+     * internals of the password.
+     */
+    @Override
+    public void delete() {
+        textContent.deleteLeft(cursor);
+        cursor.left();
+        selection.resetTo(cursor);
+        changeMade();
+    }
+
+    /**
+     * disable left key.
+     */
+    @Override
+    protected void left(final boolean alt, final boolean shift) {
+    }
+
+    /**
+     * disable right key.
+     */
+    @Override
+    protected void right(final boolean alt, final boolean shift) {
+    }
+
+    /**
+     * disable home key.
+     */
+    @Override
+    protected void home(final boolean alt, final boolean shift) {
+    }
+
+    /**
+     * disable end key.
+     */
+    @Override
+    protected void end(final boolean alt, final boolean shift) {
+    }
+
+    /**
+     * disable page down key.
+     */
+    @Override
+    protected void pageDown(final boolean shift, final boolean ctrl) {
+    }
+
+    /**
+     * disable page up key.
+     */
+    @Override
+    protected void pageUp(final boolean shift, final boolean ctrl) {
+    }
+
+    private String echoPassword(final String password) {
+        final int length = password.length();
+        String echoedPassword = "";
+        for (int i = 0; i < length; i++) {
+            echoedPassword += echoCharacter;
+        }
+        return echoedPassword;
+    }
+
+    @Override
+    public Size getRequiredSize(final Size availableSpace) {
+        final int width = ViewConstants.HPADDING + maxTextWidth + ViewConstants.HPADDING;
+        int height = style.getTextHeight() + ViewConstants.VPADDING;
+        height = Math.max(height, Toolkit.defaultFieldHeight());
+
+        return new Size(width, height);
+    }
+
+    /**
+     * Set the maximum width of the field, as a number of characters
+     */
+    private void setMaxTextWidth(final int noCharacters) {
+        maxTextWidth = style.charWidth('o') * noCharacters;
+    }
+
+    @Override
+    protected void align() {
+    }
+
+    @Override
+    protected void drawHighlight(final Canvas canvas, final int maxWidth) {
+    }
+
+    @Override
+    protected void drawLines(final Canvas canvas, final Color color, final int width) {
+        final int baseline = getBaseline();
+        canvas.drawLine(ViewConstants.HPADDING, baseline, ViewConstants.HPADDING + width, baseline, color);
+    }
+
+    @Override
+    protected void drawText(final Canvas canvas, final Color textColor, final int width) {
+
+        final String[] lines = textContent.getDisplayLines();
+        if (lines.length > 1) {
+            throw new IsisException("Password field should contain a string that contains no line breaks; contains " + lines.length);
+        }
+
+        final String chars = lines[0];
+        if (chars == null) {
+            throw new IsisException();
+        }
+        if (chars.endsWith("\n")) {
+            throw new IsisException();
+        }
+
+        final int baseline = getBaseline();
+        final String echoPassword = echoPassword(chars);
+
+        // draw cursor
+        if (hasFocus() && canChangeValue().isAllowed()) {
+            final int pos = style.stringWidth(echoPassword) - ViewConstants.HPADDING;
+            final Color color = Toolkit.getColor(ColorsAndFonts.COLOR_TEXT_CURSOR);
+            canvas.drawLine(pos, (baseline + style.getDescent()), pos, baseline - style.getAscent(), color);
+        }
+
+        // draw text
+        canvas.drawText(echoPassword, ViewConstants.HPADDING, baseline, textColor, style);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java
new file mode 100644
index 0000000..a51dfeb
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java
@@ -0,0 +1,49 @@
+/*
+ *  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.field;
+
+import org.apache.isis.core.progmodel.facets.value.password.PasswordValueFacet;
+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.base.AbstractFieldSpecification;
+
+public class PasswordFieldSpecification extends AbstractFieldSpecification {
+    @Override
+    public boolean canDisplay(final ViewRequirement requirement) {
+        return requirement.isTextParseable() && requirement.isForValueType(PasswordValueFacet.class);
+    }
+
+    @Override
+    public View createView(final Content content, final Axes axes, final int sequence) {
+        return new PasswordField(content, this);
+    }
+
+    @Override
+    public String getName() {
+        return "Password Field";
+    }
+
+    @Override
+    public boolean isAligned() {
+        return true;
+    }
+}