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:02 UTC
[27/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/menu/PopupMenu.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenu.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenu.java
new file mode 100644
index 0000000..b8d9a47
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenu.java
@@ -0,0 +1,606 @@
+/*
+ * 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.menu;
+
+import java.awt.event.KeyEvent;
+import java.util.Vector;
+
+import org.apache.log4j.Logger;
+
+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.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Padding;
+import org.apache.isis.viewer.dnd.drawing.Shape;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserAction;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.content.AbstractContent;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.window.SubviewFocusManager;
+
+public class PopupMenu extends AbstractView {
+
+ private static class Item {
+ public static Item createDivider() {
+ final Item item = new Item();
+ item.isBlank = true;
+ return item;
+ }
+
+ public static Item createNoOption() {
+ final Item item = new Item();
+ item.name = "no options";
+ return item;
+ }
+
+ public static Item createOption(final UserAction action, final Object object, final View view, final Location location) {
+ final Item item = new Item();
+ if (action == null) {
+ item.isBlank = true;
+ } else {
+ item.isBlank = false;
+ item.action = action;
+ item.view = view;
+ item.name = action.getName(view);
+ item.description = action.getDescription(view);
+ final Consent consent = action.disabled(view);
+ item.isDisabled = consent.isVetoed();
+ item.reasonDisabled = consent.getReason();
+ }
+ return item;
+ }
+
+ UserAction action;
+ String description;
+ boolean isBlank;
+ boolean isDisabled;
+ String name;
+ String reasonDisabled;
+ View view;
+
+ private Item() {
+ }
+
+ public String getHelp() {
+ return action.getHelp(view);
+ }
+
+ @Override
+ public String toString() {
+ return isBlank ? "NONE" : (name + " " + (isDisabled ? "DISABLED " : " " + action));
+ }
+ }
+
+ private class PopupContent extends AbstractContent {
+
+ public PopupContent() {
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public void debugDetails(final DebugBuilder debug) {
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ final int optionNo = getOption();
+ return items[optionNo].description;
+ }
+
+ @Override
+ public String getHelp() {
+ final int optionNo = getOption();
+ return items[optionNo].getHelp();
+ }
+
+ @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 boolean isOptionEnabled() {
+ return false;
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ return null;
+ }
+
+ @Override
+ public boolean isTransient() {
+ return false;
+ }
+
+ public void parseTextEntry(final String entryText) {
+ }
+
+ @Override
+ public String title() {
+ final int optionNo = getOption();
+ return items[optionNo].name;
+ }
+
+ @Override
+ public ObjectAdapter[] getOptions() {
+ return null;
+ }
+ }
+
+ private static class PopupSpecification implements ViewSpecification {
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return false;
+ }
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return "Popup Menu";
+ }
+
+ @Override
+ public boolean isAligned() {
+ return false;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return false;
+ }
+
+ @Override
+ public boolean isSubView() {
+ return false;
+ }
+ }
+
+ private static final Logger LOG = Logger.getLogger(PopupMenu.class);
+ private Color backgroundColor;
+ private View forView;
+ private Item[] items = new Item[0];
+ private int optionIdentified;
+ private final FocusManager simpleFocusManager;
+
+ public PopupMenu(final PopupMenuContainer parent) {
+ super(new NullContent(), new PopupSpecification());
+ // REVIEW should this content be used as param 1 above?
+ setContent(new PopupContent());
+ setParent(parent);
+ simpleFocusManager = new SubviewFocusManager(this);
+ }
+
+ private void addItems(final View target, final UserAction[] options, final int len, final Vector<Item> list, final ActionType type) {
+ final int initialSize = list.size();
+ for (int i = 0; i < len; i++) {
+ if (options[i].getType() == type) {
+ if (initialSize > 0 && list.size() == initialSize) {
+ list.addElement(Item.createDivider());
+ }
+ list.addElement(Item.createOption(options[i], null, target, getLocation()));
+ }
+ }
+ }
+
+ protected Color backgroundColor() {
+ return backgroundColor;
+ }
+
+ @Override
+ public Consent canChangeValue() {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public boolean canFocus() {
+ return true;
+ }
+
+ protected Color disabledColor() {
+ return Toolkit.getColor(ColorsAndFonts.COLOR_MENU_DISABLED);
+ }
+
+ /**
+ * Draws the popup menu
+ *
+ * @see java.awt.Component#paint(java.awt.Graphics)
+ */
+ @Override
+ public void draw(final Canvas canvas) {
+ final Size coreSize = getSize();
+ final int width = coreSize.getWidth();
+ final int height = coreSize.getHeight();
+ canvas.drawSolidRectangle(0, 0, width, height, backgroundColor);
+ canvas.draw3DRectangle(0, 0, width, height, backgroundColor, true);
+
+ final int itemHeight = style().getLineHeight() + ViewConstants.VPADDING;
+ // int baseLine = itemHeight / 2 + style().getAscent() / 2 +
+ // getPadding().getTop();
+ int baseLine = style().getAscent() + getPadding().getTop() + 1;
+ final int left = getPadding().getLeft();
+ for (int i = 0; i < items.length; i++) {
+ if (items[i].isBlank) {
+ final int y = baseLine - (style().getAscent() / 2);
+ canvas.drawLine(1, y, width - 2, y, backgroundColor.brighter());
+ canvas.drawLine(1, y - 1, width - 2, y - 1, backgroundColor.darker());
+ } else {
+ Color color;
+ if (items[i].isDisabled || items[i].action == null) {
+ color = disabledColor();
+ } else if (getOption() == i) {
+ final int top = getPadding().getTop() + i * itemHeight;
+ final int depth = style().getLineHeight() + 2;
+ canvas.drawSolidRectangle(2, top, width - 4, depth, backgroundColor.darker());
+ canvas.draw3DRectangle(2, top, width - 4, depth + 1, backgroundColor.brighter(), false);
+ // canvas.drawText(items[i].name, left, baseLine,
+ // normalColor(), style());
+
+ color = reversedColor();
+ } else {
+ color = normalColor();
+ }
+ canvas.drawText(items[i].name, left, baseLine, color, style());
+ if (items[i].action instanceof UserActionSet) {
+ Shape arrow;
+ arrow = new Shape(0, 0);
+ arrow.addVector(4, 4);
+ arrow.addVector(-4, 4);
+ canvas.drawSolidShape(arrow, width - 10, baseLine - 8, color);
+ }
+ }
+
+ baseLine += itemHeight;
+ }
+
+ // canvas.drawRectangleAround(this,
+ // Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_VIEW));
+ }
+
+ @Override
+ public void firstClick(final Click click) {
+ if (click.button1() || click.button2()) {
+ mouseMoved(click.getLocation());
+ invoke();
+ }
+ }
+
+ @Override
+ public void focusLost() {
+ }
+
+ @Override
+ public void focusReceived() {
+ }
+
+ @Override
+ public FocusManager getFocusManager() {
+ return simpleFocusManager;
+ }
+
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ final Size size = new Size();
+
+ for (final Item item : items) {
+ final int itemWidth = item.isBlank ? 0 : style().stringWidth(item.name);
+ size.ensureWidth(itemWidth);
+ size.extendHeight(style().getLineHeight() + ViewConstants.VPADDING);
+ }
+
+ size.extend(getPadding());
+ size.extendWidth(ViewConstants.HPADDING * 2);
+ return size;
+ }
+
+ public int getOption() {
+ return optionIdentified;
+ }
+
+ public int getOptionPostion() {
+ final int itemHeight = style().getLineHeight() + ViewConstants.VPADDING;
+ return itemHeight * getOption();
+ }
+
+ public int getOptionCount() {
+ return items.length;
+ }
+
+ @Override
+ public Padding getPadding() {
+ final Padding in = super.getPadding();
+ in.extendTop(ViewConstants.VPADDING);
+ in.extendBottom(ViewConstants.VPADDING);
+ in.extendLeft(ViewConstants.HPADDING + 5);
+ in.extendRight(ViewConstants.HPADDING + 5);
+
+ return in;
+ }
+
+ @Override
+ public Workspace getWorkspace() {
+ return forView.getWorkspace();
+ }
+
+ @Override
+ public boolean hasFocus() {
+ return false;
+ }
+
+ private void invoke() {
+ final int option = getOption();
+ final Item item = items[option];
+ if (item.isBlank || item.action == null || item.action.disabled(forView).isVetoed()) {
+ return;
+
+ } else if (item.action instanceof UserActionSet) {
+ final UserAction[] menuOptions = ((UserActionSet) item.action).getUserActions();
+ ((PopupMenuContainer) getParent()).openSubmenu(menuOptions);
+ } else {
+ final Workspace workspace = getWorkspace();
+
+ final Location location = new Location(getAbsoluteLocation());
+ location.subtract(workspace.getView().getAbsoluteLocation());
+ final Padding padding = workspace.getView().getPadding();
+ location.move(-padding.getLeft(), -padding.getTop());
+
+ final int itemHeight = style().getLineHeight() + ViewConstants.VPADDING;
+ final int baseLine = itemHeight * option;
+ location.add(0, baseLine);
+
+ getParent().dispose();
+ LOG.debug("execute " + item.name + " on " + forView + " in " + workspace);
+ item.action.execute(workspace, forView, location);
+ }
+ }
+
+ @Override
+ public void keyPressed(final KeyboardAction key) {
+ final int keyCode = key.getKeyCode();
+
+ if (keyCode == KeyEvent.VK_ESCAPE) {
+ if (getParent() == null) {
+ dispose();
+ }
+
+ key.consume();
+
+ } else if (keyCode == KeyEvent.VK_ENTER) {
+ key.consume();
+ invoke();
+
+ } else if (keyCode == KeyEvent.VK_RIGHT && items[getOption()].action instanceof UserActionSet) {
+ key.consume();
+ invoke();
+
+ } else if (keyCode == KeyEvent.VK_UP) {
+ key.consume();
+ if (optionIdentified == 0) {
+ optionIdentified = items.length;
+ }
+
+ for (int i = optionIdentified - 1; i >= 0; i--) {
+ if (items[i].isBlank) {
+ continue;
+ }
+ if (items[i].isDisabled) {
+ continue;
+ }
+ setOption(i);
+ break;
+ }
+
+ } else if (keyCode == KeyEvent.VK_DOWN) {
+ key.consume();
+ if (optionIdentified == items.length - 1) {
+ optionIdentified = -1;
+ }
+
+ for (int i = optionIdentified + 1; i < items.length; i++) {
+ if (items[i].isBlank) {
+ continue;
+ }
+ if (items[i].isDisabled) {
+ continue;
+ }
+ setOption(i);
+ break;
+ }
+ }
+
+ }
+
+ @Override
+ public void keyReleased(final KeyboardAction action) {
+ }
+
+ @Override
+ public void keyTyped(final KeyboardAction action) {
+ }
+
+ /*
+ * @Override public void layout(final Size maximumSize) { coreSize = new
+ * Bounds(getCoreRequiredSize());
+ *
+ * final int option = getOption(); final int itemHeight =
+ * style().getLineHeight() + VPADDING; int menuWidth = coreSize.getWidth();
+ * // Location menuLocation = new Location(menuWidth - 4, itemHeight *
+ * option); Location menuLocation = new Location(0, itemHeight * option);
+ *
+ * if (submenu != null) { submenu.layout(maximumSize);
+ * submenu.setLocation(menuLocation);
+ *
+ * //coreSize.setX(submenu.getSize().getWidth() - 4); //getLocation() }
+ * setSize(getMaximumSize()); }
+ */
+ public View makeView(final ObjectAdapter object, final ObjectAssociation field) throws CloneNotSupportedException {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public void markDamaged() {
+ if (getParent() == null) {
+ super.markDamaged();
+ } else {
+ getParent().markDamaged();
+ }
+ // markDamaged(new Bounds(getAbsoluteLocation(), getSize()));
+ // ///getView().getBounds());
+ }
+
+ @Override
+ public void mouseMoved(final Location at) {
+ int option = (at.getY() - getPadding().getTop()) / (style().getLineHeight() + ViewConstants.VPADDING);
+ option = Math.max(option, 0);
+ option = Math.min(option, items.length - 1);
+ if (option >= 0 && optionIdentified != option) {
+ // LOG.debug("mouse over option " + option + " " + this);
+ setOption(option);
+ markDamaged();
+ }
+ }
+
+ protected Color normalColor() {
+ return Toolkit.getColor(ColorsAndFonts.COLOR_MENU);
+ }
+
+ protected Color reversedColor() {
+ return Toolkit.getColor(ColorsAndFonts.COLOR_MENU_REVERSED);
+ }
+
+ public void setOption(final int option) {
+ if (option != optionIdentified) {
+ optionIdentified = option;
+ markDamaged();
+ updateFeedback();
+ }
+ }
+
+ private void updateFeedback() {
+ final Item item = items[optionIdentified];
+ if (item.isBlank) {
+ getFeedbackManager().clearAction();
+ } else if (isEmpty(item.reasonDisabled)) {
+ getFeedbackManager().setAction(item.description == null ? "" : item.description);
+ } else {
+ getFeedbackManager().setAction(item.reasonDisabled);
+ }
+ }
+
+ private boolean isEmpty(final String str) {
+ return str == null || str.length() == 0;
+ }
+
+ void show(final View target, final UserAction[] options, final Color color) {
+ this.forView = target;
+
+ optionIdentified = 0;
+ backgroundColor = color;
+
+ final int len = options.length;
+ if (len == 0) {
+ items = new Item[] { Item.createNoOption() };
+ } else {
+ final Vector list = new Vector();
+ addItems(target, options, len, list, ActionType.USER);
+ addItems(target, options, len, list, ActionType.EXPLORATION);
+ addItems(target, options, len, list, ActionType.PROTOTYPE);
+ addItems(target, options, len, list, ActionType.DEBUG);
+ items = new Item[list.size()];
+ list.copyInto(items);
+ }
+
+ updateFeedback();
+ }
+
+ protected Text style() {
+ return Toolkit.getText(ColorsAndFonts.TEXT_MENU);
+ }
+
+ @Override
+ public String toString() {
+ return "PopupMenu [location=" + getLocation() + ",item=" + optionIdentified + ",itemCount=" + (items == null ? 0 : items.length) + "]";
+ }
+
+ protected boolean transparentBackground() {
+ 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/menu/PopupMenuContainer.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenuContainer.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenuContainer.java
new file mode 100644
index 0000000..1e2f29c
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/PopupMenuContainer.java
@@ -0,0 +1,304 @@
+/*
+ * 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.menu;
+
+import java.awt.event.KeyEvent;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.KeyboardAction;
+import org.apache.isis.viewer.dnd.view.MenuOptions;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserAction;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.debug.DebugOption;
+
+public class PopupMenuContainer extends AbstractView {
+ private static final int MENU_OVERLAP = 4;
+ private static final UserAction DEBUG_OPTION = new DebugOption();
+ private PopupMenu menu;
+ private PopupMenu submenu;
+ private Color backgroundColor;
+ private final View target;
+ private final Vector options = new Vector();
+ private final Location at;
+ private boolean isLayoutInvalid;
+
+ public PopupMenuContainer(final View target, final Location at) {
+ super(new NullContent());
+ this.target = target;
+ this.at = at;
+ setLocation(at);
+ isLayoutInvalid = true;
+ }
+
+ @Override
+ public void debug(final DebugBuilder debug) {
+ super.debug(debug);
+ debug.appendTitle("Submenu");
+ debug.append(submenu);
+ debug.append("\n");
+ }
+
+ @Override
+ public void dispose() {
+ if (getParent() == null) {
+ super.dispose();
+ getViewManager().clearOverlayView(this);
+ } else {
+ getParent().dispose();
+ }
+ }
+
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ final Size size = menu.getRequiredSize(Size.createMax());
+ if (submenu != null) {
+ final Size subviewSize = submenu.getRequiredSize(Size.createMax());
+ size.extendWidth(subviewSize.getWidth() - MENU_OVERLAP);
+ size.ensureHeight(submenuOffset() + subviewSize.getHeight());
+ }
+ return size;
+ }
+
+ @Override
+ public void layout() {
+ if (isLayoutInvalid) {
+ menu.layout();
+ final Size menuSize = menu.getRequiredSize(Size.createMax());
+ menu.setSize(menuSize);
+ menu.setLocation(new Location(0, 0));
+
+ final Location containerLocation = new Location(at);
+ final Size bounds = getViewManager().getOverlaySize();
+ if (containerLocation.getX() < 0) {
+ containerLocation.setX(0);
+ } else if (containerLocation.getX() + menuSize.getWidth() > bounds.getWidth()) {
+ containerLocation.setX(bounds.getWidth() - menuSize.getWidth());
+ }
+
+ if (containerLocation.getY() < 0) {
+ containerLocation.setY(0);
+ } else if (containerLocation.getY() + menuSize.getHeight() > bounds.getHeight()) {
+ containerLocation.setY(bounds.getHeight() - menuSize.getHeight());
+ }
+
+ if (submenu != null) {
+ submenu.layout();
+ final Size submenuSize = submenu.getRequiredSize(Size.createMax());
+ submenu.setSize(submenuSize);
+
+ int submenuOffset = submenuOffset();
+ final Location menuLocation = new Location();
+
+ final int containerBottom = containerLocation.getY() + submenuOffset + submenuSize.getHeight();
+ if (containerBottom > bounds.getHeight()) {
+ final int overstretch = containerBottom - bounds.getHeight();
+ submenuOffset -= overstretch;
+ }
+ final Location submenuLocation = new Location(0, submenuOffset);
+
+ final boolean placeToLeft = at.getX() + menuSize.getWidth() + submenuSize.getWidth() < getViewManager().getOverlaySize().getWidth();
+ if (placeToLeft) {
+ submenuLocation.setX(menuSize.getWidth() - MENU_OVERLAP);
+ } else {
+ menuLocation.setX(submenuSize.getWidth() - MENU_OVERLAP);
+ containerLocation.move(-submenu.getSize().getWidth() + MENU_OVERLAP, 0);
+ }
+
+ if (containerLocation.getY() + menuSize.getHeight() > bounds.getHeight()) {
+ containerLocation.setY(bounds.getHeight() - menuSize.getHeight());
+ }
+
+ submenu.setLocation(submenuLocation); // // !
+ menu.setLocation(menuLocation); // / !
+
+ }
+
+ setLocation(containerLocation);
+
+ }
+ }
+
+ private int submenuOffset() {
+ return menu.getOptionPostion();
+ }
+
+ @Override
+ public void mouseMoved(final Location at) {
+ if (menu.getBounds().contains(at)) {
+ at.subtract(menu.getLocation());
+ menu.mouseMoved(at);
+ } else if (submenu != null && submenu.getBounds().contains(at)) {
+ at.subtract(submenu.getLocation());
+ submenu.mouseMoved(at);
+ }
+ }
+
+ public void show(final boolean forView, final boolean includeDebug, final boolean includeExploration, final boolean includePrototype) {
+ final boolean withExploration = getViewManager().isRunningAsExploration() && includeExploration;
+ final boolean withPrototype = getViewManager().isRunningAsPrototype() && includePrototype;
+
+ final UserActionSet optionSet = new UserActionSetImpl(withExploration, withPrototype, includeDebug, ActionType.USER);
+ if (forView) {
+ target.viewMenuOptions(optionSet);
+ } else {
+ target.contentMenuOptions(optionSet);
+ }
+ optionSet.add(DEBUG_OPTION);
+ final Enumeration e = options.elements();
+ while (e.hasMoreElements()) {
+ final MenuOptions element = (MenuOptions) e.nextElement();
+ element.menuOptions(optionSet);
+ }
+
+ menu = new PopupMenu(this);
+
+ backgroundColor = optionSet.getColor();
+ menu.show(target, optionSet.getUserActions(), backgroundColor);
+ getViewManager().setOverlayView(this);
+
+ if (target != null) {
+ final String status = changeStatus(target, forView, withExploration, includeDebug);
+ getFeedbackManager().setViewDetail(status);
+ }
+ }
+
+ private String changeStatus(final View over, final boolean forView, final boolean includeExploration, final boolean includeDebug) {
+ final StringBuffer status = new StringBuffer("Menu for ");
+ if (forView) {
+ status.append("view ");
+ status.append(over.getSpecification().getName());
+ } else {
+ status.append("object");
+ final Content content = over.getContent();
+ if (content != null) {
+ status.append(" '");
+ status.append(content.title());
+ status.append("'");
+ }
+
+ }
+ if (includeDebug || includeExploration) {
+ status.append(" (includes ");
+ if (includeExploration) {
+ status.append("exploration");
+ }
+ if (includeDebug) {
+ if (includeExploration) {
+ status.append(" & ");
+ }
+ status.append("debug");
+ }
+ status.append(" options)");
+ }
+ return status.toString();
+ }
+
+ public void addMenuOptions(final MenuOptions options) {
+ this.options.addElement(options);
+ }
+
+ void openSubmenu(final UserAction[] options) {
+ markDamaged();
+
+ submenu = new PopupMenu(this);
+ submenu.setParent(this);
+ submenu.show(target, options, backgroundColor);
+ invalidateLayout();
+ final Size size = getRequiredSize(Size.createMax());
+ setSize(size);
+ layout();
+
+ isLayoutInvalid = false;
+
+ markDamaged();
+ }
+
+ @Override
+ public void keyPressed(final KeyboardAction key) {
+ if (submenu != null) {
+ final int keyCode = key.getKeyCode();
+ if (keyCode == KeyEvent.VK_ESCAPE) {
+ markDamaged();
+ invalidateLayout();
+ submenu = null;
+ key.consume();
+
+ } else if (getParent() != null && keyCode == KeyEvent.VK_LEFT) {
+ markDamaged();
+ invalidateLayout();
+ submenu = null;
+ key.consume();
+ } else {
+ submenu.keyPressed(key);
+ }
+ } else {
+ menu.keyPressed(key);
+ }
+ }
+
+ @Override
+ public void invalidateLayout() {
+ isLayoutInvalid = true;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+ if (menu != null) {
+ final Canvas menuCanvas = canvas.createSubcanvas(menu.getBounds());
+ menu.draw(menuCanvas);
+ }
+ if (submenu != null) {
+ final Canvas submenuCanvas = canvas.createSubcanvas(submenu.getBounds());
+ submenu.draw(submenuCanvas);
+ }
+
+ if (Toolkit.debug) {
+ canvas.drawRectangleAround(getBounds(), Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_VIEW));
+ }
+ }
+
+ @Override
+ public void firstClick(final Click click) {
+ final Location location = click.getLocation();
+ if (menu.getBounds().contains(location)) {
+ click.subtract(menu.getLocation());
+ menu.firstClick(click);
+ } else if (submenu != null && submenu.getBounds().contains(location)) {
+ click.subtract(submenu.getLocation());
+ submenu.firstClick(click);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/UserActionSetImpl.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/UserActionSetImpl.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/UserActionSetImpl.java
new file mode 100644
index 0000000..d24f8e3
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/menu/UserActionSetImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.menu;
+
+import java.util.Vector;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UserAction;
+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.action.OptionFactory;
+
+public class UserActionSetImpl implements UserActionSet {
+
+ private Color backgroundColor;
+
+ private final String groupName;
+ private final boolean includeDebug;
+ private final boolean includeExploration;
+ private final boolean includePrototype;
+ private final Vector options = new Vector();
+ private final ActionType type;
+
+ public UserActionSetImpl(final boolean includeExploration, final boolean includePrototype, final boolean includeDebug, final ActionType type) {
+ this("", type, includeExploration, includePrototype, includeDebug, Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BASELINE));
+ }
+
+ private UserActionSetImpl(final String groupName, final UserActionSetImpl parent) {
+ this(groupName, parent, parent.getType());
+ }
+
+ private UserActionSetImpl(final String groupName, final UserActionSetImpl parent, final ActionType type) {
+ this(groupName, type, parent.includeExploration, parent.includePrototype, parent.includeDebug, parent.getColor());
+ }
+
+ private UserActionSetImpl(final String groupName, final ActionType type, final boolean includeExploration, final boolean includePrototype, final boolean includeDebug, final Color backgroundColor) {
+ this.groupName = groupName;
+ this.type = type;
+ this.includeExploration = includeExploration;
+ this.includePrototype = includePrototype;
+ this.includeDebug = includeDebug;
+ this.backgroundColor = backgroundColor;
+ }
+
+ @Override
+ public UserActionSet addNewActionSet(final String name) {
+ final UserActionSetImpl set = new UserActionSetImpl(name, this);
+ add(set);
+ return set;
+ }
+
+ @Override
+ public UserActionSet addNewActionSet(final String name, final ActionType type) {
+ final UserActionSetImpl set = new UserActionSetImpl(name, this, type);
+ add(set);
+ return set;
+ }
+
+ /**
+ * Add the specified option if it is of the right type for this menu.
+ */
+ @Override
+ public void add(final UserAction option) {
+ final ActionType section = option.getType();
+ if (section == ActionType.USER || (includeExploration && section == ActionType.EXPLORATION) || (includePrototype && section == ActionType.PROTOTYPE) || (includeDebug && section == ActionType.DEBUG)) {
+ options.addElement(option);
+ }
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ }
+
+ /**
+ * Returns the background colour for the menu
+ */
+ @Override
+ public Color getColor() {
+ return backgroundColor;
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "";
+ }
+
+ @Override
+ public String getHelp(final View view) {
+ return "";
+ }
+
+ @Override
+ public UserAction[] getUserActions() {
+ final UserAction[] v = new UserAction[options.size()];
+ for (int i = 0; i < v.length; i++) {
+ v[i] = (UserAction) options.elementAt(i);
+ }
+ return v;
+ }
+
+ @Override
+ public String getName(final View view) {
+ return groupName;
+ }
+
+ @Override
+ public ActionType getType() {
+ return type;
+ }
+
+ /**
+ * Specifies the background colour for the menu
+ */
+ @Override
+ public void setColor(final Color color) {
+ backgroundColor = color;
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("type", type);
+ for (int i = 0, size = options.size(); i < size; i++) {
+ str.append(((UserAction) options.elementAt(i)).getClass() + " ,");
+ }
+ return str.toString();
+ }
+
+ @Override
+ public void addCreateOptions(final ObjectSpecification specification) {
+ OptionFactory.addCreateOptions(specification, this);
+ }
+
+ @Override
+ public void addObjectMenuOptions(final ObjectAdapter object) {
+ OptionFactory.addObjectMenuOptions(object, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/DetailedMessageViewSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/DetailedMessageViewSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/DetailedMessageViewSpecification.java
new file mode 100644
index 0000000..0acae98
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/DetailedMessageViewSpecification.java
@@ -0,0 +1,186 @@
+/*
+ * 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.message;
+
+import java.util.StringTokenizer;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.ButtonAction;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAreaType;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.border.ButtonBorder;
+import org.apache.isis.viewer.dnd.view.border.ScrollBorder;
+import org.apache.isis.viewer.dnd.view.control.AbstractButtonAction;
+import org.apache.isis.viewer.dnd.view.control.CancelAction;
+import org.apache.isis.viewer.dnd.view.debug.DebugOutput;
+
+public class DetailedMessageViewSpecification implements ViewSpecification {
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ final Content content = requirement.getContent();
+ return content instanceof MessageContent && ((MessageContent) content).getDetail() != null;
+ }
+
+ @Override
+ public String getName() {
+ return "Detailed Message";
+ }
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final ButtonAction actions[] = new ButtonAction[] { new AbstractButtonAction("Print...") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ DebugOutput.print("Print exception", extract(view));
+ }
+ }, new AbstractButtonAction("Save...") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ DebugOutput.saveToFile("Save exception", "Exception", extract(view));
+ }
+ }, new AbstractButtonAction("Copy") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ DebugOutput.saveToClipboard(extract(view));
+ }
+ }, new CancelAction(),
+
+ };
+
+ final DetailedMessageView messageView = new DetailedMessageView(content, this);
+ return new ButtonBorder(actions, new ScrollBorder(messageView));
+ }
+
+ private String extract(final View view) {
+ final Content content = view.getContent();
+ final String message = ((MessageContent) content).getMessage();
+ final String heading = ((MessageContent) content).title();
+ final String detail = ((MessageContent) content).getDetail();
+
+ final StringBuffer text = new StringBuffer();
+ text.append(heading);
+ text.append("\n\n");
+ text.append(message);
+ text.append("\n\n");
+ text.append(detail);
+ text.append("\n\n");
+ return text.toString();
+ }
+
+ @Override
+ public boolean isAligned() {
+ return false;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return false;
+ }
+
+ @Override
+ public boolean isSubView() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return true;
+ }
+}
+
+class DetailedMessageView extends AbstractView {
+ protected DetailedMessageView(final Content content, final ViewSpecification specification) {
+ super(content, specification);
+ }
+
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ final Size size = new Size();
+ size.extendHeight(Toolkit.getText(ColorsAndFonts.TEXT_TITLE).getTextHeight());
+ size.extendHeight(30);
+
+ final String message = ((MessageContent) getContent()).getMessage();
+ size.ensureWidth(500);
+ size.extendHeight(Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).stringHeight(message, 500));
+ size.extendHeight(30);
+
+ final String detail = ((MessageContent) getContent()).getDetail();
+ final StringTokenizer st = new StringTokenizer(detail, "\n\r");
+ while (st.hasMoreTokens()) {
+ final String line = st.nextToken();
+ final Text text = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ size.ensureWidth((line.startsWith("\t") ? 20 : 0) + text.stringWidth(line));
+ size.extendHeight(text.getTextHeight());
+ }
+
+ size.extend(40, 20);
+ return size;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+
+ final int left = 10;
+ final Text title = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+ int y = 10 + title.getAscent();
+ final String message = ((MessageContent) getContent()).getMessage();
+ final String heading = ((MessageContent) getContent()).title();
+ final String detail = ((MessageContent) getContent()).getDetail();
+
+ final Color black = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+ canvas.drawText(heading, left, y, black, title);
+ y += title.getTextHeight();
+ final Text text = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ canvas.drawText(message, left, y, 500, black, text);
+
+ y += text.stringHeight(message, 500);
+ canvas.drawText(detail, left, y, 1000, Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1), text);
+ }
+
+ @Override
+ public ViewAreaType viewAreaType(final Location mouseLocation) {
+ return ViewAreaType.VIEW;
+ }
+
+ @Override
+ public void setFocusManager(final FocusManager focusManager) {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/ExceptionMessageContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/ExceptionMessageContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/ExceptionMessageContent.java
new file mode 100644
index 0000000..d43983b
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/ExceptionMessageContent.java
@@ -0,0 +1,191 @@
+/*
+ * 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.message;
+
+import org.apache.isis.core.commons.debug.DebugBuilder;
+import org.apache.isis.core.commons.exceptions.IsisApplicationException;
+import org.apache.isis.core.commons.lang.NameUtils;
+import org.apache.isis.core.commons.lang.ThrowableUtils;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+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.drawing.Image;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+
+public class ExceptionMessageContent implements MessageContent {
+
+ protected String message;
+ protected String name;
+ protected String trace;
+ protected String title;
+ private final String icon;
+
+ public ExceptionMessageContent(final Throwable error) {
+ String fullName = error.getClass().getName();
+ fullName = fullName.substring(fullName.lastIndexOf('.') + 1);
+ name = NameUtils.naturalName(fullName);
+ message = error.getMessage();
+ trace = ThrowableUtils.stackTraceFor(error);
+ if (trace.indexOf("\tat") != -1) {
+ trace = trace.substring(trace.indexOf("\tat"));
+ }
+
+ if (name == null) {
+ name = "";
+ }
+ if (message == null) {
+ message = "";
+ }
+ if (trace == null) {
+ trace = "";
+ }
+
+ if (error instanceof IsisApplicationException) {
+ title = "Application Error";
+ icon = "application-error";
+ } else if (error instanceof ConcurrencyException) {
+ title = "Concurrency Error";
+ icon = "concurrency-error";
+ } else {
+ title = "System Error";
+ icon = "system-error";
+ }
+
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String getDetail() {
+ return trace;
+ }
+
+ @Override
+ public String getIconName() {
+ return icon;
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @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 name;
+ }
+
+ @Override
+ public String getHelp() {
+ return "";
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return "message-exception";
+ }
+
+ @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 name;
+ }
+
+ @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/message/MessageContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageContent.java
new file mode 100644
index 0000000..b8e6c33
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageContent.java
@@ -0,0 +1,28 @@
+/*
+ * 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.message;
+
+import org.apache.isis.viewer.dnd.view.Content;
+
+public interface MessageContent extends Content {
+ String getMessage();
+
+ String getDetail();
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageDialogSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageDialogSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageDialogSpecification.java
new file mode 100644
index 0000000..d7ec4d33
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/MessageDialogSpecification.java
@@ -0,0 +1,183 @@
+/*
+ * 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.message;
+
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.drawing.ImageFactory;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.ButtonAction;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAreaType;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.base.AbstractView;
+import org.apache.isis.viewer.dnd.view.border.ButtonBorder;
+import org.apache.isis.viewer.dnd.view.border.ScrollBorder;
+import org.apache.isis.viewer.dnd.view.control.AbstractButtonAction;
+import org.apache.isis.viewer.dnd.view.window.SubviewFocusManager;
+
+public class MessageDialogSpecification implements ViewSpecification {
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ return requirement.getContent() instanceof MessageContent;
+ }
+
+ @Override
+ public String getName() {
+ return "Message Dialog";
+ }
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ final ButtonAction actions[] = new ButtonAction[] { new CloseViewAction() };
+ final MessageView messageView = new MessageView((MessageContent) content, this);
+ final View dialogView = new ButtonBorder(actions, new ScrollBorder(messageView));
+ dialogView.setFocusManager(new SubviewFocusManager(dialogView));
+ return dialogView;
+ }
+
+ @Override
+ public boolean isAligned() {
+ return false;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return true;
+ }
+
+ @Override
+ public boolean isSubView() {
+ return false;
+ }
+
+ public static class CloseViewAction extends AbstractButtonAction {
+ public CloseViewAction() {
+ super("Close");
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ view.dispose();
+ }
+ }
+}
+
+class MessageView extends AbstractView {
+ private static final int MAX_TEXT_WIDTH = 400;
+ private static final int LEFT = 20;
+ private static final int RIGHT = 20;
+ private static final int TOP = 15;
+ private static final int PADDING = 10;
+ private Image errorIcon;
+ private FocusManager focusManager;
+
+ protected MessageView(final MessageContent content, final ViewSpecification specification) {
+ super(content, specification);
+ final String iconName = ((MessageContent) getContent()).getIconName();
+ errorIcon = ImageFactory.getInstance().loadIcon(iconName, 32, null);
+ if (errorIcon == null) {
+ errorIcon = ImageFactory.getInstance().loadDefaultIcon(32, null);
+ }
+ }
+
+ @Override
+ public Size getRequiredSize(final Size availableSpace) {
+ final Size size = new Size();
+
+ final String message = ((MessageContent) getContent()).getMessage();
+ final String heading = ((MessageContent) getContent()).title();
+
+ size.ensureHeight(errorIcon.getHeight());
+ final Text text = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+ final Text titleText = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+ size.extendWidth(text.stringWidth(message, MAX_TEXT_WIDTH));
+ int textHeight = titleText.getLineHeight();
+ textHeight += text.stringHeight(message, MAX_TEXT_WIDTH);
+ size.ensureHeight(textHeight);
+
+ size.ensureWidth(titleText.stringWidth(heading));
+
+ size.extendWidth(errorIcon.getWidth());
+ size.extendWidth(PADDING);
+
+ size.extend(LEFT + RIGHT, TOP * 2);
+ return size;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+
+ final String message = ((MessageContent) getContent()).getMessage();
+ final String heading = ((MessageContent) getContent()).title();
+
+ clearBackground(canvas, Toolkit.getColor(ColorsAndFonts.COLOR_WHITE));
+
+ canvas.drawImage(errorIcon, LEFT, TOP);
+
+ final int x = LEFT + errorIcon.getWidth() + PADDING;
+ int y = TOP + 3 + Toolkit.getText(ColorsAndFonts.TEXT_NORMAL).getAscent();
+ final Color black = Toolkit.getColor(ColorsAndFonts.COLOR_BLACK);
+ if (!heading.equals("")) {
+ final Text title = Toolkit.getText(ColorsAndFonts.TEXT_TITLE);
+ canvas.drawText(heading, x, y, black, title);
+ y += title.getLineHeight();
+ }
+ canvas.drawText(message, x, y, MAX_TEXT_WIDTH, black, Toolkit.getText(ColorsAndFonts.TEXT_NORMAL));
+ }
+
+ @Override
+ public ViewAreaType viewAreaType(final Location mouseLocation) {
+ return ViewAreaType.VIEW;
+ }
+
+ @Override
+ public FocusManager getFocusManager() {
+ return focusManager == null ? super.getFocusManager() : focusManager;
+ }
+
+ @Override
+ public void setFocusManager(final FocusManager focusManager) {
+ this.focusManager = focusManager;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/TextMessageContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/TextMessageContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/TextMessageContent.java
new file mode 100644
index 0000000..189fa9d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/message/TextMessageContent.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.message;
+
+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.viewer.dnd.drawing.Image;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+
+public class TextMessageContent implements MessageContent {
+ protected final String message;
+ protected final String heading;
+ protected final String detail;
+ protected final String title;
+
+ public TextMessageContent(final String title, final String message) {
+ final int pos = message.indexOf(':');
+ if (pos > 2) {
+ this.heading = message.substring(0, pos).trim();
+ this.message = message.substring(pos + 1).trim();
+ } else {
+ this.heading = "";
+ this.message = message;
+ }
+ this.title = title;
+ this.detail = null;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String getDetail() {
+ return detail;
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @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 title;
+ }
+
+ @Override
+ public String getHelp() {
+ return "";
+ }
+
+ @Override
+ public String getIconName() {
+ return "message";
+ }
+
+ @Override
+ public Image getIconPicture(final int iconHeight) {
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return "message-exception";
+ }
+
+ @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 isPersistable() {
+ return false;
+ }
+
+ @Override
+ public boolean isOptionEnabled() {
+ 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 heading;
+ }
+
+ @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/option/CloseAllViewsForObjectOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsForObjectOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsForObjectOption.java
new file mode 100644
index 0000000..3e76ba3
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsForObjectOption.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.option;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class CloseAllViewsForObjectOption extends UserActionAbstract {
+ public CloseAllViewsForObjectOption() {
+ super("Close all views for this object");
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ final View views[] = workspace.getSubviews();
+ for (final View v : views) {
+ if (v.getContent().getAdapter() == object) {
+ v.dispose();
+ }
+ }
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ final String title = view.getContent().title();
+ return "Close all views for '" + 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/option/CloseAllViewsOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsOption.java
new file mode 100644
index 0000000..89e7fca
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseAllViewsOption.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.view.option;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class CloseAllViewsOption extends UserActionAbstract {
+ public CloseAllViewsOption() {
+ super("Close all others");
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final View views[] = view.getWorkspace().getSubviews();
+
+ for (final View otherView : views) {
+ if (otherView.getSpecification().isOpen() && otherView != view) {
+ otherView.dispose();
+ }
+ }
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "Close all views except " + view.getSpecification().getName().toLowerCase();
+ }
+
+ @Override
+ public String toString() {
+ return new ToString(this).toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseOtherViewsForObjectOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseOtherViewsForObjectOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseOtherViewsForObjectOption.java
new file mode 100644
index 0000000..44d254d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseOtherViewsForObjectOption.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.option;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class CloseOtherViewsForObjectOption extends UserActionAbstract {
+ public CloseOtherViewsForObjectOption() {
+ super("Close other views for this object");
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final ObjectAdapter object = view.getContent().getAdapter();
+ final View views[] = workspace.getSubviews();
+ for (final View v : views) {
+ if (view != v && v.getContent().getAdapter() == object) {
+ v.dispose();
+ }
+ }
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ final String title = view.getContent().title();
+ return "Close other views for '" + 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/option/CloseViewOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseViewOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseViewOption.java
new file mode 100644
index 0000000..7a222d8
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/CloseViewOption.java
@@ -0,0 +1,46 @@
+/*
+ * 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.option;
+
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class CloseViewOption extends UserActionAbstract {
+ public CloseViewOption() {
+ super("Close");
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ view.dispose();
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "Close this " + view.getSpecification().getName();
+ }
+
+ @Override
+ public String toString() {
+ return new ToString(this).toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/DisposeObjectOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/DisposeObjectOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/DisposeObjectOption.java
new file mode 100644
index 0000000..806d293
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/DisposeObjectOption.java
@@ -0,0 +1,101 @@
+/*
+ * 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.option;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.runtimes.dflt.runtime.system.persistence.Persistor;
+import org.apache.isis.runtimes.dflt.runtime.system.transaction.UpdateNotifier;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+/**
+ * Destroy this object
+ */
+public class DisposeObjectOption extends UserActionAbstract {
+ public DisposeObjectOption() {
+ super("Dispose Object", ActionType.EXPLORATION);
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ final ObjectAdapter adapter = view.getContent().getAdapter();
+ if (adapter.isDestroyed()) {
+ // TODO: move logic into Facet
+ return new Veto("Can't do anything with a destroyed object");
+ }
+ if (isObjectInRootView(view)) {
+ return Allow.DEFAULT;
+ } else {
+ // TODO: move logic into Facet
+ return new Veto("Can't dispose an object from within another view.");
+ }
+ }
+
+ private boolean isObjectInRootView(final View view) {
+ final View rootView = rootView(view);
+ return view.getContent() == rootView.getContent();
+ }
+
+ private View rootView(final View view) {
+ final View parent = view.getParent();
+ if (view.getWorkspace() == parent) {
+ return view;
+ } else {
+ return rootView(parent);
+ }
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+
+ final ObjectAdapter object = ((ObjectContent) view.getContent()).getObject();
+
+ // xactn mgmt now done by PersistenceSession#destroyObject()
+ // getTransactionManager().startTransaction();
+
+ getPersistenceSession().destroyObject(object);
+
+ // getTransactionManager().endTransaction();
+
+ getUpdateNotifier().addDisposedObject(object);
+ view.getViewManager().disposeUnneededViews();
+ view.getFeedbackManager().showMessagesAndWarnings();
+ }
+
+ // /////////////////////////////////////////////////////
+ // Dependencies (from context)
+ // /////////////////////////////////////////////////////
+
+ private static Persistor getPersistenceSession() {
+ return IsisContext.getPersistenceSession();
+ }
+
+ private static UpdateNotifier getUpdateNotifier() {
+ return IsisContext.getUpdateNotifier();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/IconizeViewOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/IconizeViewOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/IconizeViewOption.java
new file mode 100644
index 0000000..7581211
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/IconizeViewOption.java
@@ -0,0 +1,66 @@
+/*
+ * 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.option;
+
+import org.apache.isis.core.metamodel.consent.Allow;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class IconizeViewOption extends UserActionAbstract {
+ public IconizeViewOption() {
+ super("Iconize");
+ }
+
+ @Override
+ public Consent disabled(final View view) {
+ return Allow.DEFAULT;
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final View minimizedView = Toolkit.getViewFactory().createMinimizedView(view);
+ minimizedView.setLocation(view.getLocation());
+ final View[] views = workspace.getSubviews();
+ for (final View view2 : views) {
+ if (view2 == view) {
+ workspace.removeView(view);
+ workspace.addView(minimizedView);
+ workspace.invalidateLayout();
+ return;
+ }
+ }
+
+ /*
+ * // TODO change so that an iconized version of the window is created
+ * and displayed, which holds the original view. View iconView = new
+ * RootIconSpecification().createView(view.getContent(), null);
+ * iconView.setLocation(view.getLocation()); workspace.replaceView(view,
+ * iconView);
+ */
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "Show this object as an icon on the workspace";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/OpenViewOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/OpenViewOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/OpenViewOption.java
new file mode 100644
index 0000000..2127720
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/OpenViewOption.java
@@ -0,0 +1,64 @@
+/*
+ * 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.option;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.Placement;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+import org.apache.isis.viewer.dnd.view.content.FieldContent;
+
+public class OpenViewOption extends UserActionAbstract {
+ private static final Logger LOG = Logger.getLogger(OpenViewOption.class);
+ private final ViewSpecification specification;
+
+ public OpenViewOption(final ViewSpecification builder) {
+ super(builder.getName());
+ this.specification = builder;
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ Content content = view.getContent();
+ if (content.getAdapter() != null && !(content instanceof FieldContent)) {
+ content = Toolkit.getContentFactory().createRootContent(content.getAdapter());
+ }
+ final View newView = specification.createView(content, view.getViewAxes(), -1);
+ LOG.debug("open view " + newView);
+ workspace.addWindow(newView, new Placement(view));
+ workspace.markDamaged();
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ final String title = view.getContent().title();
+ return "Open '" + title + "' in a " + specification.getName() + " window";
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " [prototype=" + specification.getName() + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/ReplaceViewOption.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/ReplaceViewOption.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/ReplaceViewOption.java
new file mode 100644
index 0000000..6cdb8c3
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/view/option/ReplaceViewOption.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.view.option;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewSpecification;
+import org.apache.isis.viewer.dnd.view.Workspace;
+
+public class ReplaceViewOption extends UserActionAbstract {
+ private static final Logger LOG = Logger.getLogger(ReplaceViewOption.class);
+ private final ViewSpecification specification;
+
+ public ReplaceViewOption(final ViewSpecification specification) {
+ super(specification.getName());
+ this.specification = specification;
+ }
+
+ @Override
+ public String getDescription(final View view) {
+ return "Replace this " + view.getSpecification().getName() + " view with a " + specification.getName() + " view";
+ }
+
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ final View replacement = specification.createView(view.getContent(), new Axes(), -1);
+ LOG.debug("replacement view " + replacement);
+ replace(view, replacement);
+ }
+
+ protected void replace(final View view, final View withReplacement) {
+ final View existingView = view.getView();
+ view.getParent().replaceView(existingView, withReplacement);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " [prototype=" + specification.getName() + "]";
+ }
+}