You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2012/12/08 15:56:01 UTC
[12/53] [partial] ISIS-188: making structure of component viewers
consistent
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CheckboxField.java
new file mode 100644
index 0000000..dd44730
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ClearValueOption.java
new file mode 100644
index 0000000..3daa53f
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorField.java
new file mode 100644
index 0000000..986ef0f
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ColorFieldOverlay.java
new file mode 100644
index 0000000..ab27820
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/CopyValueOption.java
new file mode 100644
index 0000000..b9219af
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DateFieldSpecification.java
new file mode 100644
index 0000000..5a8cc12
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePicker.java
new file mode 100644
index 0000000..2153fb5
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/DatePickerControl.java
new file mode 100644
index 0000000..99f1675
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyField.java
new file mode 100644
index 0000000..1f5449a
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/EmptyFieldTitleText.java
new file mode 100644
index 0000000..4cbc524
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/FieldOfSpecification.java
new file mode 100644
index 0000000..362405f
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/ImageField.java
new file mode 100644
index 0000000..cfbce6c
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordField.java
new file mode 100644
index 0000000..fefd02f
--- /dev/null
+++ b/component/viewer/dnd/impl/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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasswordFieldSpecification.java
new file mode 100644
index 0000000..a51dfeb
--- /dev/null
+++ b/component/viewer/dnd/impl/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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasteValueOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasteValueOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasteValueOption.java
new file mode 100644
index 0000000..138ae26
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/PasteValueOption.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.Consent;
+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 PasteValueOption extends AbstractValueOption {
+
+ public PasteValueOption(final AbstractField field) {
+ super(field, "Paste");
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ final Consent changable = view.canChangeValue();
+ if (changable.isVetoed()) {
+ return changable;
+ } else {
+ return changable.setDescription(String.format("Replace field content with '%s' from clipboard", getClipboard(view)));
+ }
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ field.pasteFromClipboard();
+ }
+
+ private String getClipboard(final View view) {
+ return (String) view.getViewManager().getClipboard(String.class);
+ }
+
+ @Override
+ public String toString() {
+ return "PasteValueOption";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/RevertFieldOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/RevertFieldOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/RevertFieldOption.java
new file mode 100644
index 0000000..ba739de
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/RevertFieldOption.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.field;
+
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.ConsentAbstract;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class RevertFieldOption extends UserActionAbstract {
+ private final TextField field;
+
+ public RevertFieldOption(final TextField field) {
+ super("Revert");
+ this.field = field;
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "Revert the field to it original state";
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ return ConsentAbstract.allowIf(field.hasInvalidEntry());
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ field.revertInvalidEntry();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/SimpleDatePicker.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/SimpleDatePicker.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/SimpleDatePicker.java
new file mode 100644
index 0000000..46f6408
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/field/SimpleDatePicker.java
@@ -0,0 +1,392 @@
+/*
+ * 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.event.KeyEvent;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.progmodel.facets.value.date.DateValueFacet;
+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.Shape;
+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.Content;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+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.FieldContent;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+
+public class SimpleDatePicker extends AbstractView implements DatePicker {
+ private static class Button {
+ private final char key;
+ private final int period;
+ private final int increment;
+
+ public Button(final char key, final int period, final int increment) {
+ this.key = key;
+ this.period = period;
+ this.increment = increment;
+ }
+
+ public void adjustDate(final Calendar date) {
+ date.add(period, increment);
+ }
+
+ public String getLabel() {
+ return "" + key;
+ }
+ }
+
+ private static final Button[] buttons = new Button[] { new Button('W', Calendar.WEEK_OF_YEAR, 1), new Button('F', Calendar.WEEK_OF_YEAR, 2), new Button('M', Calendar.MONTH, 1), new Button('Q', Calendar.MONTH, 3), new Button('Y', Calendar.YEAR, 1), new Button('D', Calendar.YEAR, 10),
+
+ new Button('w', Calendar.WEEK_OF_YEAR, -1), new Button('f', Calendar.WEEK_OF_YEAR, -2), new Button('m', Calendar.MONTH, -1), new Button('q', Calendar.MONTH, -3), new Button('y', Calendar.YEAR, -1), new Button('d', Calendar.YEAR, -10) };
+ private static final int ROWS = 7;
+ private static final int COLUMNS = 7;
+ private static final int PADDING = 5;
+ private final Calendar date;
+ private final Text style = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ private final int labelWidth = style.stringWidth("XXX 0000") * 4 / 3;
+ private final int cellWidth = style.stringWidth("00") * 8 / 5;
+ private final int cellHeight = style.getLineHeight() * 4 / 3;
+ private final int headerHeight = style.getLineHeight() + PADDING * 2;
+ private final int firstRowBaseline = headerHeight + style.getLineHeight();
+ private final int calendarHeight = cellHeight * ROWS;
+ private final int controlWidth = style.charWidth('W') + 4;
+ private final int controlHeight = style.getLineHeight() * 11 / 10 + controlWidth + 4 + PADDING * 2;
+ private int mouseOverButton = -1;
+ private int mouseOverRow = -1;
+ private int mouseOverColumn;
+ private Calendar currentDate;
+ private final Calendar today;
+ private final DateFormat monthFormat = new SimpleDateFormat("MMM");
+ private final DateFormat dayFormat = new SimpleDateFormat("EEE");
+ private final boolean isEditable;
+
+ public SimpleDatePicker(final Content content) {
+ super(content);
+
+ isEditable = content instanceof FieldContent && ((FieldContent) content).isEditable().isAllowed();
+
+ today = Calendar.getInstance();
+ clearTime(today);
+
+ date = Calendar.getInstance();
+ final ObjectAdapter dateAdapter = ((TextParseableContent) getContent()).getAdapter();
+ if (dateAdapter != null) {
+ final DateValueFacet facet = dateAdapter.getSpecification().getFacet(DateValueFacet.class);
+ currentDate = Calendar.getInstance();
+ final Date dateValue = facet.dateValue(dateAdapter);
+ currentDate.setTime(dateValue);
+ clearTime(currentDate);
+ date.setTime(dateValue);
+ }
+ clearTime(date);
+ date.add(Calendar.DAY_OF_MONTH, -21);
+ roundDownDate();
+ }
+
+ private void roundDownDate() {
+ date.add(Calendar.DAY_OF_MONTH, date.getFirstDayOfWeek() - date.get(Calendar.DAY_OF_WEEK));
+ }
+
+ private void clearTime(final Calendar date) {
+ date.clear(Calendar.AM_PM);
+ date.clear(Calendar.HOUR);
+ date.clear(Calendar.HOUR_OF_DAY);
+ date.clear(Calendar.MINUTE);
+ date.clear(Calendar.SECOND);
+ date.clear(Calendar.MILLISECOND);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.nakedobjects.plugins.dnd.field.DatePicker#getRequiredSize(org.
+ * nakedobjects.plugins.dnd.drawing.Size)
+ */
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ return new Size(labelWidth + COLUMNS * cellWidth + 2, headerHeight + calendarHeight + controlHeight + 2);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.nakedobjects.plugins.dnd.field.DatePicker#draw(org.nakedobjects.plugins
+ * .dnd.drawing.Canvas)
+ */
+ @Override
+ public void draw(final Canvas canvas) {
+ final int width = getSize().getWidth();
+ final int height = getSize().getHeight();
+
+ final Color secondaryTextColor = Toolkit.getColor(ColorsAndFonts.COLOR_WHITE);
+ final Color mainTextColor = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+
+ drawBackground(canvas, width, height);
+ drawDaysOfWeek(canvas, secondaryTextColor);
+ if (isEditable) {
+ drawDayMarker(canvas);
+ }
+ drawMonthsAndWeeks(canvas, secondaryTextColor);
+ drawDays(canvas, mainTextColor);
+ drawControls(canvas, width);
+ }
+
+ private void drawBackground(final Canvas canvas, final int width, final int height) {
+ canvas.drawSolidRectangle(0, 0, width - 1, headerHeight, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1));
+ canvas.drawSolidRectangle(0, 0, labelWidth, height - 1, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1));
+ canvas.drawSolidRectangle(labelWidth, headerHeight, width - labelWidth - 1, height - cellHeight - 1, Toolkit.getColor(ColorsAndFonts.COLOR_WINDOW));
+ canvas.drawRectangle(0, 0, width - 1, height - 1, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1));
+ }
+
+ private void drawDaysOfWeek(final Canvas canvas, final Color textColor) {
+ final Calendar d = Calendar.getInstance();
+ d.setTime(date.getTime());
+ int x = labelWidth + cellWidth / 2;
+ final int y = PADDING + style.getAscent();
+ for (int column = 0; column < 7; column++) {
+ final String day = dayFormat.format(d.getTime()).substring(0, 1);
+ canvas.drawText(day, x - style.stringWidth(day) / 2, y, textColor, style);
+ x += cellWidth;
+ d.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ }
+
+ private void drawDayMarker(final Canvas canvas) {
+ if (mouseOverColumn >= 0 && mouseOverColumn < COLUMNS && mouseOverRow >= 0 && mouseOverRow < ROWS) {
+ canvas.drawRectangle(labelWidth + mouseOverColumn * cellWidth, headerHeight + mouseOverRow * cellHeight, cellWidth, cellHeight, Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY3));
+ }
+ }
+
+ private int drawMonthsAndWeeks(final Canvas canvas, final Color color) {
+ final Calendar d = Calendar.getInstance();
+ d.setTime(date.getTime());
+ int y = firstRowBaseline;
+ String lastMonth = "";
+ for (int row = 0; row < ROWS; row++) {
+ final int x = labelWidth;
+ final String month = monthFormat.format(d.getTime()) + " " + d.get(Calendar.YEAR);
+ if (!month.equals(lastMonth)) {
+ canvas.drawText(month, x - style.stringWidth(month) - PADDING, y, color, style);
+ lastMonth = month;
+ } else {
+ final String week = "wk " + (d.get(Calendar.WEEK_OF_YEAR));
+ canvas.drawText(week == null ? "*" : week, x - style.stringWidth(week) - PADDING, y, color, style);
+ }
+ d.add(Calendar.DAY_OF_MONTH, 7);
+ y += cellHeight;
+ }
+ return y;
+ }
+
+ private int drawDays(final Canvas canvas, final Color mainTextColor) {
+ final Calendar d = Calendar.getInstance();
+ d.setTime(date.getTime());
+ int y = firstRowBaseline;
+ for (int row = 0; row < ROWS; row++) {
+ int x = labelWidth;
+ for (int column = 0; column < COLUMNS; column++) {
+ final String day = "" + d.get(Calendar.DAY_OF_MONTH);
+ if (currentDate != null && currentDate.equals(d)) {
+ canvas.drawSolidRectangle(x, headerHeight + row * cellHeight, cellWidth, cellHeight, Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY2));
+ }
+ if (today.getTime().equals(d.getTime())) {
+ canvas.drawRectangle(x, headerHeight + row * cellHeight, cellWidth, cellHeight, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2));
+ }
+ canvas.drawText(day, x - PADDING / 2 + cellWidth - style.stringWidth(day), y, mainTextColor, style);
+ x += cellWidth;
+ d.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ y += cellHeight;
+ }
+ return y;
+ }
+
+ private void drawControls(final Canvas canvas, final int width) {
+ int x = labelWidth + PADDING;
+ final int y = headerHeight + calendarHeight + PADDING;
+
+ final int spaceTaken = width - labelWidth - 2 * PADDING - 6 * controlWidth;
+ final int spaceBetween = spaceTaken / 5;
+ final int adjustment = spaceTaken - 5 * spaceBetween - 2;
+
+ for (int i = 0; i < buttons.length / 2; i++) {
+ drawControl(canvas, x, y, controlWidth, controlHeight - PADDING * 2, buttons[i].getLabel(), i);
+ x += controlWidth + spaceBetween + (i == 3 ? adjustment : 0);
+ }
+ }
+
+ private void drawControl(final Canvas canvas, final int x, final int y, final int width, final int height, final String label, final int over) {
+ if (Toolkit.debug) {
+ canvas.drawRectangle(x - 2, y, width + 4, height, Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_VIEW));
+ }
+ final Color color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2);
+
+ final int arrowHeight = width / 2;
+ final Shape upArrow = new Shape(0, arrowHeight);
+ upArrow.addVector(arrowHeight, -arrowHeight);
+ upArrow.addVector(arrowHeight, arrowHeight);
+ if (mouseOverButton == over + 6) {
+ canvas.drawSolidShape(upArrow, x, y + 2, color);
+ } else {
+ canvas.drawShape(upArrow, x, y + 2, color);
+ }
+
+ final Shape downArrow = new Shape(0, 0);
+ downArrow.addVector(arrowHeight, arrowHeight);
+ downArrow.addVector(arrowHeight, -arrowHeight);
+ if (mouseOverButton == over) {
+ canvas.drawSolidShape(downArrow, x, y + height - 4 - arrowHeight, color);
+ } else {
+ canvas.drawShape(downArrow, x, y + height - 4 - arrowHeight, color);
+ }
+ final int charWidth = style.stringWidth(label);
+ canvas.drawText(label, x + width / 2 - charWidth / 2, y + 2 + arrowHeight + style.getAscent(), color, style);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.nakedobjects.plugins.dnd.field.DatePicker#mouseMoved(org.nakedobjects
+ * .plugins.dnd.drawing.Location)
+ */
+ @Override
+ public void mouseMoved(final Location location) {
+ final int over = overButton(location);
+ if (over == -1) {
+ mouseOverButton = -1;
+ final int col = column(location);
+ final int row = row(location);
+ if (col != mouseOverColumn || row != mouseOverRow) {
+ if (isEditable) {
+ mouseOverColumn = col;
+ mouseOverRow = row;
+ }
+ markDamaged();
+ }
+ } else if (over != mouseOverButton) {
+ mouseOverButton = over;
+ markDamaged();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.nakedobjects.plugins.dnd.field.DatePicker#exited()
+ */
+ @Override
+ public void exited() {
+ mouseOverButton = -1;
+ super.exited();
+ }
+
+ private int overButton(final Location location) {
+ final int x = location.getX();
+ final int y = location.getY();
+ final int verticalBoundary = headerHeight + calendarHeight + PADDING;
+ final int height = controlHeight - PADDING * 2;
+ if (x > labelWidth && y > verticalBoundary && y < verticalBoundary + height) {
+ int column = (x - labelWidth) / ((getSize().getWidth() - labelWidth) / 6);
+ if (y <= verticalBoundary + height / 2) {
+ column += 6;
+ }
+ return column;
+ } else {
+ return -1;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.nakedobjects.plugins.dnd.field.DatePicker#firstClick(org.nakedobjects
+ * .plugins.dnd.view.Click)
+ */
+ @Override
+ public void firstClick(final Click click) {
+ if (mouseOverButton != -1) {
+ buttons[mouseOverButton].adjustDate(date);
+ roundDownDate();
+ markDamaged();
+ return;
+ }
+
+ if (isEditable) {
+ final Location location = click.getLocation();
+ final int col = column(location);
+ final int row = row(location);
+ if (col >= 0 && col < COLUMNS && row >= 0 && row < ROWS) {
+ date.add(Calendar.DAY_OF_MONTH, row * 7 + col);
+ final Content content = getContent();
+ final DateValueFacet facet = content.getSpecification().getFacet(DateValueFacet.class);
+ final ObjectAdapter value = facet.createValue(date.getTime());
+ ((TextParseableContent) content).parseTextEntry(value.titleString());
+ ((TextParseableContent) content).entryComplete();
+ /*
+ * if (content.isObject()) { ((ObjectContent)
+ * content).setObject(value); }
+ */
+ // content.
+ getView().refresh();
+
+ // content.
+ }
+ }
+ getViewManager().clearOverlayView();
+ }
+
+ private int row(final Location location) {
+ return (location.getY() - headerHeight) / cellHeight;
+ }
+
+ private int column(final Location location) {
+ return (location.getX() - labelWidth) / cellWidth;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.nakedobjects.plugins.dnd.field.DatePicker#keyPressed(org.nakedobjects
+ * .plugins.dnd.view.KeyboardAction)
+ */
+ @Override
+ public void keyPressed(final KeyboardAction key) {
+ if (isEditable && key.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ getViewManager().clearOverlayView();
+ } else {
+ super.keyPressed(key);
+ }
+ }
+}