You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2012/12/06 18:42:18 UTC
[47/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/interaction/DragStartImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragStartImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragStartImpl.java
new file mode 100644
index 0000000..e825fc2
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/DragStartImpl.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Offset;
+import org.apache.isis.viewer.dnd.view.DragStart;
+
+public class DragStartImpl extends PointerEvent implements DragStart {
+ private final Location location;
+
+ public DragStartImpl(final Location location, final int mods) {
+ super(mods);
+ this.location = location;
+ }
+
+ @Override
+ public Location getLocation() {
+ return location;
+ }
+
+ @Override
+ public void subtract(final Location location) {
+ this.location.subtract(location);
+ }
+
+ @Override
+ public void subtract(final int x, final int y) {
+ location.subtract(x, y);
+ }
+
+ public void add(final Offset offset) {
+ location.add(offset.getDeltaX(), offset.getDeltaY());
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("location", location);
+ str.append("buttons", super.toString());
+ 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/interaction/KeyboardActionImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/KeyboardActionImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/KeyboardActionImpl.java
new file mode 100644
index 0000000..7fcab94
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/KeyboardActionImpl.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+
+public class KeyboardActionImpl implements KeyboardAction {
+
+ final int keyCode;
+ final int modifiers;
+ private boolean isConsumed;
+
+ public KeyboardActionImpl(final int keyCode, final int modifiers) {
+ this.keyCode = keyCode;
+ this.modifiers = modifiers;
+ isConsumed = false;
+ }
+
+ @Override
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ @Override
+ public char getKeyChar() {
+ return (char) keyCode;
+ }
+
+ @Override
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ @Override
+ public boolean isConsumed() {
+ return isConsumed;
+ }
+
+ @Override
+ public void consume() {
+ isConsumed = true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/PointerEvent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/PointerEvent.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/PointerEvent.java
new file mode 100644
index 0000000..8367021
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/PointerEvent.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import java.awt.event.InputEvent;
+
+/**
+ * Details an event involving the pointer, such as a click or drag.
+ */
+public abstract class PointerEvent {
+ protected int mods;
+
+ /**
+ * Creates a new pointer event object.
+ *
+ * @param mods
+ * the button and key modifiers (@see java.awt.event.MouseEvent)
+ */
+ PointerEvent(final int mods) {
+ this.mods = mods;
+ }
+
+ public boolean button1() {
+ return (isButton1() && !isShift()) || (isButton2() && isShift());
+ }
+
+ public boolean button2() {
+ return (isButton2() && !isShift()) || (isButton1() && isShift());
+ }
+
+ public boolean button3() {
+ return isButton3();
+ }
+
+ /**
+ * Returns true if the 'Alt' key is depressed
+ */
+ public boolean isAlt() {
+ return (mods & InputEvent.ALT_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the left-hand button on the mouse is depressed
+ */
+ private boolean isButton1() {
+ return (mods & InputEvent.BUTTON1_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the middle button on the mouse is depressed
+ */
+ private boolean isButton2() {
+ return (mods & InputEvent.BUTTON2_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the right-hand button on the mouse is depressed
+ */
+ private boolean isButton3() {
+ return (mods & InputEvent.BUTTON3_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the control key is depressed
+ */
+ public boolean isCtrl() {
+ return (mods & InputEvent.CTRL_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the 'Alt' key is depressed
+ */
+ public boolean isMeta() {
+ return (mods & InputEvent.META_MASK) > 0;
+ }
+
+ /**
+ * Returns true if the shift key is depressed
+ */
+ public boolean isShift() {
+ return (mods & InputEvent.SHIFT_MASK) > 0;
+ }
+
+ @Override
+ public String toString() {
+ final String buttons = (isButton1() ? "^" : "-") + (isButton2() ? "^" : "-") + (isButton3() ? "^" : "-");
+ final String modifiers = (isShift() ? "S" : "-") + (isAlt() ? "A" : "-") + (isCtrl() ? "C" : "-");
+
+ return "buttons=" + buttons + ",modifiers=" + modifiers;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/SimpleInternalDrag.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/SimpleInternalDrag.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/SimpleInternalDrag.java
new file mode 100644
index 0000000..3a3e418
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/SimpleInternalDrag.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Offset;
+import org.apache.isis.viewer.dnd.drawing.Padding;
+import org.apache.isis.viewer.dnd.view.InternalDrag;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Viewer;
+
+public class SimpleInternalDrag extends DragImpl implements InternalDrag {
+ private final Location location;
+ // TODO replace Location with Offset
+ private final Location offset;
+ private final View view;
+
+ /**
+ * Creates a new drag event. The source view has its pickup(), and then,
+ * exited() methods called on it. The view returned by the pickup method
+ * becomes this event overlay view, which is moved continuously so that it
+ * tracks the pointer,
+ *
+ * @param view
+ * the view over which the pointer was when this event started
+ * @param location
+ * the location within the viewer (the Frame/Applet/Window etc)
+ *
+ * TODO combine the two constructors
+ */
+ public SimpleInternalDrag(final View view, final Location location) {
+ this.view = view;
+
+ this.location = new Location(location);
+ offset = view.getAbsoluteLocation();
+
+ final Padding targetPadding = view.getPadding();
+ final Padding containerPadding = view.getView().getPadding();
+ offset.add(containerPadding.getLeft() - targetPadding.getLeft(), containerPadding.getTop() - targetPadding.getTop());
+
+ this.location.subtract(offset);
+ }
+
+ public SimpleInternalDrag(final View view, final Offset off) {
+ this.view = view;
+
+ location = new Location();
+
+ offset = new Location(off.getDeltaX(), off.getDeltaY());
+
+ final Padding targetPadding = view.getPadding();
+ final Padding containerPadding = view.getView().getPadding();
+ offset.add(containerPadding.getLeft() - targetPadding.getLeft(), containerPadding.getTop() - targetPadding.getTop());
+
+ this.location.subtract(offset);
+ }
+
+ @Override
+ public void cancel(final Viewer viewer) {
+ view.dragCancel(this);
+ }
+
+ @Override
+ public void drag(final View target, final Location location, final int mods) {
+ this.location.setX(location.getX());
+ this.location.setY(location.getY());
+ this.location.subtract(offset);
+ view.drag(this);
+ }
+
+ @Override
+ public void end(final Viewer viewer) {
+ view.dragTo(this);
+ }
+
+ /**
+ * Gets the location of the pointer relative to the view.
+ */
+ @Override
+ public Location getLocation() {
+ return new Location(location);
+ }
+
+ @Override
+ public View getOverlay() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ final ToString s = new ToString(this, super.toString());
+ s.append("location", location);
+ s.append("relative", getLocation());
+ return s.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ViewDragImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ViewDragImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ViewDragImpl.java
new file mode 100644
index 0000000..9bf31e8
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/interaction/ViewDragImpl.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.interaction;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Offset;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewDrag;
+import org.apache.isis.viewer.dnd.view.Viewer;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class ViewDragImpl extends DragImpl implements ViewDrag {
+ private Location location;
+ /**
+ * Offset from the view's top-left corner to the pointer (relative to the
+ * view).
+ */
+ private final Offset overlayOffset;
+ private final View sourceView;
+ private final View overlayView;
+ private View targetView;
+ private final Workspace viewsWorkspace;
+
+ /**
+ * Creates a new drag event. The source view has its pickup(), and then,
+ * exited() methods called on it. The view returned by the pickup method
+ * becomes this event overlay view, which is moved continuously so that it
+ * tracks the pointer.
+ *
+ * @param view
+ * the view over which the pointer was when this event started
+ */
+ public ViewDragImpl(final View view, final Offset offset, final View dragView) {
+ this.sourceView = view;
+ this.overlayView = dragView;
+ this.overlayOffset = offset;
+
+ viewsWorkspace = view.getWorkspace();
+ }
+
+ /**
+ * getView().getAbsoluteLocation().getX(),
+ * -getView().getAbsoluteLocation().getY() Cancel drag by changing cursor
+ * back to pointer.
+ */
+ @Override
+ public void cancel(final Viewer viewer) {
+ getSourceView().getFeedbackManager().showDefaultCursor();
+ }
+
+ /**
+ * Moves the overlay view so it follows the pointer
+ */
+ protected void drag(final Viewer viewer) {
+ if (overlayView != null) {
+ overlayView.markDamaged();
+ updateDraggingLocation();
+ overlayView.markDamaged();
+ }
+ }
+
+ @Override
+ public void drag(final View target, final Location location, final int mods) {
+ this.location = location;
+ if (overlayView != null) {
+ overlayView.markDamaged();
+ updateDraggingLocation();
+ // this.location.subtract(target.getAbsoluteLocation());
+ viewsWorkspace.getViewManager().getSpy().addTrace(target, " over", getLocation());
+ targetView = target;
+ target.drag(this);
+ overlayView.markDamaged();
+ }
+ }
+
+ /**
+ * Ends the drag by calling drop() on the workspace.
+ */
+ @Override
+ public void end(final Viewer viewer) {
+ viewer.clearAction();
+ targetView.drop(this);
+ }
+
+ @Override
+ public View getOverlay() {
+ return overlayView;
+ }
+
+ @Override
+ public Location getLocation() {
+ return location;
+ }
+
+ @Override
+ public View getSourceView() {
+ return sourceView;
+ }
+
+ @Override
+ public Location getViewDropLocation() {
+ final Location viewLocation = new Location(location);
+ viewLocation.subtract(overlayOffset);
+ return viewLocation;
+ }
+
+ public void subtract(final Location location) {
+ location.subtract(location);
+ }
+
+ @Override
+ public String toString() {
+ return "ViewDrag [" + super.toString() + "]";
+ }
+
+ private void updateDraggingLocation() {
+ final Location viewLocation = new Location(location);
+ viewLocation.subtract(overlayOffset);
+ overlayView.setLocation(viewLocation);
+ overlayView.limitBoundsWithin(viewsWorkspace.getSize());
+ }
+
+ @Override
+ public void subtract(final int x, final int y) {
+ location.subtract(x, y);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionBorder.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionBorder.java
new file mode 100644
index 0000000..9ea2cc5
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionBorder.java
@@ -0,0 +1,128 @@
+/*
+ * 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.list;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+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.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Placement;
+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.ViewState;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.base.IconGraphic;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+import org.apache.isis.viewer.dnd.view.field.OneToManyField;
+
+public class InternalCollectionBorder extends AbstractBorder {
+ public static class Factory implements CompositeViewDecorator {
+ @Override
+ public View decorate(final View child, final Axes axes) {
+ return new InternalCollectionBorder(child);
+ }
+ }
+
+ private final IconGraphic icon;
+
+ protected InternalCollectionBorder(final View wrappedView) {
+ super(wrappedView);
+
+ icon = new InternalCollectionIconGraphic(this, Toolkit.getText(ColorsAndFonts.TEXT_NORMAL));
+ left = icon.getSize().getWidth();
+ }
+
+ @Override
+ protected void debugDetails(final DebugBuilder debug) {
+ debug.append("InternalCollectionBorder ");
+ }
+
+ @Override
+ public Size getRequiredSize(final Size maximumSize) {
+ final Size size = super.getRequiredSize(maximumSize);
+ size.ensureWidth(left + 45 + right);
+ size.ensureHeight(24);
+ return size;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ icon.draw(canvas, 0, getBaseline());
+
+ final ObjectAdapter collection = getContent().getAdapter();
+ final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
+ final ViewState state = getState();
+ final Color color;
+ if (state.canDrop()) {
+ color = Toolkit.getColor(ColorsAndFonts.COLOR_VALID);
+ } else if (state.cantDrop()) {
+ color = Toolkit.getColor(ColorsAndFonts.COLOR_INVALID);
+ } else {
+ color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2);
+ }
+ if (collection == null || facet.size(collection) == 0) {
+ canvas.drawText("empty", left, getBaseline(), color, Toolkit.getText(ColorsAndFonts.TEXT_NORMAL));
+ } else {
+ final int x = icon.getSize().getWidth() / 2;
+ final int x2 = x + 4;
+ final int y = icon.getSize().getHeight() + 1;
+ final int y2 = getSize().getHeight() - 5;
+ canvas.drawLine(x, y, x, y2, color);
+ canvas.drawLine(x, y2, x2, y2, color);
+ }
+ super.draw(canvas);
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ super.contentMenuOptions(options);
+ // final ObjectSpecification specification = ((OneToManyField)
+ // getContent()).getSpecification();
+ // OptionFactory.addCreateOptions(specification, options);
+ }
+
+ @Override
+ public void objectActionResult(final ObjectAdapter result, final Placement placement) {
+ // same as in TreeNodeBorder
+ final OneToManyField internalCollectionContent = (OneToManyField) getContent();
+ final OneToManyAssociation field = internalCollectionContent.getOneToManyAssociation();
+ final ObjectAdapter target = ((ObjectContent) getParent().getContent()).getObject();
+
+ final Consent valid = field.isValidToAdd(target, result);
+ if (valid.isAllowed()) {
+ field.addElement(target, result);
+ }
+ super.objectActionResult(result, placement);
+ }
+
+ @Override
+ public String toString() {
+ return "InternalCollectionBorder/" + wrappedView;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionIconGraphic.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionIconGraphic.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionIconGraphic.java
new file mode 100644
index 0000000..737ace8
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalCollectionIconGraphic.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.list;
+
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.base.IconGraphic;
+
+public class InternalCollectionIconGraphic extends IconGraphic {
+
+ public InternalCollectionIconGraphic(final View view, final Text text) {
+ super(view, text);
+ }
+
+ /*
+ * protected Image iconPicture(ObjectAdapter object) { final
+ * InternalCollection cls = (InternalCollection) object; final
+ * ObjectSpecification spec = cls.getElementSpecification(); Image icon =
+ * loadIcon(spec, ""); if(icon == null) { icon = loadIcon(spec, ""); }
+ * return icon; }
+ */
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalListSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalListSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalListSpecification.java
new file mode 100644
index 0000000..77f4229
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/InternalListSpecification.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.list;
+
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+
+public class InternalListSpecification extends SimpleListSpecification {
+
+ public InternalListSpecification() {
+ addViewDecorator(new InternalCollectionBorder.Factory());
+ }
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return super.canDisplay(requirement) && requirement.is(ViewRequirement.SUBVIEW);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/SimpleListSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/SimpleListSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/SimpleListSpecification.java
new file mode 100644
index 0000000..b3d0bef
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/list/SimpleListSpecification.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.list;
+
+import org.apache.isis.viewer.dnd.icon.IconElementFactory;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.composite.AbstractCollectionViewSpecification;
+
+// TODO use the superclass instead
+public class SimpleListSpecification extends AbstractCollectionViewSpecification {
+
+ @Override
+ protected ViewFactory createElementFactory() {
+ return new IconElementFactory();
+ }
+
+ @Override
+ public String getName() {
+ return "List";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/PerspectiveContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/PerspectiveContent.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/PerspectiveContent.java
new file mode 100644
index 0000000..47ad1aa
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/PerspectiveContent.java
@@ -0,0 +1,130 @@
+/*
+ * 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.service;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.userprofile.PerspectiveEntry;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.content.AbstractContent;
+
+public class PerspectiveContent extends AbstractContent {
+ private final PerspectiveEntry perspective;
+
+ public PerspectiveContent(final PerspectiveEntry perspective) {
+ this.perspective = perspective;
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ debug.appendln("perspective", perspective);
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return null;
+ }
+
+ @Override
+ public String getHelp() {
+ return "";
+ }
+
+ @Override
+ public String getId() {
+ return "";
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return null;
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return null;
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return false;
+ }
+
+ @Override
+ public String title() {
+ return perspective.getTitle();
+ }
+
+ @Override
+ public String toString() {
+ return "Perspective: " + perspective;
+ }
+
+ @Override
+ public String windowTitle() {
+ return perspective.getTitle();
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ return null;
+ }
+
+ @Override
+ public String getIconName() {
+ return "icon";
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return null;
+ }
+
+ public void parseTextEntry(final String entryText) {
+ }
+
+ public PerspectiveEntry getPerspective() {
+ return perspective;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceBorder.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceBorder.java
new file mode 100644
index 0000000..2b8f750
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceBorder.java
@@ -0,0 +1,110 @@
+/*
+ * 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.service;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+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.View;
+import org.apache.isis.viewer.dnd.view.ViewState;
+import org.apache.isis.viewer.dnd.view.base.AbstractBorder;
+
+public class ServiceBorder extends AbstractBorder {
+ private static final int BORDER = 13;
+
+ public ServiceBorder(final int size, final View wrappedView) {
+ super(wrappedView);
+
+ top = size;
+ left = size;
+ bottom = size;
+ right = size + BORDER;
+ }
+
+ public ServiceBorder(final View wrappedView) {
+ this(1, wrappedView);
+ }
+
+ @Override
+ protected void debugDetails(final DebugBuilder debug) {
+ debug.append("ServiceBorder " + top + " pixels");
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+
+ Color color = null;
+ final ViewState state = getState();
+ final boolean hasFocus = getViewManager().hasFocus(getView());
+ if (hasFocus) {
+ color = Toolkit.getColor(ColorsAndFonts.COLOR_IDENTIFIED);
+ } else if (state.isObjectIdentified()) {
+ color = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2);
+ }
+
+ final Size s = getSize();
+ if (color != null) {
+ if (hasFocus) {
+ final int xExtent = s.getWidth() - left;
+ for (int i = 0; i < left; i++) {
+ canvas.drawRectangle(i, i, xExtent - 2 * i, s.getHeight() - 2 * i, color);
+ }
+ } else {
+ final int xExtent = s.getWidth();
+ for (int i = 0; i < left; i++) {
+ canvas.drawRectangle(i, i, xExtent - 2 * i, s.getHeight() - 2 * i, color);
+ }
+ canvas.drawLine(xExtent - BORDER, left, xExtent - BORDER, left + s.getHeight(), color);
+ canvas.drawSolidRectangle(xExtent - BORDER + 1, left, BORDER - 2, s.getHeight() - 2 * left, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3));
+ }
+ }
+ }
+
+ @Override
+ public void entered() {
+ getState().setContentIdentified();
+ getState().setViewIdentified();
+ wrappedView.entered();
+ markDamaged();
+ }
+
+ @Override
+ public void exited() {
+ getState().clearObjectIdentified();
+ getState().clearViewIdentified();
+ wrappedView.exited();
+ markDamaged();
+ }
+
+ @Override
+ public void secondClick(final Click click) {
+ // ignore - prevents the super class opening a view
+ }
+
+ @Override
+ public String toString() {
+ return wrappedView.toString() + "/ServiceBorder [" + getSpecification() + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIcon.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIcon.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIcon.java
new file mode 100644
index 0000000..3e30ff1
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIcon.java
@@ -0,0 +1,86 @@
+/*
+ * 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.service;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.runtime.userprofile.PerspectiveEntry;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.icon.Icon;
+import org.apache.isis.viewer.dnd.util.Properties;
+import org.apache.isis.viewer.dnd.view.Content;
+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.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.action.OptionFactory;
+import org.apache.isis.viewer.dnd.view.base.IconGraphic;
+import org.apache.isis.viewer.dnd.view.option.CloseViewOption;
+import org.apache.isis.viewer.dnd.view.text.ObjectTitleText;
+
+public class ServiceIcon extends Icon {
+ private final static int ICON_SIZE;
+ private final static int LARGE_ICON_SIZE = 34;
+ private final static String LARGE_ICON_SIZE_PROPERTY;
+
+ static {
+ LARGE_ICON_SIZE_PROPERTY = Properties.PROPERTY_BASE + "large-icon-size";
+ ICON_SIZE = IsisContext.getConfiguration().getInteger(LARGE_ICON_SIZE_PROPERTY, LARGE_ICON_SIZE);
+ }
+
+ public ServiceIcon(final Content content, final ViewSpecification specification) {
+ super(content, specification);
+ setTitle(new ObjectTitleText(this, Toolkit.getText(ColorsAndFonts.TEXT_ICON)));
+ setSelectedGraphic(new IconGraphic(this, ICON_SIZE));
+ setVertical(true);
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_CONTENT));
+ OptionFactory.addObjectMenuOptions(getContent().getAdapter(), options);
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ options.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_MENU_VIEW));
+
+ options.add(new CloseViewOption() {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final PerspectiveContent parent = (PerspectiveContent) view.getParent().getContent();
+ final PerspectiveEntry perspective = parent.getPerspective();
+ final ServiceObject serviceContent = (ServiceObject) view.getContent();
+ final ObjectAdapter element = serviceContent.getObject();
+ perspective.removeFromServices(element);
+ super.execute(workspace, view, at);
+ }
+ });
+ }
+
+ @Override
+ public DragEvent dragStart(final DragStart drag) {
+ return Toolkit.getViewFactory().createDragContentOutline(this, drag.getLocation());
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIconSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIconSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIconSpecification.java
new file mode 100644
index 0000000..ebb4d5a
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceIconSpecification.java
@@ -0,0 +1,71 @@
+/*
+ * 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.service;
+
+import org.apache.isis.viewer.dnd.icon.Icon;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+
+public class ServiceIconSpecification implements ViewSpecification {
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return requirement.isFor(ServiceObject.class) && requirement.getSpecification().isService();
+ }
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final Icon icon = new ServiceIcon(content, this);
+ return new ServiceBorder(icon);
+ }
+
+ @Override
+ public String getName() {
+ return "Service Icon";
+ }
+
+ @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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceObject.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceObject.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceObject.java
new file mode 100644
index 0000000..4bba0af
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/service/ServiceObject.java
@@ -0,0 +1,181 @@
+/*
+ * 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.service;
+
+import java.util.Arrays;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
+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.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+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.UserActionSet;
+import org.apache.isis.viewer.dnd.view.content.AbstractContent;
+
+public class ServiceObject extends AbstractContent {
+ private final ObjectAdapter adapter;
+
+ public ServiceObject(final ObjectAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ public Consent canClear() {
+ return Veto.DEFAULT;
+ }
+
+ public Consent canSet(final ObjectAdapter dragSource) {
+ return Veto.DEFAULT;
+ }
+
+ public void clear() {
+ throw new IsisException("Invalid call");
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ debug.appendln("service", adapter);
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return adapter;
+ }
+
+ @Override
+ public String getDescription() {
+ final String specName = getSpecification().getSingularName();
+ final String objectTitle = getObject().titleString();
+ return specName + (specName.equalsIgnoreCase(objectTitle) ? "" : ": " + objectTitle) + " " + getSpecification().getDescription();
+ }
+
+ @Override
+ public String getHelp() {
+ return "";
+ }
+
+ @Override
+ public String getId() {
+ return "";
+ }
+
+ public ObjectAdapter getObject() {
+ return adapter;
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return null;
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return adapter.getSpecification();
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return adapter != null && adapter.isTransient();
+ }
+
+ public void setObject(final ObjectAdapter object) {
+ throw new IsisException("Invalid call");
+ }
+
+ @Override
+ public String title() {
+ return adapter.titleString();
+ }
+
+ @Override
+ public String toString() {
+ return "Service Object [" + adapter + "]";
+ }
+
+ @Override
+ public String windowTitle() {
+ return (isTransient() ? "UNSAVED " : "") + getSpecification().getSingularName();
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ final ObjectAction action = actionFor(sourceContent);
+ if (action == null) {
+ return Veto.DEFAULT;
+ } else {
+ final ObjectAdapter source = sourceContent.getAdapter();
+ final Consent parameterSetValid = action.isProposedArgumentSetValid(adapter, new ObjectAdapter[] { source });
+ parameterSetValid.setDescription("Execute '" + action.getName() + "' with " + source.titleString());
+ return parameterSetValid;
+ }
+ }
+
+ private ObjectAction actionFor(final Content sourceContent) {
+ ObjectAction action;
+ action = adapter.getSpecification().getObjectAction(ActionType.USER, null, Arrays.asList(sourceContent.getSpecification()));
+ return action;
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ final ObjectAction action = actionFor(sourceContent);
+ final ObjectAdapter source = sourceContent.getAdapter();
+ return action.execute(adapter, new ObjectAdapter[] { source });
+ }
+
+ @Override
+ public String getIconName() {
+ final ObjectAdapter object = getObject();
+ return object == null ? null : object.getIconName();
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ final ObjectAdapter adapter = getObject();
+ final ObjectSpecification specification = adapter.getSpecification();
+ final Image icon = ImageFactory.getInstance().loadIcon(specification, iconHeight, null);
+ return icon;
+ }
+
+ public void parseTextEntry(final String entryText) {
+ throw new UnexpectedCallException();
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/AbstractTableSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/AbstractTableSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/AbstractTableSpecification.java
new file mode 100644
index 0000000..09b49d4
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/AbstractTableSpecification.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.table;
+
+import java.util.List;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.composite.CollectionElementBuilder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewSpecification;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+
+public abstract class AbstractTableSpecification extends CompositeViewSpecification {
+
+ public AbstractTableSpecification() {
+ builder = new CollectionElementBuilder(new ViewFactory() {
+ TableRowSpecification rowSpecification = new TableRowSpecification();
+
+ // TODO do directly without specification
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ // ViewSpecification rowSpecification = new
+ // SubviewIconSpecification();
+ return rowSpecification.createView(content, axes, -1);
+ }
+ });
+
+ addSubviewDecorator(new TableRowBorder.Factory());
+
+ addViewDecorator(new CompositeViewDecorator() {
+ @Override
+ public View decorate(final View view, final Axes axes) {
+ axes.getAxis(TableAxis.class).setRoot(view);
+ return view;
+ }
+ });
+ }
+
+ @Override
+ public Layout createLayout(final Content content, final Axes axes) {
+ return new StackLayout();
+ }
+
+ @Override
+ public void createAxes(final Content content, final Axes axes) {
+ axes.add(new TableAxisImpl((CollectionContent) content), TableAxis.class);
+ }
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ if (!requirement.isCollection() || !requirement.isOpen()) {
+ return false;
+ } else {
+ final CollectionContent collectionContent = (CollectionContent) requirement.getContent();
+ final ObjectSpecification elementSpecification = collectionContent.getElementSpecification();
+ final List<ObjectAssociation> fields = elementSpecification.getAssociations(ObjectAssociationFilters.WHEN_VISIBLE_IRRESPECTIVE_OF_WHERE);
+ for (int i = 0; i < fields.size(); i++) {
+ if (fields.get(i).isOneToOneAssociation()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /*
+ * protected View decorateView(View view) { TableAxis tableAxis =
+ * (TableAxis) view.getViewAxisForChildren(); tableAxis.setRoot(view);
+ * return view; // return doCreateView(table, content, axis); } protected
+ * abstract View doCreateView(final View table, final Content content, final
+ * ViewAxis axis);
+ */
+
+ @Override
+ public String getName() {
+ return "Standard Table";
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/ColumnWidthStrategy.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/ColumnWidthStrategy.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/ColumnWidthStrategy.java
new file mode 100644
index 0000000..ddfe959
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/ColumnWidthStrategy.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.table;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+
+public interface ColumnWidthStrategy {
+ int getMinimumWidth(int i, ObjectAssociation specification);
+
+ int getPreferredWidth(int i, ObjectAssociation specification);
+
+ int getMaximumWidth(int i, ObjectAssociation specification);
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/DefaultColumnWidthStrategy.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/DefaultColumnWidthStrategy.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/DefaultColumnWidthStrategy.java
new file mode 100644
index 0000000..5c5c4b5
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/DefaultColumnWidthStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.table;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+
+public class DefaultColumnWidthStrategy implements ColumnWidthStrategy {
+
+ private final int minimum;
+ private final int preferred;
+ private final int maximum;
+
+ public DefaultColumnWidthStrategy() {
+ this(18, 70, 250);
+ }
+
+ public DefaultColumnWidthStrategy(final int minimum, final int preferred, final int maximum) {
+ if (minimum <= 0) {
+ throw new IllegalArgumentException("minimum width must be greater than zero");
+ }
+ if (preferred <= minimum || preferred >= maximum) {
+ throw new IllegalArgumentException("preferred width must be greater than minimum and less than maximum");
+ }
+ this.minimum = minimum;
+ this.preferred = preferred;
+ this.maximum = maximum;
+ }
+
+ @Override
+ public int getMinimumWidth(final int i, final ObjectAssociation specification) {
+ return minimum;
+ }
+
+ @Override
+ public int getPreferredWidth(final int i, final ObjectAssociation specification) {
+ return preferred;
+ }
+
+ @Override
+ public int getMaximumWidth(final int i, final ObjectAssociation specification) {
+ return maximum;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/InternalTableSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/InternalTableSpecification.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/InternalTableSpecification.java
new file mode 100644
index 0000000..ffaef29
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/InternalTableSpecification.java
@@ -0,0 +1,76 @@
+/*
+ * 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.table;
+
+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.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.ScrollBorder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewDecorator;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+import org.apache.isis.viewer.dnd.viewer.basic.TableFocusManager;
+
+public class InternalTableSpecification extends AbstractTableSpecification {
+ public InternalTableSpecification() {
+ addViewDecorator(new CompositeViewDecorator() {
+ @Override
+ public View decorate(final View view, final Axes axes) {
+ final ScrollBorder scrollingView = new ScrollBorder(view);
+ // note - the next call needs to be after the creation of the
+ // window border
+ // so that it exists when the header is set up
+ scrollingView.setTopHeader(new TableHeader(view.getContent(), axes.getAxis(TableAxis.class)));
+ scrollingView.setFocusManager(new TableFocusManager(scrollingView));
+ return scrollingView;
+
+ }
+ });
+
+ }
+
+ @Override
+ public Layout createLayout(final Content content, final Axes axes) {
+ return new StackLayout();
+ }
+
+ // TODO remove
+ /*
+ * @Override public View doCreateView(final View view, final Content
+ * content, final ViewAxis axis) { final ScrollBorder scrollingView = new
+ * ScrollBorder(view); // note - the next call needs to be after the
+ * creation of the window border // so that it exists when the header is set
+ * up scrollingView.setTopHeader(new TableHeader(content));
+ * scrollingView.setFocusManager(new TableFocusManager(scrollingView));
+ * return scrollingView; }
+ *
+ * protected View decorateView(View view) { super.decorateView(view);
+ *
+ * final ScrollBorder scrollingView = new ScrollBorder(view); // note - the
+ * next call needs to be after the creation of the window border // so that
+ * it exists when the header is set up scrollingView.setTopHeader(new
+ * TableHeader(view.getContent())); scrollingView.setFocusManager(new
+ * TableFocusManager(scrollingView)); return scrollingView; }
+ */
+ @Override
+ public String getName() {
+ return "Table";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxis.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxis.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxis.java
new file mode 100644
index 0000000..5a5c676
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxis.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.table;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+
+public interface TableAxis extends ViewAxis {
+
+ void ensureOffset(final int offset);
+
+ /**
+ * Returns the number of the column found at the specificied position,
+ * ignoring the columns two borders. Returns 0 for the first column, 1 for
+ * second column, etc.
+ *
+ * If over the column border then returns -1.
+ */
+ int getColumnAt(final int xPosition);
+
+ /**
+ * Returns 0 for left side of first column, 1 for right side of first
+ * column, 2 for right side of second column, etc.
+ *
+ * If no column border is identified then returns -1.
+ */
+ int getColumnBorderAt(final int xPosition);
+
+ int getColumnCount();
+
+ String getColumnName(final int column);
+
+ int getColumnWidth(final int column);
+
+ ObjectAssociation getFieldForColumn(final int column);
+
+ int getHeaderOffset();
+
+ int getLeftEdge(final int resizeColumn);
+
+ void invalidateLayout();
+
+ void setOffset(final int offset);
+
+ void setRoot(final View view);
+
+ void setupColumnWidths(final ColumnWidthStrategy strategy);
+
+ void setWidth(final int index, final int width);
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/255ef514/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxisImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxisImpl.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxisImpl.java
new file mode 100644
index 0000000..34f54e9
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableAxisImpl.java
@@ -0,0 +1,217 @@
+/*
+ * 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.table;
+
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+
+public class TableAxisImpl implements TableAxis {
+ private final List<ObjectAssociation> columns;
+ private final String[] columnName;
+ private int rowHeaderOffet;
+ private View table;
+ private final int[] widths;
+
+ public TableAxisImpl(final CollectionContent content) {
+ // TODO create axis first, then after view built set up the axis
+ // details?
+ final ObjectSpecification elementSpecification = (content).getElementSpecification();
+ final List<ObjectAssociation> accessibleFields = elementSpecification.getAssociations(ObjectAssociationFilters.WHEN_VISIBLE_IRRESPECTIVE_OF_WHERE);
+
+ this.columns = tableFields(accessibleFields, content);
+ widths = new int[columns.size()];
+ columnName = new String[columns.size()];
+ for (int i = 0; i < widths.length; i++) {
+ columnName[i] = columns.get(i).getName();
+ }
+
+ // TODO make the setting of the column width strategy external so it can
+ // be changed
+ setupColumnWidths(new TypeBasedColumnWidthStrategy());
+ }
+
+ /*
+ * public TableAxis(final ObjectAssociation[] columns) { this.columns =
+ * columns; widths = new int[columns.length]; columnName = new
+ * String[columns.length]; for (int i = 0; i < widths.length; i++) {
+ * columnName[i] = columns[i].getName(); } }
+ */
+ private List<ObjectAssociation> tableFields(final List<ObjectAssociation> viewFields, final CollectionContent content) {
+ for (int i = 0; i < viewFields.size(); i++) {
+ // final ObjectAssociation objectAssociation = viewFields[i];
+ // TODO reinstate check to skip unsuitable types
+ /*
+ * if (viewFields[i].getSpecification().isOfType(
+ * IsisContext.getSpecificationLoader
+ * ().loadSpecification(ImageValue.class))) { continue; }
+ */
+
+ // if
+ // (!objectAssociation.isVisible(IsisContext.getAuthenticationSession(),
+ // content.getAdapter()).isAllowed()) {
+ // continue;
+ // }
+ // LOG.debug("column " + objectAssociation.getSpecification());
+ // if(viewFields[i].getSpecification().isOfType(Isis.getSpecificationLoader().lo));
+ }
+
+ final List<ObjectAssociation> tableFields = Lists.newArrayList();
+ for (int i = 0; i < viewFields.size(); i++) {
+ if (!(viewFields.get(i) instanceof OneToManyAssociation)) {
+ tableFields.add(viewFields.get(i));
+ }
+ }
+
+ return tableFields;
+ }
+
+ @Override
+ public void ensureOffset(final int offset) {
+ rowHeaderOffet = Math.max(rowHeaderOffet, offset + 5);
+ }
+
+ /**
+ * Returns the number of the column found at the specificied position,
+ * ignoring the columns two borders. Returns 0 for the first column, 1 for
+ * second column, etc.
+ *
+ * If over the column border then returns -1.
+ */
+ @Override
+ public int getColumnAt(final int xPosition) {
+ int edge = getHeaderOffset();
+ for (int i = 0, cols = getColumnCount() + 1; i < cols; i++) {
+ if (xPosition >= edge - 1 && xPosition <= edge + 1) {
+ return -1;
+ }
+ if (xPosition < edge - 1) {
+ return i;
+ }
+ edge += getColumnWidth(i);
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns 0 for left side of first column, 1 for right side of first
+ * column, 2 for right side of second column, etc.
+ *
+ * If no column border is identified then returns -1.
+ */
+ @Override
+ public int getColumnBorderAt(final int xPosition) {
+ int edge = getHeaderOffset();
+ for (int i = 0, cols = getColumnCount(); i < cols; i++) {
+ if (xPosition >= edge - 1 && xPosition <= edge + 1) {
+ return i;
+ }
+ edge += getColumnWidth(i);
+ }
+ if (xPosition >= edge - 1 && xPosition <= edge + 1) {
+ return getColumnCount();
+ }
+
+ return -1;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return columnName.length;
+ }
+
+ @Override
+ public String getColumnName(final int column) {
+ return columnName[column];
+ }
+
+ @Override
+ public int getColumnWidth(final int column) {
+ return widths[column];
+ }
+
+ @Override
+ public ObjectAssociation getFieldForColumn(final int column) {
+ return columns.get(column);
+ }
+
+ @Override
+ public int getHeaderOffset() {
+ return rowHeaderOffet;
+ }
+
+ @Override
+ public int getLeftEdge(final int resizeColumn) {
+ int width = getHeaderOffset();
+ for (int i = 0, cols = getColumnCount(); i < resizeColumn && i < cols; i++) {
+ width += getColumnWidth(i);
+ }
+ return width;
+ }
+
+ @Override
+ public void invalidateLayout() {
+ final View[] rows = table.getSubviews();
+ for (final View row : rows) {
+ row.invalidateLayout();
+ }
+ table.invalidateLayout();
+ }
+
+ @Override
+ public void setOffset(final int offset) {
+ rowHeaderOffet = offset;
+ }
+
+ @Override
+ public void setRoot(final View view) {
+ table = view;
+ }
+
+ @Override
+ public void setupColumnWidths(final ColumnWidthStrategy strategy) {
+ for (int i = 0; i < widths.length; i++) {
+ widths[i] = strategy.getPreferredWidth(i, columns.get(i));
+ }
+ }
+
+ @Override
+ public void setWidth(final int index, final int width) {
+ widths[index] = width;
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("columns", columnName.length);
+ str.append("header offset", rowHeaderOffet);
+ str.append("table", table);
+ 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/table/TableCellBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableCellBuilder.java b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableCellBuilder.java
new file mode 100644
index 0000000..8a29d08
--- /dev/null
+++ b/component/viewer/dnd/src/main/java/org/apache/isis/viewer/dnd/table/TableCellBuilder.java
@@ -0,0 +1,202 @@
+/*
+ * 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.table;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
+import org.apache.isis.core.commons.exceptions.UnknownTypeException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.progmodel.facets.value.booleans.BooleanValueFacet;
+import org.apache.isis.core.progmodel.facets.value.image.ImageValueFacet;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.field.CheckboxField;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.GlobalViewFactory;
+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.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.BlankView;
+import org.apache.isis.viewer.dnd.view.base.FieldErrorView;
+import org.apache.isis.viewer.dnd.view.composite.AbstractViewBuilder;
+import org.apache.isis.viewer.dnd.view.content.TextParseableContent;
+import org.apache.isis.viewer.dnd.view.field.OneToOneFieldImpl;
+import org.apache.isis.viewer.dnd.view.field.TextParseableFieldImpl;
+import org.apache.isis.viewer.dnd.viewer.basic.UnlinedTextFieldSpecification;
+
+class TableCellBuilder extends AbstractViewBuilder {
+ private static final Logger LOG = Logger.getLogger(TableCellBuilder.class);
+
+ // REVIEW: should provide this rendering context, rather than hardcoding.
+ // the net effect currently is that class members annotated with
+ // @Hidden(where=Where.ALL_TABLES) will indeed be hidden from all tables
+ // but will be shown (perhaps incorrectly) if annotated with Where.PARENTED_TABLE
+ // or Where.STANDALONE_TABLE
+ private final Where where = Where.ALL_TABLES;
+
+
+ private void addField(final View view, final Axes axes, final ObjectAdapter object, final ObjectAssociation field) {
+ final ObjectAdapter value = field.get(object);
+ View fieldView;
+ fieldView = createFieldView(view, axes, object, field, value);
+ if (fieldView != null) {
+ view.addView(decorateSubview(axes, fieldView));
+ } else {
+ view.addView(new FieldErrorView("No field for " + value));
+ }
+ }
+
+ @Override
+ public void build(final View view, final Axes axes) {
+ Assert.assertEquals("ensure the view is complete decorated view", view.getView(), view);
+
+ final Content content = view.getContent();
+ final ObjectAdapter object = ((ObjectContent) content).getObject();
+
+ if (view.getSubviews().length == 0) {
+ initialBuild(object, view, axes);
+ } else {
+ updateBuild(object, view, axes);
+ }
+ }
+
+ private void updateBuild(final ObjectAdapter object, final View view, final Axes axes) {
+ final TableAxis viewAxis = axes.getAxis(TableAxis.class);
+
+ LOG.debug("update view " + view + " for " + object);
+ final View[] subviews = view.getSubviews();
+ final ObjectSpecification spec = object.getSpecification();
+ for (int i = 0; i < subviews.length; i++) {
+ final ObjectAssociation field = fieldFromActualSpec(spec, viewAxis.getFieldForColumn(i));
+ final View subview = subviews[i];
+ final ObjectAdapter value = field.get(object);
+
+ // if the field is parseable then it may have been modified; we need
+ // to replace what was
+ // typed in with the actual title.
+ if (field.getSpecification().isParseable()) {
+ final boolean visiblityChange = !field.isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed() ^ (subview instanceof BlankView);
+ final ObjectAdapter adapter = subview.getContent().getAdapter();
+ final boolean valueChange = value != null && value.getObject() != null && !value.getObject().equals(adapter.getObject());
+
+ if (visiblityChange || valueChange) {
+ final View fieldView = createFieldView(view, axes, object, field, value);
+ view.replaceView(subview, decorateSubview(axes, fieldView));
+ }
+ subview.refresh();
+ } else if (field.isOneToOneAssociation()) {
+ final ObjectAdapter existing = ((ObjectContent) subviews[i].getContent()).getObject();
+ final boolean changedValue = value != existing;
+ if (changedValue) {
+ View fieldView;
+ fieldView = createFieldView(view, axes, object, field, value);
+ if (fieldView != null) {
+ view.replaceView(subview, decorateSubview(axes, fieldView));
+ } else {
+ view.addView(new FieldErrorView("No field for " + value));
+ }
+ }
+ }
+ }
+ }
+
+ private ObjectAssociation fieldFromActualSpec(final ObjectSpecification spec, final ObjectAssociation field) {
+ final String fieldName = field.getId();
+ return spec.getAssociation(fieldName);
+ }
+
+ private void initialBuild(final ObjectAdapter object, final View view, final Axes axes) {
+ final TableAxis viewAxis = axes.getAxis(TableAxis.class);
+ LOG.debug("build view " + view + " for " + object);
+ final int len = viewAxis.getColumnCount();
+ final ObjectSpecification spec = object.getSpecification();
+ for (int f = 0; f < len; f++) {
+ if (f > 3) {
+ continue;
+ }
+ final ObjectAssociation field = fieldFromActualSpec(spec, viewAxis.getFieldForColumn(f));
+ addField(view, axes, object, field);
+ }
+ }
+
+ private View createFieldView(final View view, final Axes axes, final ObjectAdapter object, final ObjectAssociation field, final ObjectAdapter value) {
+ if (field == null) {
+ throw new NullPointerException();
+ }
+ final GlobalViewFactory factory = Toolkit.getViewFactory();
+ ViewSpecification cellSpec;
+ Content content;
+ if (field instanceof OneToManyAssociation) {
+ throw new UnexpectedCallException("no collections allowed");
+ } else if (field instanceof OneToOneAssociation) {
+
+ final ObjectSpecification fieldSpecification = field.getSpecification();
+ if (fieldSpecification.isParseable()) {
+ content = new TextParseableFieldImpl(object, value, (OneToOneAssociation) field);
+ // REVIEW how do we deal with IMAGES?
+ if (content.getAdapter() instanceof ImageValueFacet) {
+ return new BlankView(content);
+ }
+
+ if (!field.isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed()) {
+ return new BlankView(content);
+ }
+ if (((TextParseableContent) content).getNoLines() > 0) {
+ /*
+ * TODO remove this after introducing constraints into view
+ * specs that allow the parent view to specify what kind of
+ * subviews it can deal
+ */
+
+ if (fieldSpecification.containsFacet(BooleanValueFacet.class)) {
+ cellSpec = new CheckboxField.Specification();
+ } else {
+ cellSpec = new UnlinedTextFieldSpecification();
+ }
+ } else {
+ return factory.createView(new ViewRequirement(content, ViewRequirement.CLOSED));
+ }
+ } else {
+ content = new OneToOneFieldImpl(object, value, (OneToOneAssociation) field);
+
+ if (!field.isVisible(IsisContext.getAuthenticationSession(), object, where).isAllowed()) {
+ return new BlankView(content);
+ }
+ return factory.createView(new ViewRequirement(content, ViewRequirement.CLOSED | ViewRequirement.SUBVIEW));
+
+ }
+
+ } else {
+ throw new UnknownTypeException(field);
+ }
+
+ return cellSpec.createView(content, axes, -1);
+ }
+
+}