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:19 UTC
[51/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/view/action/ObjectParameterImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ObjectParameterImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ObjectParameterImpl.java
new file mode 100644
index 0000000..9df01a1
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ObjectParameterImpl.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.action;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+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.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneActionParameter;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.content.AbstractObjectContent;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class ObjectParameterImpl extends AbstractObjectContent implements ObjectParameter {
+ private final ObjectAdapter adapter;
+ private final ActionHelper invocation;
+ private final int index;
+ private final ObjectAdapter[] optionAdapters;
+ private final OneToOneActionParameter objectActionParameter;
+
+ public ObjectParameterImpl(final OneToOneActionParameter objectActionParameter, final ObjectAdapter adapter, final ObjectAdapter[] optionAdapters, final int i, final ActionHelper invocation) {
+ this.objectActionParameter = objectActionParameter;
+ this.optionAdapters = optionAdapters;
+ this.index = i;
+ this.invocation = invocation;
+ this.adapter = adapter;
+ }
+
+ public ObjectParameterImpl(final ObjectParameterImpl content, final ObjectAdapter object) {
+ objectActionParameter = content.objectActionParameter;
+ optionAdapters = content.optionAdapters;
+ index = content.index;
+ invocation = content.invocation;
+ this.adapter = object;
+ }
+
+ @Override
+ public Consent canClear() {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public Consent canSet(final ObjectAdapter dragSource) {
+ if (dragSource.getSpecification().isOfType(getSpecification())) {
+ // TODO: move logic into Facet
+ return Allow.DEFAULT;
+ } else {
+ // TODO: move logic into Facet
+ return new Veto(String.format("Object must be ", getSpecification().getShortIdentifier()));
+ }
+ }
+
+ @Override
+ public void clear() {
+ setObject(null);
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ debug.appendln("name", getParameterName());
+ debug.appendln("required", isRequired());
+ debug.appendln("object", adapter);
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return adapter;
+ }
+
+ @Override
+ public ObjectAdapter getObject() {
+ return adapter;
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return optionAdapters;
+ }
+
+ @Override
+ public boolean isObject() {
+ return true;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return !objectActionParameter.isOptional();
+ }
+
+ @Override
+ public boolean isPersistable() {
+ return false;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return optionAdapters != null && optionAdapters.length > 0;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return adapter != null && adapter.isTransient();
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ if (adapter != null) {
+ options.add(new UserActionAbstract("Clear parameter") {
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ clear();
+ view.getParent().invalidateContent();
+ }
+ });
+
+ OptionFactory.addObjectMenuOptions(adapter, options);
+ } else {
+ OptionFactory.addCreateOptions(getSpecification(), options);
+
+ }
+
+ }
+
+ @Override
+ public void setObject(final ObjectAdapter object) {
+ invocation.setParameter(index, object);
+ }
+
+ @Override
+ public String title() {
+ return adapter == null ? "" : adapter.titleString();
+ }
+
+ @Override
+ public String toString() {
+ final ToString toString = new ToString(this);
+ toString.append("label", getParameterName());
+ toString.append("required", isRequired());
+ toString.append("spec", getSpecification().getFullIdentifier());
+ toString.append("object", adapter == null ? "null" : adapter.titleString());
+ return toString.toString();
+ }
+
+ @Override
+ public String getParameterName() {
+ return objectActionParameter.getName();
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return objectActionParameter.getSpecification();
+ }
+
+ @Override
+ public String getDescription() {
+ final String title = adapter == null ? "" : ": " + adapter.titleString();
+ final String name = getParameterName();
+ final ObjectSpecification specification = objectActionParameter.getSpecification();
+ final String specName = specification.getShortIdentifier();
+ final String type = name.indexOf(specName) == -1 ? " (" + specName + ")" : "";
+ return name + type + title + " " + objectActionParameter.getDescription();
+ }
+
+ @Override
+ public String getHelp() {
+ return invocation.getHelp();
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/OptionFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/OptionFactory.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/OptionFactory.java
new file mode 100644
index 0000000..f3e5260
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/OptionFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.action;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.FreeStandingList;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionContainer.Contributed;
+import org.apache.isis.viewer.dnd.view.UserAction;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.option.DisposeObjectOption;
+
+public class OptionFactory {
+
+ public static void addCreateOptions(final ObjectSpecification specification, final UserActionSet options) {
+ // TODO do the same as addObjectMenuOptions and collect together all the
+ // actions for all the types
+ final List<ObjectAction> actions = specification.getServiceActionsReturning(Arrays.asList(ActionType.USER, ActionType.EXPLORATION, ActionType.PROTOTYPE, ActionType.DEBUG));
+ menuOptions(actions, null, options);
+ }
+
+ public static void addObjectMenuOptions(final ObjectAdapter adapter, final UserActionSet options) {
+ if (adapter == null) {
+ return;
+ }
+
+ final ObjectSpecification noSpec = adapter.getSpecification();
+ menuOptions(noSpec.getObjectActions(Arrays.asList(ActionType.USER, ActionType.EXPLORATION, ActionType.PROTOTYPE, ActionType.DEBUG), Contributed.INCLUDED), adapter, options);
+
+ // TODO: this looks like a bit of a hack; can we improve it by looking
+ // at the facets?
+ if (adapter.getObject() instanceof FreeStandingList) {
+ return;
+ }
+ final Oid oid = adapter.getOid();
+ if (oid != null && adapter.isTransient()) {
+ return;
+ }
+ if (noSpec.isService()) {
+ return;
+ }
+
+ options.add(new DisposeObjectOption());
+ }
+
+ private static void menuOptions(final List<ObjectAction> actions, final ObjectAdapter target, final UserActionSet menuOptionSet) {
+ for (int i = 0; i < actions.size(); i++) {
+ UserAction option = null;
+ if (actions.get(i).getActions().size() > 0) {
+ option = menuOptionSet.addNewActionSet(actions.get(i).getName());
+ menuOptions(actions.get(i).getActions(), target, (UserActionSet) option);
+
+ } else {
+ final int noOfParameters = actions.get(i).getParameterCount();
+ if (noOfParameters == 0) {
+ option = ImmediateObjectOption.createOption(actions.get(i), target);
+ } else if (actions.get(i).isContributed() && noOfParameters == 1 && target != null && target.getSpecification().isOfType(actions.get(i).getParameters().get(0).getSpecification())) {
+ option = ImmediateObjectOption.createServiceOption(actions.get(i), target);
+ } else {
+ option = DialoggedObjectOption.createOption(actions.get(i), target);
+ }
+ if (option != null) {
+ menuOptionSet.add(option);
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ParameterContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ParameterContent.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ParameterContent.java
new file mode 100644
index 0000000..11d02b0
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/ParameterContent.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.action;
+
+import org.apache.isis.viewer.dnd.view.Content;
+
+public interface ParameterContent extends Content {
+
+ String getParameterName();
+
+ boolean isRequired();
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameter.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameter.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameter.java
new file mode 100644
index 0000000..3834146
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameter.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.action;
+
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+
+public interface TextParseableParameter extends ParameterContent, TextParseableContent {
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameterImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameterImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameterImpl.java
new file mode 100644
index 0000000..3d00069
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/action/TextParseableParameterImpl.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.action;
+
+import org.apache.isis.applib.profiles.Localization;
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
+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.core.metamodel.facets.object.parseable.InvalidEntryException;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ParseableEntryActionParameter;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.ImageFactory;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.content.AbstractTextParsableContent;
+
+public class TextParseableParameterImpl extends AbstractTextParsableContent implements TextParseableParameter {
+ private ObjectAdapter object;
+ private final ObjectAdapter[] options;
+ private final ParseableEntryActionParameter parameter;
+ private final ActionHelper invocation;
+ private final int index;
+
+ public TextParseableParameterImpl(final ParseableEntryActionParameter objectActionParameters, final ObjectAdapter adapter, final ObjectAdapter[] options, final int i, final ActionHelper invocation) {
+ this.parameter = objectActionParameters;
+ this.options = options;
+ index = i;
+ this.invocation = invocation;
+ object = adapter;
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ debug.appendln("name", parameter.getName());
+ debug.appendln("required", isRequired());
+ debug.appendln("object", object);
+ }
+
+ @Override
+ public void entryComplete() {
+ }
+
+ @Override
+ public String getIconName() {
+ return "";
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return ImageFactory.getInstance().loadIcon("value", 12, null);
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return object;
+ }
+
+ @Override
+ public int getNoLines() {
+ return parameter.getNoLines();
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return options;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return object == null;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return !parameter.isOptional();
+ }
+
+ @Override
+ public Consent canClear() {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public boolean canWrap() {
+ return parameter.canWrap();
+ }
+
+ @Override
+ public void clear() {
+ object = null;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return true;
+ }
+
+ @Override
+ public boolean isTextParseable() {
+ return true;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return options != null && options.length > 0;
+ }
+
+ @Override
+ public String title() {
+ return AdapterUtils.titleString(object);
+ }
+
+ @Override
+ public String toString() {
+ final ToString toString = new ToString(this);
+ toString.append("object", object);
+ return toString.toString();
+ }
+
+ @Override
+ public String getParameterName() {
+ return parameter.getName();
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return parameter.getSpecification();
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ return null;
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public String titleString(final ObjectAdapter value) {
+ return titleString(value, parameter, parameter.getSpecification());
+ }
+
+ /**
+ * @throws InvalidEntryException
+ * - turns the parameter red if invalid.
+ */
+ @Override
+ public void parseTextEntry(final String entryText) {
+ object = parse(entryText);
+ Localization localization = IsisContext.getLocalization();
+ final String reason = parameter.isValid(object, AdapterUtils.unwrap(object), localization);
+ if (reason != null) {
+ throw new InvalidEntryException(reason);
+ } else if (!parameter.isOptional() && object == null) {
+ throw new InvalidEntryException("Mandatory parameter cannot be empty");
+ }
+ invocation.setParameter(index, object);
+ }
+
+ private ObjectAdapter parse(final String entryText) {
+ final ObjectSpecification parameterSpecification = parameter.getSpecification();
+ final ParseableFacet p = parameterSpecification.getFacet(ParseableFacet.class);
+ try {
+ Localization localization = IsisContext.getLocalization();
+ return p.parseTextEntry(object, entryText, localization);
+ } catch (final IllegalArgumentException ex) {
+ throw new InvalidEntryException(ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ final String title = object == null ? "" : ": " + object.titleString();
+ final String specification = getSpecification().getShortIdentifier();
+ final String type = getParameterName().indexOf(specification) == -1 ? "" : " (" + specification + ")";
+ return getParameterName() + type + title + " " + parameter.getDescription();
+ }
+
+ @Override
+ public String getHelp() {
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public Consent isEditable() {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public int getMaximumLength() {
+ return parameter.getMaximumLength();
+ }
+
+ @Override
+ public int getTypicalLineLength() {
+ return parameter.getTypicalLineLength();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/axis/LabelAxis.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/axis/LabelAxis.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/axis/LabelAxis.java
new file mode 100644
index 0000000..effcd5d
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/axis/LabelAxis.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.axis;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+
+public class LabelAxis implements ViewAxis {
+ private int width;
+
+ public LabelAxis() {
+ }
+
+ public void accommodateWidth(final int width) {
+ this.width = Math.max(this.width, width);
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("width", width);
+ return str.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractBorder.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractBorder.java
new file mode 100644
index 0000000..3dab885
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractBorder.java
@@ -0,0 +1,289 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.base;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+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.Padding;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.ContentDrag;
+import org.apache.isis.viewer.dnd.view.DragEvent;
+import org.apache.isis.viewer.dnd.view.DragStart;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAreaType;
+
+public class AbstractBorder extends AbstractViewDecorator {
+ protected int bottom;
+ protected int left;
+ private boolean onBorder;
+ protected int right;
+ protected int top;
+
+ protected AbstractBorder(final View view) {
+ super(view);
+ }
+
+ protected Bounds contentArea() {
+ return new Bounds(getLeft(), getTop(), getSize().getWidth() - getLeft() - getRight(), getSize().getHeight() - getTop() - getBottom());
+ }
+
+ @Override
+ public View dragFrom(final Location location) {
+ location.subtract(getLeft(), getTop());
+ return super.dragFrom(location);
+ }
+
+ @Override
+ public void dragIn(final ContentDrag drag) {
+ drag.subtract(getLeft(), getTop());
+ super.dragIn(drag);
+ }
+
+ @Override
+ public void dragOut(final ContentDrag drag) {
+ drag.subtract(getLeft(), getTop());
+ super.dragOut(drag);
+ }
+
+ @Override
+ public DragEvent dragStart(final DragStart drag) {
+ if (overContent(drag.getLocation())) {
+ drag.subtract(getLeft(), getTop());
+ return super.dragStart(drag);
+ } else {
+ return null;
+ }
+ }
+
+ protected void clearBackground(final Canvas canvas, final Color color) {
+ final Bounds bounds = getView().getBounds();
+ canvas.drawSolidRectangle(0, 0, bounds.getWidth(), bounds.getHeight(), color);
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ if (Toolkit.debug) {
+ canvas.drawDebugOutline(new Bounds(getSize()), getBaseline(), Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_BORDER));
+ }
+ final int width = getSize().getWidth() - getRight();
+ final int height = getSize().getHeight() - getBottom();
+ final Canvas subcanvas = canvas.createSubcanvas(getLeft(), getTop(), width, height);
+ wrappedView.draw(subcanvas);
+ }
+
+ @Override
+ public void drop(final ContentDrag drag) {
+ drag.subtract(getLeft(), getTop());
+ super.drop(drag);
+ }
+
+ @Override
+ public void firstClick(final Click click) {
+ if (overContent(click.getLocation())) {
+ click.subtract(getLeft(), getTop());
+ wrappedView.firstClick(click);
+ }
+ }
+
+ @Override
+ public int getBaseline() {
+ return wrappedView.getBaseline() + getTop();
+ }
+
+ protected int getBottom() {
+ return bottom;
+ }
+
+ protected int getLeft() {
+ return left;
+ }
+
+ @Override
+ public Padding getPadding() {
+ final Padding padding = wrappedView.getPadding();
+ padding.extendTop(getTop());
+ padding.extendLeft(getLeft());
+ padding.extendBottom(getBottom());
+ padding.extendRight(getRight());
+
+ return padding;
+ }
+
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ availableSpace.contract(getLeft() + getRight(), getTop() + getBottom());
+ final Size size = wrappedView.getRequiredSize(availableSpace);
+ size.extend(getLeft() + getRight(), getTop() + getBottom());
+ return size;
+ }
+
+ protected int getRight() {
+ return right;
+ }
+
+ @Override
+ public Size getSize() {
+ final Size size = wrappedView.getSize();
+ size.extend(getLeft() + getRight(), getTop() + getBottom());
+
+ return size;
+ }
+
+ protected int getTop() {
+ return top;
+ }
+
+ @Override
+ protected void debugDetails(final DebugBuilder debug) {
+ super.debugDetails(debug);
+ debug.appendln("border", getTop() + "/" + getBottom() + " " + getLeft() + "/" + getRight() + " (top/bottom left/right)");
+ debug.appendln("contents", contentArea());
+ }
+
+ protected boolean overBorder(final Location location) {
+ return !contentArea().contains(location);
+ }
+
+ protected boolean overContent(final Location location) {
+ return contentArea().contains(location);
+ }
+
+ protected boolean isOnBorder() {
+ return onBorder;
+ }
+
+ @Override
+ public View identify(final Location location) {
+ getViewManager().getSpy().addTrace(this, "mouse location within border", location);
+ getViewManager().getSpy().addTrace(this, "non border area", contentArea());
+
+ if (overBorder(location)) {
+ getViewManager().getSpy().addTrace(this, "over border area", contentArea());
+ return getView();
+ } else {
+ location.add(-getLeft(), -getTop());
+ return super.identify(location);
+ }
+
+ }
+
+ @Override
+ public void mouseDown(final Click click) {
+ if (overContent(click.getLocation())) {
+ click.subtract(getLeft(), getTop());
+ wrappedView.mouseDown(click);
+ }
+ }
+
+ @Override
+ public void mouseMoved(final Location at) {
+ final boolean on = overBorder(at);
+ if (onBorder != on) {
+ markDamaged();
+ onBorder = on;
+ }
+
+ if (!on) {
+ at.move(-getLeft(), -getTop());
+ wrappedView.mouseMoved(at);
+ }
+ }
+
+ @Override
+ public void mouseUp(final Click click) {
+ if (overContent(click.getLocation())) {
+ click.subtract(getLeft(), getTop());
+ wrappedView.mouseUp(click);
+ }
+ }
+
+ @Override
+ public void exited() {
+ onBorder = false;
+ super.exited();
+ }
+
+ @Override
+ public View pickupContent(final Location location) {
+ location.subtract(getLeft(), getTop());
+ return super.pickupContent(location);
+ }
+
+ @Override
+ public View pickupView(final Location location) {
+ if (overBorder(location)) {
+ return Toolkit.getViewFactory().createDragViewOutline(getView());
+ } else {
+ location.subtract(getLeft(), getTop());
+ return super.pickupView(location);
+ }
+ }
+
+ @Override
+ public void secondClick(final Click click) {
+ if (overContent(click.getLocation())) {
+ click.subtract(getLeft(), getTop());
+ wrappedView.secondClick(click);
+ }
+ }
+
+ @Override
+ public void setSize(final Size size) {
+ final Size wrappedViewSize = new Size(size);
+ wrappedViewSize.contract(getLeft() + getRight(), getTop() + getBottom());
+ wrappedView.setSize(wrappedViewSize);
+ }
+
+ @Override
+ public void setBounds(final Bounds bounds) {
+ final Bounds wrappedViewBounds = new Bounds(bounds);
+ wrappedViewBounds.contract(getLeft() + getRight(), getTop() + getBottom());
+ wrappedView.setBounds(wrappedViewBounds);
+ }
+
+ @Override
+ public void thirdClick(final Click click) {
+ if (overContent(click.getLocation())) {
+ click.subtract(getLeft(), getTop());
+ wrappedView.thirdClick(click);
+ }
+ }
+
+ @Override
+ public ViewAreaType viewAreaType(final Location mouseLocation) {
+ final Size size = wrappedView.getSize();
+ final Bounds bounds = new Bounds(getLeft(), getTop(), size.getWidth(), size.getHeight());
+
+ if (bounds.contains(mouseLocation)) {
+ mouseLocation.subtract(getLeft(), getTop());
+
+ return wrappedView.viewAreaType(mouseLocation);
+ } else {
+ return ViewAreaType.VIEW;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFieldSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFieldSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFieldSpecification.java
new file mode 100644
index 0000000..79e098f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFieldSpecification.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.view.base;
+
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+
+public abstract class AbstractFieldSpecification implements ViewSpecification {
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return requirement.isTextParseable() && requirement.isEditable();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return false;
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return true;
+ }
+
+ @Override
+ public boolean isSubView() {
+ return true;
+ }
+
+ @Override
+ public boolean isAligned() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFocusManager.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFocusManager.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFocusManager.java
new file mode 100644
index 0000000..22f5f1f
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractFocusManager.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.base;
+
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.View;
+
+/**
+ * Abstract focus manager that uses the set of views to move focus between from
+ * the concrete subclass.
+ *
+ * @see #getChildViews()
+ */
+public abstract class AbstractFocusManager implements FocusManager {
+ // TODO container to go in subclass ??
+ protected View container;
+ protected View focus;
+ private final View initialFocus;
+
+ public AbstractFocusManager(final View container) {
+ this(container, null);
+ }
+
+ public AbstractFocusManager(final View container, final View initalFocus) {
+ Assert.assertNotNull(container);
+ this.container = container;
+ this.initialFocus = initalFocus;
+ focus = initalFocus;
+ }
+
+ /**
+ * Throws a ObjectAdapterRuntimeException if the specified view is available
+ * to this focus manager.
+ */
+ private void checkCanFocusOn(final View view) {
+ final View[] views = getChildViews();
+ boolean valid = view == container.getView();
+ for (int j = 0; valid == false && j < views.length; j++) {
+ if (views[j] == view) {
+ valid = true;
+ }
+ }
+
+ if (!valid) {
+ // throw new ObjectAdapterRuntimeException("No view " + view +
+ // " to focus on in " +
+ // container.getView());
+ }
+ }
+
+ @Override
+ public void focusFirstChildView() {
+ final View[] views = getChildViews();
+ for (final View view : views) {
+ if (view.canFocus()) {
+ setFocus(view);
+ return;
+ }
+ }
+ // no other focusable view; stick with the view we've got
+ return;
+ }
+
+ @Override
+ public void focusInitialChildView() {
+ if (initialFocus == null) {
+ focusFirstChildView();
+ } else {
+ setFocus(initialFocus);
+ }
+ }
+
+ @Override
+ public void focusLastChildView() {
+ final View[] views = getChildViews();
+ for (int j = views.length - 1; j > 0; j--) {
+ if (views[j].canFocus()) {
+ setFocus(views[j]);
+ return;
+ }
+ }
+ // no other focusable view; stick with the view we've got
+ return;
+ }
+
+ @Override
+ public void focusNextView() {
+ final View[] views = getChildViews();
+ for (int i = 0; i < views.length; i++) {
+ if (testView(views, i)) {
+ for (int j = i + 1; j < views.length; j++) {
+ if (views[j].canFocus()) {
+ setFocus(views[j]);
+ return;
+ }
+ }
+ for (int j = 0; j < i; j++) {
+ if (views[j].canFocus()) {
+ setFocus(views[j]);
+ return;
+ }
+ }
+ // no other focusable view; stick with the view we've got
+ return;
+ }
+ }
+
+ // throw new ObjectAdapterRuntimeException();
+ }
+
+ private boolean testView(final View[] views, final int i) {
+ final View view = views[i];
+ return view == focus;
+ }
+
+ @Override
+ public void focusParentView() {
+ container.getFocusManager().setFocus(container.getFocusManager().getFocus());
+ }
+
+ @Override
+ public void focusPreviousView() {
+ final View[] views = getChildViews();
+ if (views.length > 1) {
+ for (int i = 0; i < views.length; i++) {
+ if (testView(views, i)) {
+ for (int j = i - 1; j >= 0; j--) {
+ if (views[j].canFocus()) {
+ setFocus(views[j]);
+ return;
+ }
+ }
+ for (int j = views.length - 1; j > i; j--) {
+ if (views[j].canFocus()) {
+ setFocus(views[j]);
+ return;
+ }
+ }
+ // no other focusable view; stick with the view we've got
+ return;
+ }
+ }
+
+ // Don't move to any view
+ // throw new
+ // ObjectAdapterRuntimeException("Can't move to previous peer from "
+ // + focus);
+ }
+ }
+
+ protected abstract View[] getChildViews();
+
+ @Override
+ public View getFocus() {
+ return focus;
+ }
+
+ @Override
+ public void setFocus(final View view) {
+ checkCanFocusOn(view);
+
+ if (view != null && view.canFocus()) {
+ if ((focus != null) && (focus != view)) {
+ focus.focusLost();
+ focus.markDamaged();
+ }
+
+ focus = view;
+ focus.focusReceived();
+
+ view.markDamaged();
+ }
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("container", container);
+ str.append("initialFocus", initialFocus);
+ str.append("focus", focus);
+ return str.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractView.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractView.java
new file mode 100644
index 0000000..79ae4eb
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/view/base/AbstractView.java
@@ -0,0 +1,987 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.base;
+
+import java.util.Enumeration;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.ConsentAbstract;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+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.Padding;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.util.Properties;
+import org.apache.isis.viewer.dnd.util.ViewerException;
+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.ContentDrag;
+import org.apache.isis.viewer.dnd.view.DragEvent;
+import org.apache.isis.viewer.dnd.view.DragStart;
+import org.apache.isis.viewer.dnd.view.Feedback;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.InternalDrag;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+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.UndoStack;
+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.ViewAxis;
+import org.apache.isis.viewer.dnd.view.ViewDrag;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.ViewState;
+import org.apache.isis.viewer.dnd.view.Viewer;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.collection.RootCollection;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+import org.apache.isis.viewer.dnd.view.content.RootObject;
+import org.apache.isis.viewer.dnd.view.option.OpenViewOption;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public abstract class AbstractView implements View {
+ private static final Logger LOG = Logger.getLogger(AbstractView.class);
+
+ private static int nextId = 0;
+ private int id = 0;
+ private View parent;
+ private View viewRoot;
+ private ViewSpecification specification;
+ private Content content;
+ private final ViewState state;
+ private int x;
+ private int y;
+ private int height;
+ private int width;
+
+ protected AbstractView(final Content content) {
+ this(content, null);
+ }
+
+ protected AbstractView(final Content content, final ViewSpecification specification) {
+ if (content == null) {
+ throw new IllegalArgumentException("Content not specified");
+ }
+ assignId();
+ this.content = content;
+ this.specification = specification;
+ state = new ViewState();
+ viewRoot = this;
+ }
+
+ @Override
+ public void addView(final View view) {
+ throw new IsisException("Can't add views to " + this);
+ }
+
+ protected void assignId() {
+ id = nextId++;
+ }
+
+ @Override
+ public Consent canChangeValue() {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public boolean canFocus() {
+ return true;
+ }
+
+ @Override
+ public boolean contains(final View view) {
+ final View[] subviews = getSubviews();
+ for (final View subview : subviews) {
+ if (subview == view || (subview != null && subview.contains(view))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean containsFocus() {
+ if (hasFocus()) {
+ return true;
+ }
+
+ final View[] subviews = getSubviews();
+ for (final View subview : subviews) {
+ if (subview != null && subview.containsFocus()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_CONTENT));
+
+ final Content content = getContent();
+ if (content != null) {
+ content.contentMenuOptions(options);
+ }
+ }
+
+ /**
+ * Returns debug details about this view.
+ */
+ @Override
+ public void debug(final DebugBuilder debug) {
+ final String name = getClass().getName();
+ debug.appendln("Root: " + name.substring(name.lastIndexOf('.') + 1) + getId());
+ debug.indent();
+ debug.appendln("required size", getRequiredSize(Size.createMax()));
+ debug.appendln("given size", getSize());
+ debug.appendln("padding", getPadding());
+ debug.appendln("base line", getBaseline());
+ debug.unindent();
+ debug.appendln();
+
+ debug.appendTitle("Specification");
+ if (specification == null) {
+ debug.append("\none");
+ } else {
+ debug.appendln(specification.getName());
+ debug.appendln(" " + specification.getClass().getName());
+ debug.appendln(" " + (specification.isOpen() ? "open" : "closed"));
+ debug.appendln(" " + (specification.isReplaceable() ? "replaceable" : "non-replaceable"));
+ debug.appendln(" " + (specification.isSubView() ? "subview" : "main view"));
+ }
+
+ debug.appendln();
+ debug.appendTitle("View");
+
+ debug.appendln("Self", getView());
+ debug.appendln("Parent's size", getParent() == null ? new Size() : getParent().getSize());
+ debug.appendln("Size w/in parent", getView().getRequiredSize(getParent() == null ? new Size() : getParent().getSize()));
+ debug.appendln("Location w/in parent", getView().getLocation());
+ debug.appendln("Changable", canChangeValue());
+ debug.appendln("Focus", (canFocus() ? "focusable" : "non-focusable"));
+ debug.appendln("Has focus", hasFocus());
+ debug.appendln("Contains focus", containsFocus());
+ debug.appendln("Focus manager", getFocusManager());
+ debug.appendln("State", getState());
+ debug.appendln("Axes", getViewAxes());
+ appendDebug(debug);
+
+ debug.appendln("Workspace", getWorkspace());
+
+ View p = getParent();
+ debug.appendln("Parent hierarchy:" + (p == null ? "none" : ""));
+ debug.indent();
+ while (p != null) {
+ debug.appendln(p.toString());
+ p = p.getParent();
+ }
+ debug.unindent();
+
+ debug.appendln();
+ debug.appendln();
+ debug.appendln();
+
+ debug.appendTitle("View structure");
+ // b.appendln("Built", (buildInvalid ? "no" : "yes") + ", " + buildCount
+ // + " builds");
+ // b.appendln("Laid out", (layoutInvalid ? "no" : "yes") + ", " +
+ // layoutCount + " layouts");
+
+ debug.appendln(getSpecification().getName().toUpperCase());
+ debugStructure(debug);
+ }
+
+ protected void appendDebug(final DebugBuilder debug) {
+ }
+
+ @Override
+ public void debugStructure(final DebugBuilder b) {
+ b.appendln("Content", getContent() == null ? "none" : getContent());
+ b.appendln("Required size ", getRequiredSize(Size.createMax()));
+ b.appendln("Bounds", getBounds());
+ b.appendln("Baseline", getBaseline());
+ b.appendln("Location", getAbsoluteLocation());
+ final View views[] = getSubviews();
+ b.indent();
+ for (final View subview : views) {
+ b.appendln();
+ final ViewSpecification spec = subview.getSpecification();
+ b.appendln(spec == null ? "none" : spec.getName().toUpperCase());
+ b.appendln("View", subview);
+ subview.debugStructure(b);
+ }
+ b.unindent();
+ }
+
+ @Override
+ public void dispose() {
+ final View parent = getParent();
+ if (parent != null) {
+ parent.removeView(getView());
+ }
+ }
+
+ @Override
+ public void drag(final InternalDrag drag) {
+ }
+
+ @Override
+ public void drag(final ContentDrag contentDrag) {
+ }
+
+ @Override
+ public void drag(final ViewDrag drag) {
+ getViewManager().getSpy().addTrace(this, "view drag", drag);
+ }
+
+ @Override
+ public void dragCancel(final InternalDrag drag) {
+ getFeedbackManager().showDefaultCursor();
+ }
+
+ @Override
+ public View dragFrom(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview != null) {
+ location.subtract(subview.getLocation());
+ return subview.dragFrom(location);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void dragIn(final ContentDrag drag) {
+ }
+
+ @Override
+ public void dragOut(final ContentDrag drag) {
+ }
+
+ @Override
+ public DragEvent dragStart(final DragStart drag) {
+ final View subview = subviewFor(drag.getLocation());
+ if (subview != null) {
+ drag.subtract(subview.getLocation());
+ return subview.dragStart(drag);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void dragTo(final InternalDrag drag) {
+ }
+
+ /**
+ * Clears the background of this view to the given color (call from the
+ * {@link #draw(Canvas)} method.
+ */
+ protected void clearBackground(final Canvas canvas, final Color color) {
+ final Bounds bounds = getBounds();
+ canvas.drawSolidRectangle(0, 0, bounds.getWidth(), bounds.getHeight(), color);
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ if (Toolkit.debug) {
+ canvas.drawDebugOutline(new Bounds(getSize()), getBaseline(), Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_VIEW));
+ }
+ }
+
+ @Override
+ public void drop(final ContentDrag drag) {
+ }
+
+ /**
+ * No default behaviour, views can only be dropped on workspace
+ */
+ @Override
+ public void drop(final ViewDrag drag) {
+ getParent().drop(drag);
+ }
+
+ @Override
+ public void editComplete(final boolean moveFocus, final boolean toNextField) {
+ }
+
+ @Override
+ public void entered() {
+ final Content cont = getContent();
+ if (cont != null) {
+ final String description = cont.getDescription();
+ if (description != null && !"".equals(description)) {
+ getFeedbackManager().setViewDetail(description);
+ }
+ }
+ }
+
+ @Override
+ public void exited() {
+ }
+
+ @Override
+ public void firstClick(final Click click) {
+ final View subview = subviewFor(click.getLocation());
+ if (subview != null) {
+ click.subtract(subview.getLocation());
+ subview.firstClick(click);
+ }
+ }
+
+ @Override
+ public void focusLost() {
+ }
+
+ @Override
+ public void focusReceived() {
+ }
+
+ @Override
+ public Location getAbsoluteLocation() {
+ final View parent = getParent();
+ if (parent == null) {
+ return getLocation();
+ } else {
+ final Location location = parent.getAbsoluteLocation();
+ getViewManager().getSpy().addTrace(this, "parent location", location);
+ location.add(x, y);
+ getViewManager().getSpy().addTrace(this, "plus view's location", location);
+ final Padding pad = parent.getPadding();
+ location.add(pad.getLeft(), pad.getTop());
+ getViewManager().getSpy().addTrace(this, "plus view's padding", location);
+ return location;
+ }
+ }
+
+ @Override
+ public int getBaseline() {
+ return 0;
+ }
+
+ @Override
+ public Bounds getBounds() {
+ return new Bounds(x, y, width, height);
+ }
+
+ @Override
+ public Content getContent() {
+ return content;
+ }
+
+ @Override
+ public FocusManager getFocusManager() {
+ return getParent() == null ? null : getParent().getFocusManager();
+ }
+
+ @Override
+ public int getId() {
+ return id;
+ }
+
+ @Override
+ public Location getLocation() {
+ return new Location(x, y);
+ }
+
+ @Override
+ public Padding getPadding() {
+ return new Padding(0, 0, 0, 0);
+ }
+
+ @Override
+ public final View getParent() {
+ // Assert.assertEquals(parent == null ? null : parent.getView(),
+ // parent);
+ // return parent;
+
+ return parent == null ? null : parent.getView();
+ }
+
+ @Override
+ public Size getRequiredSize(final Size maximumSize) {
+ return new Size(maximumSize);
+ }
+
+ @Override
+ public Size getSize() {
+ return new Size(width, height);
+ }
+
+ @Override
+ public ViewSpecification getSpecification() {
+ if (specification == null) {
+ specification = new NonBuildingSpecification(this);
+ }
+ return specification;
+ }
+
+ @Override
+ public ViewState getState() {
+ return state;
+ }
+
+ @Override
+ public View[] getSubviews() {
+ return new View[0];
+ }
+
+ @Override
+ public final View getView() {
+ return viewRoot;
+ }
+
+ @Override
+ public Axes getViewAxes() {
+ return new Axes();
+ }
+
+ @Override
+ public Viewer getViewManager() {
+ return Toolkit.getViewer();
+ }
+
+ @Override
+ public Feedback getFeedbackManager() {
+ return Toolkit.getFeedbackManager();
+ }
+
+ @Override
+ public Workspace getWorkspace() {
+ return getParent() == null ? null : getParent().getWorkspace();
+ }
+
+ @Override
+ public boolean hasFocus() {
+ return getViewManager().hasFocus(getView());
+ }
+
+ @Override
+ public View identify(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview == null) {
+ getViewManager().getSpy().addTrace(this, "mouse location within node view", location);
+ getViewManager().getSpy().addTrace("----");
+ return getView();
+ } else {
+ location.subtract(subview.getLocation());
+ return subview.identify(location);
+ }
+ }
+
+ @Override
+ public void invalidateContent() {
+ }
+
+ @Override
+ public void invalidateLayout() {
+ final View parent = getParent();
+ if (parent != null) {
+ parent.invalidateLayout();
+ }
+ }
+
+ @Override
+ public void keyPressed(final KeyboardAction key) {
+ }
+
+ @Override
+ public void keyReleased(final KeyboardAction action) {
+ }
+
+ @Override
+ public void keyTyped(final KeyboardAction action) {
+ }
+
+ @Override
+ public void layout() {
+ }
+
+ /**
+ * Limits the bounds of the this view (when being moved or dropped) so it
+ * never extends outside the specified bounds e.g. outside of a parent view
+ */
+ public void limitBoundsWithin(final Bounds containerBounds) {
+ final Bounds contentBounds = getView().getBounds();
+ if (containerBounds.limitBounds(contentBounds)) {
+ getView().setBounds(contentBounds);
+ }
+ }
+
+ @Override
+ public void limitBoundsWithin(final Size size) {
+ final int w = getView().getSize().getWidth();
+ final int h = getView().getSize().getHeight();
+
+ int x = getView().getLocation().getX();
+ int y = getView().getLocation().getY();
+
+ if (x + w > size.getWidth()) {
+ x = size.getWidth() - w;
+ }
+ if (x < 0) {
+ x = 0;
+ }
+
+ if (y + h > size.getHeight()) {
+ y = size.getHeight() - h;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+
+ getView().setLocation(new Location(x, y));
+ }
+
+ @Override
+ public void markDamaged() {
+ markDamaged(getView().getBounds());
+ }
+
+ @Override
+ public void markDamaged(final Bounds bounds) {
+ final View parent = getParent();
+ if (parent == null) {
+ getViewManager().markDamaged(bounds);
+ } else {
+ final Location pos = parent.getLocation();
+ bounds.translate(pos.getX(), pos.getY());
+ final Padding pad = parent.getPadding();
+ bounds.translate(pad.getLeft(), pad.getTop());
+ parent.markDamaged(bounds);
+ }
+ }
+
+ @Override
+ public void mouseDown(final Click click) {
+ final View subview = subviewFor(click.getLocation());
+ if (subview != null) {
+ click.subtract(subview.getLocation());
+ subview.mouseDown(click);
+ }
+ }
+
+ @Override
+ public void mouseMoved(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview != null) {
+ location.subtract(subview.getLocation());
+ subview.mouseMoved(location);
+ }
+ }
+
+ @Override
+ public void mouseUp(final Click click) {
+ final View subview = subviewFor(click.getLocation());
+ if (subview != null) {
+ click.subtract(subview.getLocation());
+ subview.mouseUp(click);
+ }
+ }
+
+ @Override
+ public void objectActionResult(final ObjectAdapter result, final Placement placement) {
+ if (result != null) {
+ final CollectionFacet facet = result.getSpecification().getFacet(CollectionFacet.class);
+ ObjectAdapter objectToDisplay = result;
+ if (facet != null) {
+ if (facet.size(result) == 1) {
+ objectToDisplay = facet.firstElement(result);
+ }
+ }
+ getWorkspace().addWindowFor(objectToDisplay, placement);
+ }
+ }
+
+ @Override
+ public View pickupContent(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview != null) {
+ location.subtract(subview.getLocation());
+ return subview.pickupView(location);
+ } else {
+ return Toolkit.getViewFactory().createDragViewOutline(getView());
+ }
+ }
+
+ @Override
+ public View pickupView(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview != null) {
+ location.subtract(subview.getLocation());
+ return subview.pickupView(location);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Delegates all printing the the draw method.
+ *
+ * @see #draw(Canvas)
+ */
+ @Override
+ public void print(final Canvas canvas) {
+ draw(canvas);
+ }
+
+ @Override
+ public void refresh() {
+ }
+
+ @Override
+ public void removeView(final View view) {
+ throw new IsisException();
+ }
+
+ @Override
+ public void replaceView(final View toReplace, final View replacement) {
+ throw new IsisException();
+ }
+
+ @Override
+ public void secondClick(final Click click) {
+ final View subview = subviewFor(click.getLocation());
+ if (subview != null) {
+ click.subtract(subview.getLocation());
+ subview.secondClick(click);
+ }
+ }
+
+ /**
+ * Sets the location and size view the {@link #setLocation(Location)) and
+ * {@link #setSize(Size)) methods.
+ */
+ @Override
+ public void setBounds(final Bounds bounds) {
+ setLocation(bounds.getLocation());
+ setSize(bounds.getSize());
+ }
+
+ @Override
+ public void setFocusManager(final FocusManager focusManager) {
+ }
+
+ protected void setContent(final Content content) {
+ this.content = content;
+ }
+
+ @Override
+ public void setLocation(final Location location) {
+ x = location.getX();
+ y = location.getY();
+ }
+
+ @Override
+ public final void setParent(final View parentView) {
+ LOG.debug("set parent " + parentView + " for " + this);
+ parent = parentView.getView();
+ }
+
+ public void setMaximumSize(final Size size) {
+ }
+
+ @Override
+ public void setSize(final Size size) {
+ width = size.getWidth();
+ height = size.getHeight();
+ }
+
+ protected void setSpecification(final ViewSpecification specification) {
+ this.specification = specification;
+ }
+
+ @Override
+ public final void setView(final View view) {
+ this.viewRoot = view;
+ }
+
+ @Deprecated
+ protected void setViewAxis(final ViewAxis viewAxis) {
+ // this.viewAxis = viewAxis;
+ }
+
+ @Override
+ public View subviewFor(final Location location) {
+ return null;
+ }
+
+ @Override
+ public void thirdClick(final Click click) {
+ final View subview = subviewFor(click.getLocation());
+ if (subview != null) {
+ click.subtract(subview.getLocation());
+ subview.thirdClick(click);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final String name = getClass().getName();
+ return name.substring(name.lastIndexOf('.') + 1) + getId() + ":" + getState() + ":" + getContent();
+ }
+
+ @Override
+ public void update(final ObjectAdapter object) {
+ }
+
+ @Override
+ public void updateView() {
+ }
+
+ @Override
+ public ViewAreaType viewAreaType(final Location location) {
+ final View subview = subviewFor(location);
+ if (subview != null) {
+ location.subtract(subview.getLocation());
+ return subview.viewAreaType(location);
+ } else {
+ return ViewAreaType.CONTENT;
+ }
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_VIEW));
+
+ final Content content = getContent();
+ addContentMenuItems(options, content);
+ addNewViewMenuItems(options, content);
+
+ // TODO ask the viewer for the print option - provided by the underlying
+ // system
+ // options.add(new PrintOption());
+
+ addViewDebugMenuItems(options);
+
+ final UndoStack undoStack = getViewManager().getUndoStack();
+ if (!undoStack.isEmpty()) {
+ options.add(new UserActionAbstract("Undo " + undoStack.getNameOfUndo()) {
+
+ @Override
+ public Consent disabled(final View component) {
+ return new ConsentAbstract("", undoStack.descriptionOfUndo()) {
+ private static final long serialVersionUID = 1L;
+ };
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ undoStack.undoLastCommand();
+ }
+ });
+ }
+ }
+
+ private void addViewDebugMenuItems(final UserActionSet options) {
+ options.add(new UserActionAbstract("Refresh view", ActionType.DEBUG) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ refresh();
+ }
+ });
+
+ options.add(new UserActionAbstract("Invalidate content", ActionType.DEBUG) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ invalidateContent();
+ }
+ });
+
+ options.add(new UserActionAbstract("Invalidate layout", ActionType.DEBUG) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ invalidateLayout();
+ }
+ });
+ }
+
+ private void addNewViewMenuItems(final UserActionSet options, final Content content) {
+ if (getContent() instanceof ObjectContent) {
+ options.add(new UserActionAbstract("Use as default view for objects", ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ Properties.setStringOption("view.object-default", getSpecification().getName());
+ /*
+ * Options viewOptions =
+ * Properties.getViewConfigurationOptions
+ * (getSpecification()); getView().saveOptions(viewOptions);
+ */
+ }
+ });
+ }
+ if (getContent() instanceof CollectionContent) {
+ options.add(new UserActionAbstract("Use as default view for collection", ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ Properties.setStringOption("view.collection-default", getSpecification().getName());
+ /*
+ * Options viewOptions =
+ * Properties.getViewConfigurationOptions
+ * (getSpecification()); getView().saveOptions(viewOptions);
+ */
+ }
+ });
+ }
+ if (getContent() instanceof ObjectContent && !getSpecification().isOpen()) {
+ options.add(new UserActionAbstract("Use as default view for icon", ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ Properties.setStringOption("view.icon-default", getSpecification().getName());
+ /*
+ * Options viewOptions =
+ * Properties.getViewConfigurationOptions
+ * (getSpecification()); getView().saveOptions(viewOptions);
+ */
+ }
+ });
+ }
+
+ if (getContent() instanceof RootObject || getContent() instanceof RootCollection) {
+ options.add(new UserActionAbstract("Use as default view for " + getContent().getSpecification().getSingularName(), ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final Options viewOptions = Properties.getViewConfigurationOptions(getSpecification());
+ getView().saveOptions(viewOptions);
+
+ // Options viewOptions =
+ final ObjectSpecification specification = content.getSpecification();
+ final Options settingsOptions = Properties.getDefaultViewOptions(specification);
+ settingsOptions.addOption("spec", getSpecification().getName());
+ }
+ });
+ }
+ /*
+ * options.add(new UserActionAbstract("Create new specification",
+ * UserAction.USER) { // TODO probably needs to be a replace with new
+ * view specification public void execute(final Workspace workspace,
+ * final View view, final Location at) { UserViewSpecification newSpec =
+ * new UserViewSpecification(getView()); Options viewOptions =
+ * Properties.getViewConfigurationOptions(newSpec);
+ * getView().saveOptions(viewOptions);
+ *
+ * viewOptions = Properties.getUserViewSpecificationOptions(newSpec);
+ * viewOptions.addOption("wrapped-specification",
+ * getSpecification().getClass().getName());
+ *
+ * Toolkit.getViewFactory().addSpecification(newSpec); } });
+ */
+ options.add(new UserActionAbstract("Save specification", ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final Options viewOptions = Properties.getViewConfigurationOptions(getSpecification());
+ getView().saveOptions(viewOptions);
+
+ Toolkit.getViewFactory().addSpecification(getSpecification());
+ }
+ });
+ createOpenAsSubmenu(options, content);
+
+ createCreateViewSubmenu(options, content);
+ }
+
+ private void createOpenAsSubmenu(final UserActionSet options, final Content content) {
+ final ViewRequirement requirements = new ViewRequirement(content, ViewRequirement.OPEN | ViewRequirement.EXPANDABLE);
+ final Enumeration possibleViews = Toolkit.getViewFactory().availableViews(requirements);
+ if (possibleViews.hasMoreElements()) {
+ final UserActionSet submenu = options.addNewActionSet("Open as");
+ while (possibleViews.hasMoreElements()) {
+ final ViewSpecification specification = (ViewSpecification) possibleViews.nextElement();
+ final UserActionAbstract viewAs = new OpenViewOption(specification);
+ submenu.add(viewAs);
+ }
+ }
+ }
+
+ private void createCreateViewSubmenu(final UserActionSet options, final Content content) {
+ final ViewRequirement requirements = new ViewRequirement(content, ViewRequirement.OPEN);
+ final Enumeration possibleViews = Toolkit.getViewFactory().availableDesigns(requirements);
+ if (possibleViews.hasMoreElements()) {
+ final UserActionSet submenu = options.addNewActionSet("Create view from");
+ while (possibleViews.hasMoreElements()) {
+ final ViewSpecification specification = (ViewSpecification) possibleViews.nextElement();
+ final UserActionAbstract viewAs = new UserActionAbstract(specification.getName(), ActionType.USER) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ ViewSpecification newSpec;
+ try {
+ newSpec = specification.getClass().newInstance();
+ } catch (final InstantiationException e) {
+ throw new ViewerException(e);
+ } catch (final IllegalAccessException e) {
+ throw new ViewerException(e);
+ }
+
+ Content content = view.getContent();
+ if (!(content instanceof FieldContent)) {
+ content = Toolkit.getContentFactory().createRootContent(content.getAdapter());
+ }
+ final View newView = newSpec.createView(content, view.getViewAxes(), -1);
+ LOG.debug("open view " + newView);
+ workspace.addWindow(newView, new Placement(view));
+ workspace.markDamaged();
+
+ Options viewOptions = Properties.getViewConfigurationOptions(newSpec);
+ newView.saveOptions(viewOptions);
+ viewOptions = Properties.getUserViewSpecificationOptions(newSpec.getName());
+ viewOptions.addOption("design", specification.getClass().getName());
+
+ Toolkit.getViewFactory().addSpecification(newSpec);
+ }
+ };
+
+ submenu.add(viewAs);
+ }
+ }
+ }
+
+ private void addContentMenuItems(final UserActionSet options, final Content content) {
+ if (content != null) {
+ content.viewMenuOptions(options);
+ }
+ }
+
+ @Override
+ public void loadOptions(final Options viewOptions) {
+ }
+
+ @Override
+ public void saveOptions(final Options viewOptions) {
+ // viewOptions.addOption("spec",
+ // getSpecification().getClass().getName());
+ }
+}