You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2012/12/08 15:56:01 UTC
[23/53] [partial] ISIS-188: making structure of component viewers
consistent
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/FieldLabelsDecorator.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/FieldLabelsDecorator.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/FieldLabelsDecorator.java
new file mode 100644
index 0000000..3dc11d7
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/FieldLabelsDecorator.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.composite;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.SubviewDecorator;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.axis.LabelAxis;
+import org.apache.isis.viewer.dnd.view.border.DroppableLabelBorder;
+import org.apache.isis.viewer.dnd.view.border.LabelBorder;
+
+public class FieldLabelsDecorator implements SubviewDecorator {
+
+ @Override
+ public ViewAxis createAxis(final Content content) {
+ return new LabelAxis();
+ }
+
+ @Override
+ public View decorate(final Axes axes, final View view) {
+ final LabelAxis axis = axes.getAxis(LabelAxis.class);
+ if (view.getContent().isObject() && !view.getContent().isTextParseable()) {
+ return DroppableLabelBorder.createObjectFieldLabelBorder(axis, view);
+ } else {
+ return LabelBorder.createFieldLabelBorder(axis, view);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayout.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayout.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayout.java
new file mode 100644
index 0000000..6ae56e2
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayout.java
@@ -0,0 +1,137 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+
+/**
+ */
+public class GridLayout implements Layout, ViewAxis {
+ public final static int COLUMNS = 0;
+ public final static int ROWS = 1;
+ private int orientation = COLUMNS;
+ private int size = 1;
+
+ @Override
+ public Size getRequiredSize(final View view) {
+ final View views[] = view.getSubviews();
+
+ final int max[] = new int[size];
+ final int total[] = new int[size];
+
+ int column = 0;
+ for (final View v : views) {
+ final Size s = v.getRequiredSize(new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ if (orientation == COLUMNS) {
+ total[column] += s.getHeight();
+ max[column] = Math.max(max[column], s.getWidth());
+ } else {
+ total[column] += s.getWidth();
+ max[column] = Math.max(max[column], s.getHeight());
+ }
+ column++;
+ if (column >= size) {
+ column = 0;
+ }
+ }
+
+ int height = 0;
+ int width = 0;
+ for (int i = 0; i < size; i++) {
+ if (orientation == COLUMNS) {
+ height = Math.max(height, total[i]);
+ width += max[i];
+ } else {
+ width = Math.max(width, total[i]);
+ height += max[i];
+ }
+ }
+ return new Size(width, height);
+ }
+
+ @Override
+ public void layout(final View view, final Size maximumSize) {
+ int x = 0;
+ int y = 0;
+ final View views[] = view.getSubviews();
+ final int max[] = new int[size];
+
+ int column = 0;
+ for (final View v : views) {
+ final Size s = v.getRequiredSize(new Size(maximumSize));
+ if (orientation == COLUMNS) {
+ max[column] = Math.max(max[column], s.getWidth());
+ } else {
+ max[column] = Math.max(max[column], s.getHeight());
+ }
+ column++;
+ if (column >= size) {
+ column = 0;
+ }
+ }
+
+ column = 0;
+ for (final View v : views) {
+ final Size s = v.getRequiredSize(new Size(maximumSize));
+ v.setLocation(new Location(x, y));
+ if (orientation == COLUMNS) {
+ x += max[column];
+ s.ensureWidth(max[column]);
+ } else {
+ y += max[column];
+ s.ensureHeight(max[column]);
+ }
+ v.setSize(s);
+ column++;
+ if (column >= size) {
+ column = 0;
+ if (orientation == COLUMNS) {
+ x = 0;
+ y += s.getHeight();
+ } else {
+ y = 0;
+ x += s.getWidth();
+ }
+ }
+
+ }
+ }
+
+ public int getOrientation() {
+ return orientation;
+ }
+
+ public void setOrientation(final int orientation) {
+ this.orientation = orientation;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(final int size) {
+ this.size = size;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayoutControlBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayoutControlBorder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayoutControlBorder.java
new file mode 100644
index 0000000..13615da
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/GridLayoutControlBorder.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.composite;
+
+import org.apache.isis.core.runtime.userprofile.Options;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Axes;
+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.base.AbstractBorder;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class GridLayoutControlBorder extends AbstractBorder {
+
+ public static final class Factory implements CompositeViewDecorator {
+ @Override
+ public View decorate(final View view, final Axes axes) {
+ return new GridLayoutControlBorder(view);
+ }
+ }
+
+ protected GridLayoutControlBorder(final View view) {
+ super(view);
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet menuOptions) {
+ super.viewMenuOptions(menuOptions);
+
+ final GridLayout layout = getViewAxes().getAxis(GridLayout.class);
+
+ final boolean columnOrientation = layout.getOrientation() == GridLayout.COLUMNS;
+
+ final UserActionSet submenu = menuOptions.addNewActionSet("Grid");
+
+ submenu.add(new UserActionAbstract("Add " + (columnOrientation ? "Column" : "Row")) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ layout.setSize(layout.getSize() + 1);
+ invalidateLayout();
+ }
+ });
+
+ if (layout.getSize() > 1) {
+ submenu.add(new UserActionAbstract("Remove " + (columnOrientation ? "Column" : "Row")) {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ layout.setSize(layout.getSize() - 1);
+ invalidateLayout();
+ }
+ });
+ }
+
+ submenu.add(new UserActionAbstract(columnOrientation ? "In Rows" : "In Columns") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ layout.setOrientation(columnOrientation ? GridLayout.ROWS : GridLayout.COLUMNS);
+ invalidateLayout();
+ }
+ });
+ }
+
+ @Override
+ public void saveOptions(final Options viewOptions) {
+ super.saveOptions(viewOptions);
+
+ final GridLayout layout = getViewAxes().getAxis(GridLayout.class);
+ viewOptions.addOption("orientation", layout.getOrientation() == GridLayout.COLUMNS ? "columns" : "rows");
+ viewOptions.addOption("size", layout.getSize() + "");
+ }
+
+ @Override
+ public void loadOptions(final Options viewOptions) {
+ super.loadOptions(viewOptions);
+
+ final GridLayout layout = getViewAxes().getAxis(GridLayout.class);
+ layout.setOrientation(viewOptions.getString("orientation", "columns").equals("columns") ? GridLayout.COLUMNS : GridLayout.ROWS);
+ layout.setSize(viewOptions.getInteger("size", 1));
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/IconGridViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/IconGridViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/IconGridViewSpecification.java
new file mode 100644
index 0000000..43bf01b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/IconGridViewSpecification.java
@@ -0,0 +1,87 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.border.IconBorder;
+import org.apache.isis.viewer.dnd.view.border.LineBorder;
+
+public class IconGridViewSpecification extends AbstractCollectionViewSpecification {
+
+ public IconGridViewSpecification() {
+ addViewDecorator(new IconBorder.Factory());
+ }
+
+ @Override
+ protected ViewFactory createElementFactory() {
+ return new ViewFactory() {
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final View icon = new ImageViewSpecification().createView(content, axes, sequence);
+ /*
+ * Icon icon = new Icon(content,
+ * IconGridViewSpecification.this); Text textStyle =
+ * Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ * icon.setTitle(new ObjectTitleText(icon, textStyle));
+ * icon.setSelectedGraphic(new IconGraphic(icon, 68));
+ * icon.setUnselectedGraphic(new IconGraphic(icon, 60));
+ * icon.setVertical(true);
+ *
+ * // return icon;
+ */
+ final LineBorder lineBorderedIcon = new LineBorder(icon);
+ lineBorderedIcon.setPadding(4);
+ lineBorderedIcon.setColor(Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY3));
+
+ // return lineBorderedIcon;
+
+ return new ReplaceViewBorder(lineBorderedIcon);
+ }
+ };
+ }
+
+ @Override
+ public Layout createLayout(final Content content, final Axes axes) {
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.setSize(3);
+ return gridLayout;
+ }
+
+ @Override
+ public String getName() {
+ return "Icon Grid";
+ }
+
+ /*
+ * private static final ObjectSpecification BOOK_SPECIFICATION =
+ * IsisContext.getSpecificationLoader().loadSpecification(
+ * "org.apache.isis.example.library.dom.Book"); public boolean
+ * canDisplay(ViewRequirement requirement) { return
+ * super.canDisplay(requirement) &&
+ * requirement.getAdapter().getTypeOfFacet().valueSpec() ==
+ * BOOK_SPECIFICATION; }
+ */
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ImageViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ImageViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ImageViewSpecification.java
new file mode 100644
index 0000000..7a5ed88
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ImageViewSpecification.java
@@ -0,0 +1,83 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+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.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.base.IconGraphic;
+import org.apache.isis.viewer.dnd.view.text.ObjectTitleText;
+
+public class ImageViewSpecification implements ViewSpecification {
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final Icon icon = new Icon(content, ImageViewSpecification.this);
+ final Text textStyle = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ icon.setTitle(new ObjectTitleText(icon, textStyle));
+ icon.setSelectedGraphic(new IconGraphic(icon, 68));
+ icon.setUnselectedGraphic(new IconGraphic(icon, 60));
+ icon.setVertical(true);
+
+ return icon;
+ }
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return requirement.isObject() && requirement.isClosed();
+ }
+
+ @Override
+ public String getName() {
+ return "Image";
+ }
+
+ @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/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/LineBorderDecorator.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/LineBorderDecorator.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/LineBorderDecorator.java
new file mode 100644
index 0000000..ed46eaa
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/LineBorderDecorator.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.view.composite;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.SubviewDecorator;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAxis;
+import org.apache.isis.viewer.dnd.view.border.LineBorder;
+
+public class LineBorderDecorator implements SubviewDecorator {
+
+ @Override
+ public View decorate(final Axes axes, final View view) {
+ return new LineBorder(view);
+ }
+
+ @Override
+ public ViewAxis createAxis(final org.apache.isis.viewer.dnd.view.Content content) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/MasterDetailPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/MasterDetailPanel.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/MasterDetailPanel.java
new file mode 100644
index 0000000..0ace123
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/MasterDetailPanel.java
@@ -0,0 +1,232 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Selectable;
+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.border.ScrollBorder;
+import org.apache.isis.viewer.dnd.view.border.SelectableViewAxis;
+import org.apache.isis.viewer.dnd.view.border.ViewResizeBorder;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+
+public class MasterDetailPanel extends CompositeView implements Selectable {
+ private static final int MINIMUM_WIDTH = 120;
+ private final ViewSpecification leftHandSideSpecification;
+ private final Axes axes;
+
+ public MasterDetailPanel(final Content content, final ViewSpecification specification, final ViewSpecification leftHandSideSpecification) {
+ super(content, specification);
+ this.leftHandSideSpecification = leftHandSideSpecification;
+ axes = new Axes();
+ axes.add(new SelectableViewAxis(this));
+ }
+
+ @Override
+ protected void buildView() {
+ final Content content = getContent();
+ View leftHandView = leftHandSideSpecification.createView(content, axes, -1);
+ leftHandView = new ViewResizeBorder(new ScrollBorder(leftHandView));
+ leftHandView.setParent(getView());
+ addView(leftHandView);
+
+ final Size blankViewSize = new Size(MINIMUM_WIDTH, 0);
+ final View blankView = new BlankView(new NullContent(), blankViewSize);
+ blankView.setParent(getView());
+ addView(blankView);
+
+ selectFirstSuitableObject(content);
+ }
+
+ private void selectFirstSuitableObject(final Content content) {
+ if (content instanceof CollectionContent) {
+ final ObjectAdapter[] elements = ((CollectionContent) content).elements();
+ if (elements.length > 0) {
+ final ObjectAdapter firstElement = elements[0];
+ final Content firstElementContent = Toolkit.getContentFactory().createRootContent(firstElement);
+ setSelectedNode(firstElementContent);
+ }
+ } else if (content instanceof ObjectContent) {
+ /*
+ * TODO provide a view that shows first useful object (not
+ * redisplaying parent)
+ *
+ * ObjectAssociation[] associations =
+ * content.getSpecification().getAssociations(); for (int i = 0; i <
+ * associations.length; i++) { ObjectAssociation assoc =
+ * associations[i]; if (assoc.isOneToManyAssociation()) {
+ * ObjectAdapter collection = assoc.get(content.getAdapter()); final
+ * Content collectionContent =
+ * Toolkit.getContentFactory().createRootContent(collection);
+ * setSelectedNode(collectionContent); break; } else if
+ * (assoc.isOneToOneAssociation() &&
+ * !((OneToOneAssociation)assoc).getSpecification().isParseable()) {
+ * ObjectAdapter object = assoc.get(content.getAdapter()); if
+ * (object == null) { continue; } final Content objectContent =
+ * Toolkit.getContentFactory().createRootContent(object);
+ * setSelectedNode(objectContent); break; } }
+ */
+ setSelectedNode(content);
+ }
+ }
+
+ @Override
+ protected void doLayout(final Size availableSpace) {
+ availableSpace.contract(getView().getPadding());
+
+ final View[] subviews = getSubviews();
+ final View left = subviews[0];
+ final View right = subviews[1];
+ final Size leftPanelRequiredSize = left.getRequiredSize(new Size(availableSpace));
+ final Size rightPanelRequiredSize = right == null ? new Size() : right.getRequiredSize(new Size(availableSpace));
+
+ // combine the two sizes
+ final Size totalSize = new Size(leftPanelRequiredSize);
+ totalSize.extendWidth(rightPanelRequiredSize.getWidth());
+ totalSize.ensureHeight(rightPanelRequiredSize.getHeight());
+
+ if (totalSize.getWidth() > availableSpace.getWidth()) {
+ /*
+ * If the combined width is greater than the available then we need
+ * to divide the space between the two sides and recalculate
+ */
+ if (rightPanelRequiredSize.getWidth() <= MINIMUM_WIDTH) {
+ leftPanelRequiredSize.setWidth(availableSpace.getWidth() - rightPanelRequiredSize.getWidth());
+ } else {
+ final int availableWidth = availableSpace.getWidth();
+ final int requiredWidth = totalSize.getWidth();
+ leftPanelRequiredSize.setWidth(leftPanelRequiredSize.getWidth() * availableWidth / requiredWidth);
+ rightPanelRequiredSize.setWidth(rightPanelRequiredSize.getWidth() * availableWidth / requiredWidth);
+ }
+ /*
+ * final int leftWidth = Math.max(MINIMUM_WIDTH,
+ * leftPanelRequiredSize.getWidth()); final int rightWidth =
+ * rightPanelRequiredSize.getWidth(); final int totalWidth =
+ * leftWidth + rightWidth;
+ *
+ * final int bestWidth = (int) (1.0 * leftWidth / totalWidth *
+ * availableWidth); final Size maximumSizeLeft = new Size(bestWidth,
+ * maximumSize.getHeight()); leftPanelRequiredSize =
+ * left.getRequiredSize(maximumSizeLeft);
+ *
+ * final Size maximumSizeRight = new Size(availableWidth -
+ * leftPanelRequiredSize.getWidth(), maximumSize.getHeight());
+ * rightPanelRequiredSize = right.getRequiredSize(maximumSizeRight);
+ */
+ }
+
+ // combinedSize.setHeight(Math.min(combinedSize.getHeight(),
+ // maximumSize.getHeight()));
+ // totalSize.limitSize(availableSpace);
+
+ left.setSize(new Size(leftPanelRequiredSize.getWidth(), totalSize.getHeight()));
+ left.layout();
+
+ if (right != null) {
+ right.setLocation(new Location(left.getSize().getWidth(), 0));
+
+ rightPanelRequiredSize.setHeight(totalSize.getHeight());
+ right.setSize(rightPanelRequiredSize);
+ right.layout();
+ }
+ }
+
+ @Override
+ public Size requiredSize(final Size availableSpace) {
+ final View[] subviews = getSubviews();
+ final View left = subviews[0];
+ final View right = subviews.length > 1 ? subviews[1] : null;
+
+ Size leftPanelRequiredSize = left.getRequiredSize(new Size(availableSpace));
+ Size rightPanelRequiredSize = right == null ? new Size() : right.getRequiredSize(new Size(availableSpace));
+
+ if (leftPanelRequiredSize.getWidth() + rightPanelRequiredSize.getWidth() > availableSpace.getWidth()) {
+ /*
+ * If the combined width is greater than the available then we need
+ * to divide the space between the two sides and recalculate
+ */
+
+ final int availableWidth = availableSpace.getWidth();
+ final int leftWidth = leftPanelRequiredSize.getWidth();
+ final int rightWidth = Math.max(MINIMUM_WIDTH, rightPanelRequiredSize.getWidth());
+ final int totalWidth = leftWidth + rightWidth;
+
+ final int bestWidth = (int) (1.0 * leftWidth / totalWidth * availableWidth);
+ final Size maximumSizeLeft = new Size(bestWidth, availableSpace.getHeight());
+ leftPanelRequiredSize = left.getRequiredSize(maximumSizeLeft);
+
+ final Size maximumSizeRight = new Size(availableWidth - leftPanelRequiredSize.getWidth(), availableSpace.getHeight());
+ rightPanelRequiredSize = right == null ? new Size() : right.getRequiredSize(maximumSizeRight);
+ }
+
+ // combine the two required sizes
+ final Size combinedSize = new Size(leftPanelRequiredSize);
+ combinedSize.extendWidth(rightPanelRequiredSize.getWidth());
+ combinedSize.ensureHeight(rightPanelRequiredSize.getHeight());
+ return combinedSize;
+ }
+
+ protected void showInRightPane(final View view) {
+ replaceView(getSubviews()[1], view);
+ }
+
+ @Override
+ public void setSelectedNode(final View view) {
+ final Content content = view.getContent();
+ setSelectedNode(content);
+ }
+
+ private void setSelectedNode(final Content content) {
+ final ViewRequirement requirement = new ViewRequirement(content, ViewRequirement.OPEN | ViewRequirement.SUBVIEW | ViewRequirement.FIXED);
+ /*
+ * final ObjectAdapter object = content.getAdapter(); final
+ * ObjectSpecification specification = object.getSpecification(); final
+ * CollectionFacet facet =
+ * specification.getFacet(CollectionFacet.class); if (facet != null &&
+ * facet.size(object) > 0) { if
+ * (mainViewTableSpec.canDisplay(requirement)) {
+ * showInRightPane(mainViewTableSpec.createView(content, axes, -1)); }
+ * else if (mainViewListSpec.canDisplay(requirement)) {
+ * showInRightPane(mainViewListSpec.createView(content, axes, -1)); }
+ *
+ * } else if (specification.isObject()) { if (object != null &&
+ * mainViewFormSpec.canDisplay(requirement)) {
+ * showInRightPane(mainViewFormSpec.createView(content, axes, -1)); } }
+ */
+ final View createView = Toolkit.getViewFactory().createView(requirement);
+ showInRightPane(createView);
+ }
+
+ @Override
+ public String toString() {
+ return "MasterDetailPanel" + getId();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ObjectFieldBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ObjectFieldBuilder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ObjectFieldBuilder.java
new file mode 100644
index 0000000..b14250b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ObjectFieldBuilder.java
@@ -0,0 +1,195 @@
+/*
+ * 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.composite;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.exceptions.UnknownTypeException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
+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.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.SubviewDecorator;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.base.FieldErrorView;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+
+public class ObjectFieldBuilder extends AbstractViewBuilder {
+ private static final Logger LOG = Logger.getLogger(ObjectFieldBuilder.class);
+
+ // REVIEW: confirm this rendering context
+ private final Where where = Where.OBJECT_FORMS;
+
+ private final ViewFactory subviewDesign;
+
+ // TODO remove - transitional
+ public ObjectFieldBuilder(final ViewFactory subviewDesign) {
+ this.subviewDesign = subviewDesign;
+ }
+
+ public ObjectFieldBuilder(final ViewFactory subviewDesign, final SubviewDecorator subviewDecorator) {
+ this.subviewDesign = subviewDesign;
+ addSubviewDecorator(subviewDecorator);
+ }
+
+ @Override
+ public void build(final View view, final Axes axes) {
+ Assert.assertEquals("ensure the view is the complete decorated view", view.getView(), view);
+
+ final Content content = view.getContent();
+ final ObjectAdapter object = ((ObjectContent) content).getObject();
+
+ LOG.debug("build view " + view + " for " + object);
+
+ final ObjectSpecification spec = object.getSpecification();
+ final Filter<ObjectAssociation> filter = ObjectAssociationFilters.dynamicallyVisible(IsisContext.getAuthenticationSession(), object, where);
+ final List<ObjectAssociation> flds = spec.getAssociations(filter);
+
+ if (view.getSubviews().length == 0) {
+ initialBuild(view, axes, object, flds);
+ } else {
+ updateBuild(view, axes, object, flds);
+ }
+ }
+
+ private void initialBuild(final View view, final Axes axes, final ObjectAdapter object, final List<ObjectAssociation> flds) {
+ LOG.debug(" as new build");
+ // addViewAxes(view);
+ for (int f = 0; f < flds.size(); f++) {
+ final ObjectAssociation field = flds.get(f);
+ addField(view, axes, object, field, f);
+ }
+ }
+
+ private void addField(final View view, final Axes axes, final ObjectAdapter object, final ObjectAssociation field, final int fieldNumber) {
+ final View fieldView = createFieldView(view, axes, object, fieldNumber, field);
+ if (fieldView != null) {
+ view.addView(decorateSubview(axes, fieldView));
+ }
+ }
+
+ private void updateBuild(final View view, final Axes axes, final ObjectAdapter object, final List<ObjectAssociation> flds) {
+ LOG.debug(" as update build");
+ /*
+ * 1/ To remove fields: look through views and remove any that don't
+ * exists in visible fields
+ *
+ * 2/ From remaining views, check for changes as already being done, and
+ * replace if needed
+ *
+ * 3/ Finally look through fields to see if there is no existing
+ * subview; and add one
+ */
+
+ View[] subviews = view.getSubviews();
+
+ // remove views for fields that no longer exist
+ outer: for (int i = 0; i < subviews.length; i++) {
+ final FieldContent fieldContent = ((FieldContent) subviews[i].getContent());
+
+ for (int j = 0; j < flds.size(); j++) {
+ final ObjectAssociation field = flds.get(j);
+ if (fieldContent.getField() == field) {
+ continue outer;
+ }
+ }
+ view.removeView(subviews[i]);
+ }
+
+ // update existing fields if needed
+ subviews = view.getSubviews();
+ for (int i = 0; i < subviews.length; i++) {
+ final View subview = subviews[i];
+ final ObjectAssociation field = ((FieldContent) subview.getContent()).getField();
+ final ObjectAdapter value = field.get(object);
+
+ if (field.isOneToManyAssociation()) {
+ subview.update(value);
+ } else if (field.isOneToOneAssociation()) {
+ final ObjectAdapter existing = subview.getContent().getAdapter();
+
+ // 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 changedValue = value != existing;
+ final boolean isDestroyed = existing != null && existing.isDestroyed();
+ if (changedValue || isDestroyed) {
+ View fieldView;
+ fieldView = createFieldView(view, axes, object, i, field);
+ if (fieldView != null) {
+ view.replaceView(subview, decorateSubview(axes, fieldView));
+ } else {
+ view.addView(new FieldErrorView("No field for " + value));
+ }
+ }
+ } else {
+ if (AdapterUtils.exists(value) && !AdapterUtils.wrappedEqual(value, existing)) {
+ final View fieldView = createFieldView(view, axes, object, i, field);
+ view.replaceView(subview, decorateSubview(axes, fieldView));
+ } else {
+ subview.refresh();
+ }
+ }
+ } else {
+ throw new UnknownTypeException(field.getName());
+ }
+ }
+
+ // add new fields
+ outer2: for (int j = 0; j < flds.size(); j++) {
+ final ObjectAssociation field = flds.get(j);
+ for (int i = 0; i < subviews.length; i++) {
+ final FieldContent fieldContent = ((FieldContent) subviews[i].getContent());
+ if (fieldContent.getField() == field) {
+ continue outer2;
+ }
+ }
+ addField(view, axes, object, field, j);
+ }
+ }
+
+ private View createFieldView(final View view, final Axes axes, final ObjectAdapter object, final int fieldNumber, final ObjectAssociation field) {
+ if (field == null) {
+ throw new NullPointerException();
+ }
+
+ if (field.isOneToOneAssociation()) {
+ IsisContext.getPersistenceSession().resolveField(object, field);
+ }
+
+ final Content content1 = Toolkit.getContentFactory().createFieldContent(field, object);
+ final View fieldView = subviewDesign.createView(content1, axes, fieldNumber);
+ return fieldView;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ReplaceViewBorder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ReplaceViewBorder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ReplaceViewBorder.java
new file mode 100644
index 0000000..7252e52
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ReplaceViewBorder.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.composite;
+
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.form.FormSpecification;
+import org.apache.isis.viewer.dnd.view.Axes;
+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.base.AbstractBorder;
+
+public class ReplaceViewBorder extends AbstractBorder {
+
+ protected ReplaceViewBorder(final View view) {
+ super(view);
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+
+ final Bounds b = getButtonBounds();
+ canvas.drawRoundedRectangle(b.getX(), b.getY(), b.getWidth(), b.getHeight(), 6, 6, Toolkit.getColor(0xfff));
+ }
+
+ @Override
+ public void firstClick(final Click click) {
+ if (getButtonBounds().contains(click.getLocation())) {
+ final View view = new FormSpecification().createView(getContent(), new Axes(), 0);
+ getWorkspace().replaceView(getParent(), view);
+ }
+ }
+
+ private Bounds getButtonBounds() {
+ final int x = getSize().getWidth() - 28;
+ return new Bounds(x, 8, 20, 16);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StackLayout.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StackLayout.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StackLayout.java
new file mode 100644
index 0000000..3d224c3
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StackLayout.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.view.composite;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+
+/**
+ * A stack layout stacks its components vertically, one on top of the other,
+ * working down from the top. Each component is given the space it requests.
+ * Components adopt the width of the widest component when that component's view
+ * specification's <code>isAligned</code> method returns <code>true</code>, or
+ * the layout's <code>fixedWidth</code> flag is set (via the two parameter
+ * constructor).
+ *
+ */
+public class StackLayout implements Layout {
+ private final boolean fixedWidth;
+
+ public StackLayout() {
+ this.fixedWidth = false;
+ }
+
+ public StackLayout(final boolean fixedWidth) {
+ this.fixedWidth = fixedWidth;
+ }
+
+ @Override
+ public Size getRequiredSize(final View view) {
+ int height = 0;
+ int width = 0;
+ final View views[] = view.getSubviews();
+
+ for (final View v : views) {
+ final Size s = v.getRequiredSize(new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ width = Math.max(width, s.getWidth());
+ height += s.getHeight();
+ }
+
+ return new Size(width, height);
+ }
+
+ @Override
+ public void layout(final View view, final Size maximumSize) {
+ final int x = 0;
+ int y = 0;
+ final View subviews[] = view.getSubviews();
+
+ int maxWidth = 0;
+ for (final View v : subviews) {
+ final Size s = v.getRequiredSize(new Size(maximumSize));
+ maxWidth = Math.max(maxWidth, s.getWidth());
+ }
+
+ for (final View v : subviews) {
+ final Size s = v.getRequiredSize(new Size(maximumSize));
+ s.limitWidth(maximumSize.getWidth());
+ if (fixedWidth || v.getSpecification().isAligned()) {
+ s.ensureWidth(maxWidth);
+ }
+ v.setSize(s);
+ v.setLocation(new Location(x, y));
+ y += s.getHeight();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StandardFields.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StandardFields.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StandardFields.java
new file mode 100644
index 0000000..9caba31
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/StandardFields.java
@@ -0,0 +1,74 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.core.commons.exceptions.UnknownTypeException;
+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.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+
+/**
+ * A view factory for the components of a container
+ */
+public class StandardFields implements ViewFactory {
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final GlobalViewFactory factory = Toolkit.getViewFactory();
+
+ int requirement = 0;
+ if (content.isObject()) {
+ requirement = objectRequirement();
+ } else if (content.isTextParseable()) {
+ requirement = textParseableRequirement();
+ } else if (content.isCollection()) {
+ requirement = collectionRequirement();
+ } else {
+ throw new UnknownTypeException(content);
+ }
+
+ if (requirement != 0 && include(content, sequence)) {
+ final ViewRequirement viewRequirement = new ViewRequirement(content, requirement);
+ return factory.createView(viewRequirement);
+ } else {
+ return null;
+ }
+ }
+
+ protected boolean include(final Content content, final int sequence) {
+ return true;
+ }
+
+ protected int objectRequirement() {
+ return ViewRequirement.CLOSED | ViewRequirement.SUBVIEW;
+ }
+
+ protected int textParseableRequirement() {
+ return ViewRequirement.CLOSED | ViewRequirement.SUBVIEW;
+ }
+
+ protected int collectionRequirement() {
+ return ViewRequirement.CLOSED | ViewRequirement.SUBVIEW;
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ViewBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ViewBuilder.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ViewBuilder.java
new file mode 100644
index 0000000..4d6fef5
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/composite/ViewBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * 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.composite;
+
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.SubviewDecorator;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+
+public interface ViewBuilder {
+
+ void addSubviewDecorator(SubviewDecorator decorator);
+
+ void createAxes(Axes axes, Content content);
+
+ void build(View view, Axes axes);
+
+ /**
+ * Indicates whether this view is expanded, or iconized.
+ *
+ * @return true if it is showing the object's details; false if it is
+ * showing the object only.
+ */
+ boolean isOpen();
+
+ /**
+ * Indicates whether this view can be replaced with another view (for the
+ * same value or reference).
+ *
+ * @return true if it can be replaced by another view; false if it can't be
+ * replaces
+ */
+ boolean isReplaceable();
+
+ boolean isSubView();
+
+ boolean canDragView();
+
+ void viewMenuOptions(UserActionSet options, View view);
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractContent.java
new file mode 100644
index 0000000..ac2ca9f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractContent.java
@@ -0,0 +1,58 @@
+/*
+ * 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.content;
+
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+
+public abstract class AbstractContent implements Content {
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ }
+
+ @Override
+ public boolean isCollection() {
+ return false;
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTextParseable() {
+ return false;
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ }
+
+ @Override
+ public String windowTitle() {
+ return "";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractObjectContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractObjectContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractObjectContent.java
new file mode 100644
index 0000000..dba30b2
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractObjectContent.java
@@ -0,0 +1,294 @@
+/*
+ * 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.content;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.query.QueryFindAllInstances;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ResolveState;
+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.services.container.query.QueryCardinality;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.Persistability;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+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.OneToOneAssociation;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.Persistor;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.ImageFactory;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Placement;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public abstract class AbstractObjectContent extends AbstractContent implements ObjectContent {
+
+ public static final class ExplorationInstances extends UserActionAbstract {
+
+ public ExplorationInstances() {
+ super("Instances", ActionType.EXPLORATION);
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ return ConsentAbstract.allowIf(object != null);
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ final ObjectSpecification spec = object.getSpecification();
+ final ObjectAdapter instances = IsisContext.getPersistenceSession().findInstances(new QueryFindAllInstances(spec.getFullIdentifier()), QueryCardinality.MULTIPLE);
+ workspace.objectActionResult(instances, new Placement(view));
+ }
+ }
+
+ public static final class ExplorationClone extends UserActionAbstract {
+
+ public ExplorationClone() {
+ super("Clone", ActionType.EXPLORATION);
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ return ConsentAbstract.allowIf(object != null);
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final ObjectAdapter original = view.getContent().getAdapter();
+ // ObjectAdapter original = getObject();
+ final ObjectSpecification spec = original.getSpecification();
+
+ final ObjectAdapter clone = getPersistenceSession().createTransientInstance(spec);
+ final List<ObjectAssociation> fields = spec.getAssociations();
+ for (int i = 0; i < fields.size(); i++) {
+ final ObjectAdapter fld = fields.get(i).get(original);
+
+ if (fields.get(i).isOneToOneAssociation()) {
+ ((OneToOneAssociation) fields.get(i)).setAssociation(clone, fld);
+ } else if (fields.get(i).isOneToManyAssociation()) {
+ // clone.setValue((OneToOneAssociation) fields[i],
+ // fld.getObject());
+ }
+ }
+
+ workspace.objectActionResult(clone, new Placement(view));
+ }
+ }
+
+ public static final class DebugClearResolvedOption extends UserActionAbstract {
+
+ private DebugClearResolvedOption() {
+ super("Clear resolved", ActionType.DEBUG);
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ return ConsentAbstract.allowIf(object == null || !object.isTransient() || object.isGhost());
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ object.changeState(ResolveState.GHOST);
+ }
+ }
+
+ // REVIEW: should provide this rendering context, rather than hardcoding.
+ // the net effect currently is that class members annotated with
+ // @Hidden(where=Where.ANYWHERE) or @Disabled(where=Where.ANYWHERE) will indeed
+ // be hidden/disabled, but will be visible/enabled (perhaps incorrectly)
+ // for any other value for Where
+ protected final Where where = Where.ANYWHERE;
+
+ @Override
+ public abstract Consent canClear();
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ final ObjectAdapter target = getObject();
+ if (!(sourceContent instanceof ObjectContent) || target == null) {
+ // TODO: move logic into Facet
+ return new Veto(String.format("Can't drop %s onto empty target", sourceContent.getAdapter().titleString()));
+ } else {
+ final ObjectAdapter source = ((ObjectContent) sourceContent).getObject();
+ return canDropOntoObject(target, source);
+ }
+ }
+
+ private Consent canDropOntoObject(final ObjectAdapter target, final ObjectAdapter source) {
+ final ObjectAction action = dropAction(source, target);
+ if (action != null) {
+ final Consent parameterSetValid = action.isProposedArgumentSetValid(target, new ObjectAdapter[] { source });
+ parameterSetValid.setDescription("Execute '" + action.getName() + "' with " + source.titleString());
+ return parameterSetValid;
+ } else {
+ return setFieldOfMatchingType(target, source);
+ }
+ }
+
+ private Consent setFieldOfMatchingType(final ObjectAdapter targetAdapter, final ObjectAdapter sourceAdapter) {
+ if (targetAdapter.isTransient() && sourceAdapter.representsPersistent()) {
+ // TODO: use Facet for this test instead.
+ return new Veto("Can't set field in persistent object with reference to non-persistent object");
+ }
+ final List<ObjectAssociation> fields = targetAdapter.getSpecification().getAssociations(ObjectAssociationFilters.dynamicallyVisible(IsisContext.getAuthenticationSession(), targetAdapter, where));
+ for (final ObjectAssociation fld : fields) {
+ if (!fld.isOneToOneAssociation()) {
+ continue;
+ }
+ if (!sourceAdapter.getSpecification().isOfType(fld.getSpecification())) {
+ continue;
+ }
+ if (fld.get(targetAdapter) != null) {
+ continue;
+ }
+ final Consent associationValid = ((OneToOneAssociation) fld).isAssociationValid(targetAdapter, sourceAdapter);
+ if (associationValid.isAllowed()) {
+ return associationValid.setDescription("Set field " + fld.getName());
+ }
+
+ }
+ // TODO: use Facet for this test instead
+ return new Veto(String.format("No empty field accepting object of type %s in %s", sourceAdapter.getSpecification().getSingularName(), title()));
+ }
+
+ @Override
+ public abstract Consent canSet(final ObjectAdapter dragSource);
+
+ @Override
+ public abstract void clear();
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ if (!(sourceContent instanceof ObjectContent)) {
+ return null;
+ }
+
+ final ObjectAdapter source = sourceContent.getAdapter();
+ Assert.assertNotNull(source);
+
+ final ObjectAdapter target = getObject();
+ Assert.assertNotNull(target);
+
+ if (!canDrop(sourceContent).isAllowed()) {
+ return null;
+ }
+
+ final ObjectAction action = dropAction(source, target);
+ if ((action != null) && action.isProposedArgumentSetValid(target, new ObjectAdapter[] { source }).isAllowed()) {
+ return action.execute(target, new ObjectAdapter[] { source });
+ }
+
+ final List<ObjectAssociation> associations = target.getSpecification().getAssociations(ObjectAssociationFilters.dynamicallyVisible(IsisContext.getAuthenticationSession(), target, where));
+
+ for (int i = 0; i < associations.size(); i++) {
+ final ObjectAssociation association = associations.get(i);
+ if (association.isOneToOneAssociation() && source.getSpecification().isOfType(association.getSpecification())) {
+ final OneToOneAssociation otoa = (OneToOneAssociation) association;
+ if (association.get(target) == null && otoa.isAssociationValid(target, source).isAllowed()) {
+ otoa.setAssociation(target, source);
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private ObjectAction dropAction(final ObjectAdapter source, final ObjectAdapter target) {
+ final ObjectAction action = target.getSpecification().getObjectAction(ActionType.USER, null, Arrays.asList(source.getSpecification()));
+ return action;
+ }
+
+ @Override
+ public abstract ObjectAdapter getObject();
+
+ @Override
+ public boolean isPersistable() {
+ return getObject().getSpecification().persistability() == Persistability.USER_PERSISTABLE;
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ final ObjectAdapter object = getObject();
+ options.addObjectMenuOptions(object);
+
+ if (getObject() == null) {
+ options.addCreateOptions(getSpecification());
+ } else {
+ options.add(new ExplorationInstances());
+ }
+
+ options.add(new ExplorationClone());
+ options.add(new DebugClearResolvedOption());
+ }
+
+ public void parseTextEntry(final String entryText) {
+ throw new UnexpectedCallException();
+ }
+
+ @Override
+ public abstract void setObject(final ObjectAdapter object);
+
+ @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();
+ if (adapter == null) {
+ return ImageFactory.getInstance().loadIcon("empty-field", iconHeight, null);
+ }
+ final ObjectSpecification specification = adapter.getSpecification();
+ final Image icon = ImageFactory.getInstance().loadIcon(specification, iconHeight, null);
+ return icon;
+ }
+
+ // ////////////////////////////////////////////////////////////
+ // Dependencies (from context)
+ // ////////////////////////////////////////////////////////////
+
+ private static Persistor getPersistenceSession() {
+ return IsisContext.getPersistenceSession();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractTextParsableContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractTextParsableContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractTextParsableContent.java
new file mode 100644
index 0000000..6b60e51
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/AbstractTextParsableContent.java
@@ -0,0 +1,82 @@
+/*
+ * 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.content;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ParseableEntryActionParameter;
+import org.apache.isis.viewer.dnd.drawing.Image;
+
+public abstract class AbstractTextParsableContent extends AbstractContent {
+
+ public abstract void clear();
+
+ public abstract void entryComplete();
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return null;
+ }
+
+ public abstract boolean isEmpty();
+
+ @Override
+ public boolean isPersistable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return false;
+ }
+
+ public abstract void parseTextEntry(final String entryText);
+
+ public abstract Consent isEditable();
+
+ @Override
+ public boolean isTextParseable() {
+ return true;
+ }
+
+ /**
+ * @param propertyOrParamValue
+ * the target property or parameter
+ * @param propertyOrParam
+ * the {@link ObjectAssociation} or
+ * {@link ParseableEntryActionParameter}
+ * @param propertyOrParamTypeSpecification
+ * the specification of the type of the property or parameter
+ * (for fallback).
+ */
+ protected String titleString(final ObjectAdapter propertyOrParamValue, final FacetHolder propertyOrParam, final FacetHolder propertyOrParamTypeSpecification) {
+
+ final TitleFacet titleFacet = propertyOrParam.getFacet(TitleFacet.class);
+ if (titleFacet != null) {
+ return titleFacet.title(propertyOrParamValue, null);
+ } else {
+ return propertyOrParamValue.titleString();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/FieldContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/FieldContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/FieldContent.java
new file mode 100644
index 0000000..06b4dce
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/FieldContent.java
@@ -0,0 +1,38 @@
+/*
+ * 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.content;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.view.Content;
+
+public interface FieldContent extends Content {
+
+ String getFieldName();
+
+ ObjectAssociation getField();
+
+ boolean isMandatory();
+
+ Consent isEditable();
+
+ ObjectAdapter getParent();
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/NullContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/NullContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/NullContent.java
new file mode 100644
index 0000000..24d6fa1
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/NullContent.java
@@ -0,0 +1,147 @@
+/*
+ * 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.content;
+
+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.spec.ObjectSpecification;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+
+public class NullContent implements Content {
+
+ private final String title;
+
+ public NullContent() {
+ this("");
+ }
+
+ public NullContent(final String title) {
+ this.title = title;
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return null;
+ }
+
+ @Override
+ public void contentMenuOptions(final UserActionSet options) {
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return null;
+ }
+
+ @Override
+ public String getHelp() {
+ return null;
+ }
+
+ @Override
+ public String getIconName() {
+ return null;
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return null;
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return null;
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return null;
+ }
+
+ @Override
+ public boolean isCollection() {
+ return false;
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistable() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return false;
+ }
+
+ @Override
+ public boolean isTextParseable() {
+ return false;
+ }
+
+ public void parseTextEntry(final String entryText) {
+ }
+
+ @Override
+ public String title() {
+ return title;
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ }
+
+ @Override
+ public String windowTitle() {
+ return title;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/RootObject.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/RootObject.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/RootObject.java
new file mode 100644
index 0000000..0832c5b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/RootObject.java
@@ -0,0 +1,131 @@
+/*
+ * 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.content;
+
+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.Veto;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.dnd.view.Content;
+
+public class RootObject extends AbstractObjectContent {
+ private final ObjectAdapter adapter;
+
+ public RootObject(final ObjectAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ @Override
+ public Consent canClear() {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return super.canDrop(sourceContent);
+ }
+
+ @Override
+ public Consent canSet(final ObjectAdapter dragSource) {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public void clear() {
+ throw new IsisException("Invalid call");
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ debug.appendln("object", adapter);
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return adapter;
+ }
+
+ @Override
+ public String getDescription() {
+ return getSpecification().getSingularName() + ": " + getObject().titleString() + " " + getSpecification().getDescription();
+ }
+
+ @Override
+ public String getHelp() {
+ return "";
+ }
+
+ @Override
+ public String getId() {
+ return "";
+ }
+
+ @Override
+ public ObjectAdapter getObject() {
+ return adapter;
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return null;
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return adapter.getSpecification();
+ }
+
+ @Override
+ public boolean isObject() {
+ return true;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return adapter != null && adapter.isTransient();
+ }
+
+ @Override
+ public void setObject(final ObjectAdapter object) {
+ throw new IsisException("Invalid call");
+ }
+
+ @Override
+ public String title() {
+ return adapter.titleString();
+ }
+
+ @Override
+ public String toString() {
+ return "Root Object [adapter=" + adapter + "]";
+ }
+
+ @Override
+ public String windowTitle() {
+ return (isTransient() ? "UNSAVED " : "") + getSpecification().getSingularName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/TextParseableContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/TextParseableContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/TextParseableContent.java
new file mode 100644
index 0000000..ab6d3fc
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/content/TextParseableContent.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.content;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.viewer.dnd.view.Content;
+
+public interface TextParseableContent extends Content {
+
+ void clear();
+
+ Consent canClear();
+
+ boolean canWrap();
+
+ void entryComplete();
+
+ int getMaximumLength();
+
+ int getNoLines();
+
+ int getTypicalLineLength();
+
+ Consent isEditable();
+
+ boolean isEmpty();
+
+ void parseTextEntry(String entryText);
+
+ String titleString(ObjectAdapter value);
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/control/AbstractButtonAction.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/control/AbstractButtonAction.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/control/AbstractButtonAction.java
new file mode 100644
index 0000000..a2316d6
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/control/AbstractButtonAction.java
@@ -0,0 +1,70 @@
+/*
+ * 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.control;
+
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.viewer.dnd.view.ButtonAction;
+import org.apache.isis.viewer.dnd.view.View;
+
+public abstract class AbstractButtonAction implements ButtonAction {
+ private final String name;
+ private final boolean defaultButton;
+
+ public AbstractButtonAction(final String name) {
+ this(name, false);
+ }
+
+ public AbstractButtonAction(final String name, final boolean defaultButton) {
+ this.name = name;
+ this.defaultButton = defaultButton;
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "";
+ }
+
+ @Override
+ public String getHelp(final View view) {
+ return "No help available for button";
+ }
+
+ @Override
+ public String getName(final View view) {
+ return name;
+ }
+
+ @Override
+ public ActionType getType() {
+ return ActionType.USER;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return defaultButton;
+ }
+}