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
[9/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/awt/XViewer.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/awt/XViewer.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/awt/XViewer.java
new file mode 100644
index 0000000..9cbd9b0
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/awt/XViewer.java
@@ -0,0 +1,834 @@
+/*
+ * 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.awt;
+
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.commons.debug.DebuggableWithTitle;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.commons.lang.ToString;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.drawing.Background;
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+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.help.HelpViewer;
+import org.apache.isis.viewer.dnd.util.Properties;
+import org.apache.isis.viewer.dnd.view.Click;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.DragEvent;
+import org.apache.isis.viewer.dnd.view.DragStart;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+import org.apache.isis.viewer.dnd.view.InteractionSpy;
+import org.apache.isis.viewer.dnd.view.ObjectContent;
+import org.apache.isis.viewer.dnd.view.Placement;
+import org.apache.isis.viewer.dnd.view.ShutdownListener;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+import org.apache.isis.viewer.dnd.view.UndoStack;
+import org.apache.isis.viewer.dnd.view.UserActionSet;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewAreaType;
+import org.apache.isis.viewer.dnd.view.ViewConstants;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.ViewUpdateNotifier;
+import org.apache.isis.viewer.dnd.view.Viewer;
+import org.apache.isis.viewer.dnd.view.base.NullView;
+import org.apache.isis.viewer.dnd.view.border.BackgroundBorder;
+import org.apache.isis.viewer.dnd.view.border.LineBorder;
+import org.apache.isis.viewer.dnd.view.debug.LoggingOptions;
+import org.apache.isis.viewer.dnd.view.menu.PopupMenuContainer;
+import org.apache.isis.viewer.dnd.view.message.MessageContent;
+import org.apache.isis.viewer.dnd.viewer.ApplicationOptions;
+
+public class XViewer implements Viewer {
+ private static final Size NO_SIZE = new Size(0, 0);
+ private static final Logger LOG = Logger.getLogger(Viewer.class);
+ private static final Logger UI_LOG = Logger.getLogger("ui." + Viewer.class.getName());
+ private static final LoggingOptions LOGGING_OPTIONS = new LoggingOptions();
+ private static final NullView CLEAR_OVERLAY = new NullView();
+ private static final Bounds NO_REDRAW = new Bounds();
+
+ private ApplicationOptions APPLICATION_OPTIONS;
+ private final DebugOptions DEBUG_OPTIONS = new DebugOptions(this);
+
+ private Graphics bufferGraphics;
+ private Image doubleBuffer;
+ private boolean doubleBuffering = false;
+ private Insets insets;
+ private Size internalDisplaySize = new Size(1, 1);
+ private ShutdownListener listener;
+ private View overlayView;
+ private final Bounds redrawArea;
+ private int redrawCount = 100000;
+ private RenderingArea renderingArea;
+ private View rootView;
+ private String status;
+ private boolean runningAsExploration;
+ private boolean runningAsPrototype;
+ private InteractionSpy spy;
+ private int statusBarHeight;
+ private final UndoStack undoStack = new UndoStack();
+ protected ViewUpdateNotifier updateNotifier;
+ private KeyboardManager keyboardManager;
+ private HelpViewer helpViewer;
+ private Background background;
+ private Bounds statusBarArea;
+ private XFeedbackManager feedbackManager;
+ private boolean refreshStatus;
+ public boolean showExplorationMenuByDefault;
+ boolean showRepaintArea;
+ private static Boolean isDotNetBool;
+
+ private static boolean isDotNet() {
+ if (isDotNetBool == null) {
+ isDotNetBool = new Boolean(System.getProperty("java.version", "dotnet").equals("dotnet"));
+ }
+ return isDotNetBool.booleanValue();
+ }
+
+ public XViewer() {
+ doubleBuffering = IsisContext.getConfiguration().getBoolean(Properties.PROPERTY_BASE + "double-buffer", true);
+ showExplorationMenuByDefault = IsisContext.getConfiguration().getBoolean(Properties.PROPERTY_BASE + "exploration.show", true);
+ overlayView = CLEAR_OVERLAY;
+ redrawArea = new Bounds();
+ }
+
+ public void addSpyAction(final String actionMessage) {
+ if (spy != null) {
+ spy.addAction(actionMessage);
+ }
+ }
+
+ @Override
+ public void addToNotificationList(final View view) {
+ updateNotifier.add(view.getView());
+ }
+
+ @Override
+ public String selectFilePath(final String title, final String directory) {
+ return renderingArea.selectFilePath(title, directory);
+ }
+
+ @Override
+ public void setKeyboardFocus(final View view) {
+ if (view == null) {
+ return;
+ }
+
+ final FocusManager currentFocusManager = keyboardManager.getFocusManager();
+ if (currentFocusManager != null && currentFocusManager.getFocus() != null && currentFocusManager.getFocus().getParent() != null) {
+ currentFocusManager.getFocus().getParent().markDamaged();
+ }
+
+ if (currentFocusManager != null) {
+ final View currentFocus = currentFocusManager.getFocus();
+ if (currentFocus != null && currentFocus != view) {
+ currentFocus.focusLost();
+ }
+ }
+
+ final FocusManager focusManager = view.getFocusManager();
+ if (focusManager != null) {
+ focusManager.setFocus(view);
+ if (view.getParent() != null) {
+ view.getParent().markDamaged();
+ }
+ }
+ if (focusManager == null) {
+ LOG.warn("No focus manager for " + view);
+ } else {
+ keyboardManager.setFocusManager(focusManager);
+ }
+ }
+
+ @Override
+ public void clearOverlayView() {
+ overlayView.markDamaged();
+ overlayView = CLEAR_OVERLAY;
+ }
+
+ @Override
+ public void clearOverlayView(final View view) {
+ if (this.getOverlayView() != view) {
+ LOG.warn("no such view to remove: " + view);
+ }
+ this.clearOverlayView();
+ }
+
+ /*
+ * public void clearStatus() { setStatus(""); }
+ */
+ public void quit() {
+ if (spy != null) {
+ spy.close();
+ }
+ DebugFrame.disposeAll();
+ if (listener != null) {
+ listener.quit();
+ }
+ close();
+ }
+
+ // TODO remove this method; use clearOverlay instead
+ public void disposeOverlayView() {
+ clearOverlayView();
+ }
+
+ @Override
+ public void disposeUnneededViews() {
+ updateNotifier.removeViewsForDisposedObjects();
+ }
+
+ public View dragFrom(final Location location) {
+ if (onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ return overlayView.dragFrom(location);
+ } else {
+ return rootView.dragFrom(location);
+ }
+ }
+
+ public DragEvent dragStart(final DragStart start) {
+ if (onOverlay(start.getLocation())) {
+ start.subtract(overlayView.getLocation());
+ return overlayView.dragStart(start);
+ } else {
+ return rootView.dragStart(start);
+ }
+ }
+
+ public void firstClick(final Click click) {
+ /*
+ * for (int i = 0; i < panes.length; i++) {
+ * if(panes[i].respondsTo(click.getLocation())) {
+ * panes[i].firstClick(click); return; } }
+ */
+ if (onOverlay(click.getLocation())) {
+ click.subtract(overlayView.getLocation());
+ overlayView.firstClick(click);
+ } else {
+ rootView.firstClick(click);
+ }
+ }
+
+ private FocusManager getFocusManager() {
+ return overlayView == CLEAR_OVERLAY ? keyboardManager.getFocusManager() : overlayView.getFocusManager();
+ }
+
+ public Bounds getOverlayBounds() {
+ final Bounds bounds = new Bounds(createSize(renderingArea.getSize()));
+ final Insets in = renderingArea.getInsets();
+ bounds.contract(in.left + in.right, in.top + in.bottom);
+ bounds.contract(0, statusBarHeight);
+ return bounds;
+ }
+
+ private Size createSize(final Dimension size) {
+ return new Size(size.width, size.height);
+ }
+
+ public View getOverlayView() {
+ return overlayView;
+ }
+
+ @Override
+ public InteractionSpy getSpy() {
+ return spy;
+ }
+
+ @Override
+ public UndoStack getUndoStack() {
+ return undoStack;
+ }
+
+ @Override
+ public boolean hasFocus(final View view) {
+ final FocusManager focusManager = keyboardManager.getFocusManager();
+ return focusManager != null && focusManager.getFocus() == view;
+ }
+
+ public View identifyView(final Location location, final boolean includeOverlay) {
+ if (includeOverlay && onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ return overlayView.identify(location);
+ } else {
+ return rootView.identify(location);
+ }
+ }
+
+ public void init() {
+ if (updateNotifier == null) {
+ throw new NullPointerException("No update notifier set for " + this);
+ }
+ if (rootView == null) {
+ throw new NullPointerException("No root view set for " + this);
+ }
+
+ insets = new Insets(0, 0, 0, 0);
+
+ spy = new InteractionSpy(new SpyWindow());
+
+ keyboardManager = new KeyboardManager(this);
+ final InteractionHandler interactionHandler = new InteractionHandler(this, feedbackManager, keyboardManager, spy);
+ renderingArea.addMouseMotionListener(interactionHandler);
+ renderingArea.addMouseListener(interactionHandler);
+ renderingArea.addKeyListener(interactionHandler);
+
+ if (IsisContext.getConfiguration().getBoolean(Properties.PROPERTY_BASE + "show-mouse-spy", false)) {
+ spy.open();
+ }
+
+ setKeyboardFocus(rootView);
+
+ APPLICATION_OPTIONS = new ApplicationOptions(listener);
+ }
+
+ @Override
+ public boolean isRunningAsExploration() {
+ return runningAsExploration;
+ }
+
+ @Override
+ public boolean isRunningAsPrototype() {
+ return runningAsPrototype;
+ }
+
+ public boolean isShowingMouseSpy() {
+ return spy.isVisible();
+ }
+
+ @Override
+ public void markDamaged(final Bounds bounds) {
+ if (spy != null) {
+ spy.addDamagedArea(bounds);
+ }
+
+ synchronized (redrawArea) {
+ if (redrawArea.equals(NO_REDRAW)) {
+ redrawArea.setBounds(bounds);
+ UI_LOG.debug("damage - new area " + redrawArea);
+ } else {
+ if (!bounds.getSize().equals(NO_SIZE)) {
+ redrawArea.union(bounds);
+ UI_LOG.debug("damage - extend area " + redrawArea + " - to include " + bounds);
+ }
+ }
+ }
+ }
+
+ public void menuOptions(final UserActionSet options) {
+ }
+
+ public void mouseDown(final Click click) {
+ if (onOverlay(click.getLocation())) {
+ click.subtract(overlayView.getLocation());
+ overlayView.mouseDown(click);
+ } else {
+ rootView.mouseDown(click);
+ }
+ }
+
+ public void mouseMoved(final Location location) {
+ if (onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ overlayView.mouseMoved(location);
+ } else {
+ rootView.mouseMoved(location);
+ }
+ }
+
+ public void mouseUp(final Click click) {
+ if (onOverlay(click.getLocation())) {
+ click.subtract(overlayView.getLocation());
+ overlayView.mouseUp(click);
+ } else {
+ rootView.mouseUp(click);
+ }
+ }
+
+ private boolean onOverlay(final Location mouse) {
+ return overlayView.getBounds().contains(mouse);
+ }
+
+ public void paint(final Graphics graphic) {
+ redrawCount++;
+ graphic.translate(insets.left, insets.top);
+ final Rectangle paintArea = graphic.getClipBounds();
+ final Rectangle layoutArea = layoutViews();
+ if (layoutArea != null) {
+ paintArea.union(layoutArea);
+ }
+
+ if (spy != null) {
+ spy.redraw(paintArea.toString(), redrawCount);
+ }
+ if (UI_LOG.isDebugEnabled()) {
+ UI_LOG.debug("------ repaint viewer #" + redrawCount + " " + paintArea.x + "," + paintArea.y + " " + paintArea.width + "x" + paintArea.height);
+ }
+
+ final Canvas c = createCanvas(graphic, paintArea);
+ if (background != null) {
+ background.draw(c.createSubcanvas(), rootView.getSize());
+ }
+
+ // paint views
+ if (rootView != null) {
+ rootView.draw(c.createSubcanvas());
+ }
+ // paint overlay
+
+ final Bounds bounds = overlayView.getBounds();
+ if (paintArea.intersects(new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()))) {
+ overlayView.draw(c.createSubcanvas(bounds));
+ }
+
+ /*
+ * for (int i = 0; i < panes.length; i++) {
+ * panes[i].draw(c.createSubcanvas()); }
+ */
+ // paint status
+ // paintUserStatus(bufferGraphics);
+ // blat to screen
+ if (doubleBuffering) {
+ graphic.drawImage(doubleBuffer, 0, 0, null);
+ }
+ if (showRepaintArea) {
+ graphic.setColor(((AwtColor) Toolkit.getColor(ColorsAndFonts.COLOR_DEBUG_BOUNDS_REPAINT)).getAwtColor());
+ graphic.drawRect(paintArea.x, paintArea.y, paintArea.width - 1, paintArea.height - 1);
+ graphic.drawString("#" + redrawCount, paintArea.x + 3, paintArea.y + 15);
+ }
+
+ // paint status
+ paintStatus(graphic);
+ }
+
+ private Canvas createCanvas(final Graphics graphic, final Rectangle paintArea) {
+ final int w = internalDisplaySize.getWidth();
+ final int h = internalDisplaySize.getHeight();
+ if (doubleBuffering) {
+ if ((doubleBuffer == null) || (bufferGraphics == null) || (doubleBuffer.getWidth(null) < w) || (doubleBuffer.getHeight(null) < h)) {
+ doubleBuffer = renderingArea.createImage(w, h);
+ LOG.debug("buffer sized to " + doubleBuffer.getWidth(null) + "x" + doubleBuffer.getHeight(null));
+ }
+ bufferGraphics = doubleBuffer.getGraphics().create();
+ } else {
+ bufferGraphics = graphic;
+ }
+
+ bufferGraphics.clearRect(paintArea.x, paintArea.y, paintArea.width, paintArea.height);
+ bufferGraphics.clearRect(0, 0, w, h);
+
+ bufferGraphics.setClip(paintArea.x, paintArea.y, paintArea.width, paintArea.height);
+ final Canvas c = new AwtCanvas(bufferGraphics, renderingArea, paintArea.x, paintArea.y, paintArea.width, paintArea.height);
+ // Canvas c = new Canvas(bufferGraphics, 0, 0, w, h);
+ return c;
+ }
+
+ /**
+ * Lays out the invalid views and returns the area to be repainted.
+ */
+ private Rectangle layoutViews() {
+ if (!Thread.currentThread().getName().startsWith("AWT-EventQueue") && !isDotNet()) {
+ // REVIEW remove this check and exception when problem with multiple
+ // field drawing is resolved
+ // (Bug 1)
+ throw new IsisException("Drawing with wrong thread: " + Thread.currentThread());
+ }
+ // overlayView.layout(new Size(rootView.getSize()));
+ // rootView.layout(new Size(rootView.getSize()));
+ final Size rootViewSize = rootView.getSize();
+ overlayView.layout();
+ rootView.layout();
+ synchronized (redrawArea) {
+ if (!redrawArea.equals(NO_REDRAW)) {
+ final Rectangle r2 = new Rectangle(redrawArea.getX(), redrawArea.getY(), redrawArea.getWidth(), redrawArea.getHeight());
+ redrawArea.setBounds(NO_REDRAW);
+ return r2;
+ }
+ }
+ return null;
+ }
+
+ private void paintStatus(final Graphics graphic) {
+ final int height = internalDisplaySize.getHeight();
+ final int top = height - statusBarHeight;
+ if (refreshStatus || graphic.getClip().getBounds().getY() + graphic.getClip().getBounds().getHeight() > top) {
+ refreshStatus = false;
+ UI_LOG.debug("changed user status " + status + " " + statusBarArea);
+
+ final int width = internalDisplaySize.getWidth();
+ graphic.setClip(0, top, width, statusBarHeight);
+ graphic.setColor(((AwtColor) Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3)).getAwtColor());
+ final AwtText textStyle = (AwtText) Toolkit.getText(ColorsAndFonts.TEXT_STATUS);
+ graphic.setFont(textStyle.getAwtFont());
+ final int baseline = top + textStyle.getAscent();
+ graphic.fillRect(0, top, width, statusBarHeight);
+ graphic.setColor(((AwtColor) Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY1)).getAwtColor());
+ graphic.drawLine(0, top, internalDisplaySize.getWidth(), top);
+ // graphic.drawRect(0, top, width - 1, statusBarHeight - 1);
+ graphic.setColor(((AwtColor) Toolkit.getColor(ColorsAndFonts.COLOR_BLACK)).getAwtColor());
+ graphic.drawString(status, 5, baseline + ViewConstants.VPADDING);
+ }
+ }
+
+ public View pickupContent(final Location location) {
+ if (onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ return overlayView.pickupContent(location);
+ } else {
+ return rootView.pickupContent(location);
+ }
+ }
+
+ public View pickupView(final Location location) {
+ if (onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ return overlayView.pickupView(location);
+ } else {
+ return rootView.pickupView(location);
+ }
+ }
+
+ public void popupMenu(final View over, final Location at, final boolean forView, final boolean includeExploration, final boolean includeDebug) {
+ feedbackManager.setBusy(over, null);
+ saveCurrentFieldEntry();
+ final PopupMenuContainer menu = new PopupMenuContainer(over, at);
+ if (over == rootView) {
+ menu.addMenuOptions(APPLICATION_OPTIONS);
+ menu.addMenuOptions(LOGGING_OPTIONS);
+ menu.addMenuOptions(DEBUG_OPTIONS);
+ }
+ final boolean showExplorationOptions = includeExploration || showExplorationMenuByDefault;
+ final boolean showPrototypeOptions = isRunningAsPrototype();
+ menu.show(forView, includeDebug, showExplorationOptions, showPrototypeOptions);
+ feedbackManager.clearBusy(over);
+ }
+
+ @Override
+ public void removeFromNotificationList(final View view) {
+ updateNotifier.remove(view);
+ }
+
+ /**
+ * Force a repaint of the damaged area of the viewer.
+ */
+ @Override
+ public void scheduleRepaint() {
+ updateNotifier.invalidateViewsForChangedObjects();
+ synchronized (redrawArea) {
+ if (!redrawArea.equals(NO_REDRAW) || refreshStatus) {
+ UI_LOG.debug("repaint viewer " + redrawArea);
+ final Bounds area = new Bounds(redrawArea);
+ area.translate(insets.left, insets.top);
+ renderingArea.repaint(area.getX(), area.getY(), area.getWidth(), area.getHeight());
+ redrawArea.setBounds(NO_REDRAW);
+ }
+ }
+ }
+
+ @Override
+ public void saveCurrentFieldEntry() {
+ final FocusManager focusManager = getFocusManager();
+ if (focusManager != null) {
+ final View focus = focusManager.getFocus();
+ if (focus != null) {
+ focus.editComplete(false, false);
+ // change should be marked by the field being completed
+ // focus.markDamaged();
+ }
+ }
+ }
+
+ public void secondClick(final Click click) {
+ if (onOverlay(click.getLocation())) {
+ click.subtract(overlayView.getLocation());
+ overlayView.secondClick(click);
+ } else {
+ rootView.secondClick(click);
+ }
+ }
+
+ @Override
+ public void setBackground(final Background background) {
+ this.background = background;
+ }
+
+ void setCursor(final Cursor cursor) {
+ renderingArea.setCursor(cursor);
+ }
+
+ public void setExploration(final boolean asExploration) {
+ this.runningAsExploration = asExploration;
+ }
+
+ public void setPrototype(final boolean asPrototype) {
+ this.runningAsPrototype = asPrototype;
+ }
+
+ public void setListener(final ShutdownListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void setOverlayView(final View view) {
+ disposeOverlayView();
+ overlayView = view;
+ // TODO ensure that the view is laid out properly; hence is the right
+ // size to begin with.
+ // view.limitSize(rootView.getSize());
+
+ final Size size = view.getRequiredSize(rootView.getSize());
+ // size.ensureWidth(getSize().getWidth());
+ view.setSize(size);
+ view.layout();
+
+ view.limitBoundsWithin(getOverlaySize());
+ overlayView.markDamaged();
+ }
+
+ @Override
+ public Size getOverlaySize() {
+ return rootView.getSize();
+ }
+
+ @Override
+ public void showInOverlay(final Content content, final Location location) {
+ View view;
+ view = Toolkit.getViewFactory().createView(new ViewRequirement(content, ViewRequirement.OPEN));
+ view = new LineBorder(2, Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY2), new BackgroundBorder(Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3), view));
+ final Size size = view.getRequiredSize(Size.createMax());
+ location.subtract(size.getWidth() / 2, size.getHeight() / 2);
+ view.setLocation(location);
+ setOverlayView(view);
+ }
+
+ public void setRenderingArea(final RenderingArea renderingArea) {
+ this.renderingArea = renderingArea;
+ }
+
+ public void setRootView(final View rootView) {
+ this.rootView = rootView;
+ rootView.invalidateContent();
+ }
+
+ public void setHelpViewer(final HelpViewer helpViewer) {
+ this.helpViewer = helpViewer;
+ }
+
+ public void setShowMouseSpy(final boolean showDeveloperStatus) {
+ if (spy.isVisible()) {
+ spy.close();
+ } else {
+ spy.open();
+ }
+ }
+
+ public void setUpdateNotifier(final ViewUpdateNotifier updateNotifier) {
+ this.updateNotifier = updateNotifier;
+ }
+
+ public void showSpy() {
+ spy.open();
+ }
+
+ public void sizeChange() {
+ initSize();
+ final View subviews[] = rootView.getSubviews();
+ for (final View subview : subviews) {
+ subview.invalidateLayout();
+ }
+
+ final Bounds bounds = new Bounds(internalDisplaySize);
+ markDamaged(bounds);
+ scheduleRepaint();
+
+ Properties.saveSizeOption(Properties.PROPERTY_BASE + "initial.size", bounds.getSize());
+ }
+
+ public void locationChange(final int x, final int y) {
+ Properties.saveLocationOption(Properties.PROPERTY_BASE + "initial.location", new Location(x, y));
+ }
+
+ public void initSize() {
+ internalDisplaySize = createSize(renderingArea.getSize());
+ insets = renderingArea.getInsets();
+ LOG.debug(" insets " + insets);
+ internalDisplaySize.contract(insets.left + insets.right, insets.top + insets.bottom);
+ LOG.debug(" internal " + internalDisplaySize);
+
+ final Size rootViewSize = new Size(internalDisplaySize);
+ final Text text = Toolkit.getText(ColorsAndFonts.TEXT_STATUS);
+ statusBarHeight = text.getLineHeight() + text.getDescent();
+ rootViewSize.contractHeight(statusBarHeight);
+ statusBarArea = new Bounds(insets.left, insets.top + rootViewSize.getHeight(), rootViewSize.getWidth(), statusBarHeight);
+ rootView.setSize(rootViewSize);
+ }
+
+ public void thirdClick(final Click click) {
+ if (onOverlay(click.getLocation())) {
+ click.subtract(overlayView.getLocation());
+ overlayView.thirdClick(click);
+ } else {
+ rootView.thirdClick(click);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final ToString str = new ToString(this);
+ str.append("renderingArea", renderingArea);
+ str.append("redrawArea", redrawArea);
+ str.append("rootView", rootView);
+ return str.toString();
+ }
+
+ public void translate(final MouseEvent me) {
+ me.translatePoint(-insets.left, -insets.top);
+ }
+
+ public ViewAreaType viewAreaType(final Location location) {
+ if (onOverlay(location)) {
+ location.subtract(overlayView.getLocation());
+ return overlayView.viewAreaType(location);
+ } else {
+ return rootView.viewAreaType(location);
+ }
+ }
+
+ public boolean isOverlayAvailable() {
+ return overlayView != CLEAR_OVERLAY;
+ }
+
+ public void makeRootFocus() {
+ // makeFocus(rootView);
+ }
+
+ public void openHelp(final View forView) {
+ if (forView != null) {
+ String description = null;
+ String help = null;
+ String name = null;
+
+ if (forView != null && forView.getContent() != null) {
+ final Content content = forView.getContent();
+ description = content.getDescription();
+ help = content.getHelp();
+ name = content.getId();
+ name = name == null ? content.title() : name;
+ }
+
+ helpViewer.open(forView.getAbsoluteLocation(), name, description, help);
+
+ }
+
+ }
+
+ @Override
+ public Object getClipboard(final Class<?> cls) {
+ if (cls == String.class) {
+
+ final Clipboard cb = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
+ final Transferable content = cb.getContents(this);
+
+ String value = "illegal value";
+ try {
+ value = ((String) content.getTransferData(DataFlavor.stringFlavor));
+ } catch (final Throwable e) {
+ LOG.error("invalid clipboard operation " + e);
+ }
+ return value;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void setClipboard(final String clip, final Class<?> class1) {
+ final Clipboard cb = java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
+ cb.setContents(new StringSelection(clip), null);
+ }
+
+ public void forcePaintOfStatusBar() {
+ status = feedbackManager.getStatusBarOutput();
+ refreshStatus = true;
+ scheduleRepaint();
+ }
+
+ public void showDialog(final MessageContent content) {
+ final ViewRequirement requirement = new ViewRequirement(content, ViewRequirement.OPEN);
+ final View view = Toolkit.getViewFactory().createView(requirement);
+ rootView.getWorkspace().addDialog(view, new Placement(Placement.CENTER));
+ scheduleRepaint();
+ }
+
+ @Override
+ public void showDebugFrame(final DebuggableWithTitle[] info, final Location at) {
+ final InfoDebugFrame f = new InfoDebugFrame();
+ f.setInfo(info);
+ f.show(at.getX(), at.getY());
+
+ }
+
+ @Override
+ public void clearAction() {
+ feedbackManager.clearAction();
+ clearOverlayView();
+ // feedbackManager.showDefaultCursor();
+ }
+
+ public void setFeedbackManager(final XFeedbackManager feedbackManager) {
+ this.feedbackManager = feedbackManager;
+ }
+
+ public void close() {
+ renderingArea.dispose();
+ }
+
+ @Override
+ public void saveOpenObjects() {
+ final List<ObjectAdapter> objects = new ArrayList<ObjectAdapter>();
+ for (final View view : rootView.getSubviews()) {
+ final Content content = view.getContent();
+ if (content instanceof ObjectContent) {
+ objects.add(((ObjectContent) content).getAdapter());
+ }
+ }
+ IsisContext.getUserProfileLoader().saveSession(objects);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarCellContent.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarCellContent.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarCellContent.java
new file mode 100644
index 0000000..d21bca1
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarCellContent.java
@@ -0,0 +1,96 @@
+/*
+ * 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.calendar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.Veto;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.collection.AbstractCollectionContent;
+
+public class CalendarCellContent extends AbstractCollectionContent {
+ private final String title;
+ private final List<Object> collection = new ArrayList<Object>();
+
+ public CalendarCellContent(final String title) {
+ this.title = title;
+ }
+
+ @Override
+ public ObjectAdapter getCollection() {
+ return IsisContext.getPersistenceSession().getAdapterManager().adapterFor(collection);
+ }
+
+ @Override
+ public Consent canDrop(final Content sourceContent) {
+ return Veto.DEFAULT;
+ }
+
+ @Override
+ public ObjectAdapter drop(final Content sourceContent) {
+ throw new UnexpectedCallException();
+ }
+
+ @Override
+ public String getHelp() {
+ return "No help available";
+ }
+
+ @Override
+ public String getIconName() {
+ return null;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public ObjectAdapter getAdapter() {
+ return getCollection();
+ }
+
+ @Override
+ public ObjectSpecification getSpecification() {
+ throw new UnexpectedCallException();
+ }
+
+ @Override
+ public boolean isTransient() {
+ return true;
+ }
+
+ @Override
+ public String title() {
+ return title;
+ }
+
+ public void addElement(final ObjectAdapter element) {
+ collection.add(element.getObject());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarConstants.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarConstants.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarConstants.java
new file mode 100644
index 0000000..eb6fb2f
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarConstants.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.calendar;
+
+import org.apache.isis.viewer.dnd.drawing.Color;
+import org.apache.isis.viewer.dnd.drawing.ColorsAndFonts;
+import org.apache.isis.viewer.dnd.drawing.Text;
+import org.apache.isis.viewer.dnd.view.Toolkit;
+
+public class CalendarConstants {
+ public final static String[] days = new String[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ public final static Color textColor = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY1);
+ public final static Color weekendColor = Toolkit.getColor(ColorsAndFonts.COLOR_PRIMARY3);
+ public final static Color lineColor = Toolkit.getColor(ColorsAndFonts.COLOR_SECONDARY3);
+ public final static Text style = Toolkit.getText(ColorsAndFonts.TEXT_NORMAL);
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarGrid.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarGrid.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarGrid.java
new file mode 100644
index 0000000..206afbd
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarGrid.java
@@ -0,0 +1,417 @@
+/*
+ * 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.calendar;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.isis.core.commons.exceptions.UnexpectedCallException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.progmodel.facets.value.date.DateValueFacet;
+import org.apache.isis.viewer.dnd.drawing.Canvas;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.icon.IconElementFactory;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+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.Workspace;
+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.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.composite.CollectionElementBuilder;
+import org.apache.isis.viewer.dnd.view.composite.CompositeView;
+import org.apache.isis.viewer.dnd.view.composite.CompositeViewUsingBuilder;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.option.UserActionAbstract;
+
+public class CalendarGrid extends CompositeView {
+ private Cells cellLayout;
+ private int rows;
+ private int columns;
+ private boolean acrossThenDown;
+
+ @Override
+ protected void buildNewView() {
+ final CalendarCellContent[] cellContents = createContentForCells();
+ addCellsToView(cellContents);
+ }
+
+ private void addCellsToView(final CalendarCellContent[] cellContents) {
+ final View[] cells = new View[rows * columns];
+ for (int row = 0; row < rows; row++) {
+ for (int column = 0; column < columns; column++) {
+ final int cellNo = acrossThenDown ? row * columns + column : column * rows + row;
+ View cell;
+ if (cellContents[cellNo] == null) {
+ cell = new BlankView(new NullContent());
+ } else {
+ cell = new CompositeViewUsingBuilder(cellContents[cellNo], null, new Axes(), new StackLayout(), new CollectionElementBuilder(new IconElementFactory()));
+ cell = new ScrollBorder(cell);
+ }
+ cells[cellNo] = cell;
+ addView(cell);
+ }
+ }
+ }
+
+ private CalendarCellContent[] createContentForCells() {
+ final CalendarCellContent[] cellContents = new CalendarCellContent[rows * columns];
+ final CollectionContent content = (CollectionContent) getContent();
+ for (final ObjectAdapter element : content.elements()) {
+ final Date date = dateFor(element);
+ if (date == null) {
+ continue;
+ }
+ final int period = cellLayout.getPeriodFor(date);
+ if (period >= 0 && period < cellContents.length) {
+ if (cellContents[period] == null) {
+ cellContents[period] = new CalendarCellContent(cellLayout.title(period));
+ }
+ cellContents[period].addElement(element);
+ }
+ }
+ return cellContents;
+ }
+
+ private Date dateFor(final ObjectAdapter element) {
+ final ObjectAssociation dateField = findDate(element);
+ if (dateField == null) {
+ return null;
+ }
+ final DateValueFacet facet = dateField.getSpecification().getFacet(DateValueFacet.class);
+ final ObjectAdapter field = dateField.get(element);
+ final Date date = facet.dateValue(field);
+ return date;
+ }
+
+ private ObjectAssociation findDate(final ObjectAdapter adapter) {
+ final ObjectSpecification spec = adapter.getSpecification();
+ final List<ObjectAssociation> fields = spec.getAssociations();
+ for (int i = 0; i < fields.size(); i++) {
+ final Facet facet = fields.get(i).getSpecification().getFacet(DateValueFacet.class);
+ if (facet != null) {
+ return fields.get(i);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void buildModifiedView() {
+ disposeContentsOnly();
+ buildNewView();
+ }
+
+ // TODO remove
+ @Override
+ protected void buildView() {
+ throw new UnexpectedCallException();
+ }
+
+ @Override
+ protected void doLayout(final Size maximumSize) {
+ final boolean hasHeader = cellLayout.header(0) != null;
+ final int topInset = 0 + (acrossThenDown && hasHeader ? 30 : 0);
+ final int leftInset = !acrossThenDown && hasHeader ? 50 : 0;
+ final int width = maximumSize.getWidth();
+ final int height = maximumSize.getHeight();
+ final int columnWidth = (width - leftInset) / columns;
+ final int rowHeight = (height - topInset) / rows;
+
+ final View[] cells = getSubviews();
+ int i = 0;
+ final int top = CalendarConstants.style.getLineHeight() + ViewConstants.VPADDING;
+ CalendarConstants.style.getLineSpacing();
+ final Location location = new Location(leftInset, topInset + top);
+ final Size size = new Size(columnWidth, rowHeight - top);
+ for (int row = 0; row < rows; row++) {
+ for (int column = 0; column < columns; column++) {
+ final View cell = cells[i++];
+ cell.setSize(size);
+ cell.setLocation(location);
+ location.add(columnWidth, 0);
+ }
+ location.setX(leftInset);
+ location.add(0, rowHeight);
+ }
+ }
+
+ @Override
+ public Size requiredSize(final Size availableSpace) {
+ return new Size(300, 300);
+ }
+
+ protected CalendarGrid(final Content content) {
+ super(content, null);
+
+ cellLayout = new DayCells(null);
+ acrossThenDown = true;
+ rows = cellLayout.defaultRows();
+ columns = cellLayout.defaultColumns();
+ cellLayout.add(-rows * columns / 2);
+ }
+
+ @Override
+ public void setFocusManager(final FocusManager focusManager) {
+ // this.focusManager = focusManager;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ super.draw(canvas);
+
+ final boolean hasHeader = cellLayout.header(0) != null;
+ final int topInset = 0 + (acrossThenDown && hasHeader ? 30 : 0);
+ final int leftInset = !acrossThenDown && hasHeader ? 50 : 0;
+ final int width = getSize().getWidth();
+ final int height = getSize().getHeight();
+ final int columnWidth = (width - leftInset) / columns;
+ final int rowHeight = (height - topInset) / rows;
+
+ for (int row = 0; row < rows; row++) {
+ final int y = topInset + row * rowHeight;
+ if (!acrossThenDown && hasHeader) {
+ canvas.drawText(cellLayout.header(row), 0, y + 20, CalendarConstants.textColor, CalendarConstants.style);
+ }
+ canvas.drawLine(leftInset, y, width, y, CalendarConstants.lineColor);
+ }
+ canvas.drawLine(leftInset, topInset + height - 1, width, topInset + height - 1, CalendarConstants.lineColor);
+
+ for (int column = 0; column < columns; column++) {
+ final int x = leftInset + column * columnWidth;
+ if (acrossThenDown && hasHeader) {
+ canvas.drawText(cellLayout.header(column), x, topInset - 5, CalendarConstants.textColor, CalendarConstants.style);
+ }
+ canvas.drawLine(x, topInset, x, topInset + height, CalendarConstants.lineColor);
+ }
+ canvas.drawLine(width - 1, topInset, width - 1, height, CalendarConstants.lineColor);
+
+ for (int row = 0; row < rows; row++) {
+ final int y = topInset + row * rowHeight + CalendarConstants.style.getAscent() + 2;
+ for (int column = 0; column < columns; column++) {
+ final int x = leftInset + column * columnWidth + 2;
+ final int cell = acrossThenDown ? row * columns + column : column * rows + row;
+ canvas.drawText(cellLayout.title(cell), x, y, CalendarConstants.textColor, CalendarConstants.style);
+ }
+ }
+ }
+
+ void addRow() {
+ rows++;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void removeRow() {
+ rows--;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void addColumn() {
+ columns++;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void removeColumn() {
+ columns--;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void showYears() {
+ cellLayout = new YearCells(cellLayout);
+ show();
+ }
+
+ void showMonths() {
+ cellLayout = new MonthCells(cellLayout);
+ show();
+ }
+
+ void showWeeks() {
+ cellLayout = new WeekCells(cellLayout);
+ show();
+ }
+
+ void show() {
+ cellLayout.roundDown();
+ rows = cellLayout.defaultRows();
+ columns = cellLayout.defaultColumns();
+ invalidateContent();
+ markDamaged();
+ }
+
+ void showSingleDay() {
+ cellLayout = new SingleDayCells(cellLayout);
+ show();
+ }
+
+ void showDays() {
+ cellLayout = new DayCells(cellLayout);
+ show();
+ }
+
+ void acrossFirst() {
+ acrossThenDown = true;
+ final int temp = rows;
+ rows = columns;
+ columns = temp;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void downFirst() {
+ acrossThenDown = false;
+ final int temp = rows;
+ rows = columns;
+ columns = temp;
+ invalidateContent();
+ markDamaged();
+ }
+
+ void nextPeriod() {
+ cellLayout.add(rows * columns);
+ invalidateContent();
+ markDamaged();
+ }
+
+ void previousePeriod() {
+ cellLayout.add(-rows * columns);
+ invalidateContent();
+ markDamaged();
+ }
+
+ void today() {
+ cellLayout.today();
+ invalidateContent();
+ markDamaged();
+ }
+
+ @Override
+ public void viewMenuOptions(final UserActionSet options) {
+ super.viewMenuOptions(options);
+
+ options.add(new UserActionAbstract("Add row") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ addRow();
+ }
+ });
+ options.add(new UserActionAbstract("Remove row") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ removeRow();
+ }
+ });
+
+ options.add(new UserActionAbstract("Add column") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ addColumn();
+ }
+ });
+ options.add(new UserActionAbstract("Remove column") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ removeColumn();
+ }
+ });
+
+ options.add(new UserActionAbstract("Years") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ showYears();
+ }
+ });
+
+ options.add(new UserActionAbstract("Months") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ showMonths();
+ }
+ });
+
+ options.add(new UserActionAbstract("Weeks") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ showWeeks();
+ }
+ });
+
+ options.add(new UserActionAbstract("Day") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ showSingleDay();
+ }
+ });
+ options.add(new UserActionAbstract("Days") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ showDays();
+ }
+ });
+
+ options.add(new UserActionAbstract("Across then down") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ acrossFirst();
+ }
+ });
+
+ options.add(new UserActionAbstract("Down then across") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ downFirst();
+ }
+ });
+
+ options.add(new UserActionAbstract("Previous period") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ previousePeriod();
+ }
+ });
+
+ options.add(new UserActionAbstract("Next period") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ nextPeriod();
+ }
+ });
+
+ options.add(new UserActionAbstract("Today") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ today();
+ }
+ });
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarSpecification.java
new file mode 100644
index 0000000..7cddd07
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarSpecification.java
@@ -0,0 +1,100 @@
+/*
+ * 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.calendar;
+
+import java.util.List;
+
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.progmodel.facets.value.date.DateValueFacet;
+import org.apache.isis.viewer.dnd.view.Axes;
+import org.apache.isis.viewer.dnd.view.CompositeViewSpecification;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.View;
+import org.apache.isis.viewer.dnd.view.ViewRequirement;
+import org.apache.isis.viewer.dnd.view.base.Layout;
+import org.apache.isis.viewer.dnd.view.collection.CollectionContent;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+import org.apache.isis.viewer.dnd.view.composite.ViewBuilder;
+
+public class CalendarSpecification implements CompositeViewSpecification {
+
+ public Layout createLayout(final Content content, final Axes axes) {
+ return new StackLayout();
+ }
+
+ public void createAxes(final Content content, final Axes axes) {
+ // axes.add(new CalendarAxis());
+ }
+
+ @Override
+ public View createView(final Content content, final Axes axes, final int sequence) {
+ return new CalendarView(content, this);
+ // return new ViewResizeBorder(new CalendarView(content, this));
+ }
+
+ @Override
+ public boolean canDisplay(final ViewRequirement requirement) {
+ final boolean openCollection = requirement.isCollection() && requirement.isOpen();
+ if (openCollection) {
+ final List<OneToOneAssociation> propertyList = ((CollectionContent) requirement.getContent()).getElementSpecification().getProperties();
+ for (final OneToOneAssociation association : propertyList) {
+ if (!association.isAlwaysHidden() && association.getSpecification().containsFacet(DateValueFacet.class)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "Calendar (experimental) ";
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+ @Override
+ public boolean isReplaceable() {
+ return true;
+ }
+
+ @Override
+ public boolean isSubView() {
+ return false;
+ }
+
+ public ViewBuilder getSubviewBuilder() {
+ return null;
+ }
+
+ @Override
+ public boolean isAligned() {
+ return false;
+ }
+
+ @Override
+ public boolean isResizeable() {
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarView.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarView.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarView.java
new file mode 100644
index 0000000..d8dfc7e
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/CalendarView.java
@@ -0,0 +1,199 @@
+/*
+ * 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.calendar;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.viewer.dnd.drawing.Bounds;
+import org.apache.isis.viewer.dnd.drawing.Location;
+import org.apache.isis.viewer.dnd.drawing.Size;
+import org.apache.isis.viewer.dnd.field.DatePickerControl;
+import org.apache.isis.viewer.dnd.toolbar.ToolbarView;
+import org.apache.isis.viewer.dnd.view.Content;
+import org.apache.isis.viewer.dnd.view.FocusManager;
+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.composite.CompositeView;
+import org.apache.isis.viewer.dnd.view.content.NullContent;
+import org.apache.isis.viewer.dnd.view.control.AbstractButtonAction;
+import org.apache.isis.viewer.dnd.view.control.Button;
+
+public class CalendarView extends CompositeView {
+ private static final Logger LOG = Logger.getLogger(CalendarView.class);
+
+ protected CalendarView(final Content content, final ViewSpecification specification) {
+ super(content, specification);
+ }
+
+ @Override
+ public void doLayout(final Size maximumSize) {
+ LOG.debug("doLayout() " + maximumSize + " " + getSize());
+ final View toolbar = getSubviews()[0];
+ maximumSize.contract(getPadding());
+ final Size toolbarSize = toolbar.getRequiredSize(maximumSize);
+ LOG.debug(" toolbar " + toolbarSize);
+ Bounds bounds = new Bounds(toolbarSize);
+ toolbar.setBounds(bounds);
+
+ final View grid = getSubviews()[1];
+ final Size gridSize = getRequiredSize(Size.createMax());
+ gridSize.contract(getPadding());
+ gridSize.contractHeight(toolbarSize.getHeight());
+ bounds = new Bounds(new Location(0, toolbarSize.getHeight()), gridSize);
+ grid.setBounds(bounds);
+ LOG.debug(" grid " + toolbarSize);
+
+ }
+
+ @Override
+ public void setFocusManager(final FocusManager focusManager) {
+ // this.focusManager = focusManager;
+ }
+
+ @Override
+ public Size requiredSize(final Size availableSpace) {
+ final Size workspace = getWorkspace().getSize();
+ return new Size((int) (workspace.getWidth() * 0.8), (int) (workspace.getHeight() * 0.8));
+ }
+
+ @Override
+ protected void buildView() {
+ if (subviews().length == 0) {
+ final CalendarGrid grid = new CalendarGrid(getContent());
+ final ToolbarView toolbar = createToolbar(grid);
+ addView(toolbar);
+ addView(grid);
+ } else {
+ // TODO update grid view
+ }
+ }
+
+ private ToolbarView createToolbar(final CalendarGrid calendar) {
+ final ToolbarView toolbarView = new ToolbarView(getContent(), null);
+
+ toolbarView.addView(new Button(new AbstractButtonAction("+Row") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.addRow();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("-Row") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.removeRow();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Across") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.acrossFirst();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Down") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.downFirst();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Next") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.nextPeriod();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Previous") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.previousePeriod();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Day") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.showSingleDay();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Days") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.showDays();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Weeks") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.showWeeks();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Months") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.showMonths();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Years") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.showYears();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Today") {
+ @Override
+ public void execute(final Workspace workspace, final View view, final Location at) {
+ calendar.today();
+ }
+ }, this));
+
+ toolbarView.addView(new Button(new AbstractButtonAction("Date") {
+ @Override
+ public void execute(final Workspace workspace, View view, final Location at) {
+ final Content content = new NullContent() {
+ };
+ view = DatePickerControl.getPicker(content);
+ calendar.today();
+ getViewManager().setOverlayView(view);
+ }
+ }, this));
+
+ return toolbarView;
+ }
+
+ /*
+ * public void invalidateLayout() { // super.invalidateLayout(); View parent
+ * = getParent(); if (parent != null) { // parent.invalidateLayout(); }
+ * isInvalid = true; View toolbar = getSubviews()[0];
+ * toolbar.invalidateLayout(); // View grid = getSubviews()[1]; //
+ * grid.invalidateLayout(); } protected boolean isLayoutInvalid() { return
+ * isInvalid; }
+ */
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cell.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cell.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cell.java
new file mode 100644
index 0000000..02c4577
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cell.java
@@ -0,0 +1,24 @@
+/*
+ * 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.calendar;
+
+public class Cell {
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cells.java
new file mode 100644
index 0000000..ba2e21a
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/Cells.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.calendar;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+public abstract class Cells {
+ protected final DateFormat monthFormat = new SimpleDateFormat("MMM");
+ protected final DateFormat dayFormat = new SimpleDateFormat("EEE");
+ protected Calendar date;
+
+ public Cells(final Cells replacing) {
+ if (replacing == null) {
+ today();
+ } else {
+ date = replacing.date;
+ }
+ }
+
+ public void today() {
+ date = Calendar.getInstance();
+ roundDown();
+ }
+
+ public final void setDate(final Calendar date) {
+ this.date = date;
+ }
+
+ public void roundDown() {
+ }
+
+ abstract int defaultRows();
+
+ abstract int defaultColumns();
+
+ abstract void add(int interval);
+
+ abstract String title(int cell);
+
+ public String header(final int cell) {
+ return null;
+ }
+
+ public int getPeriodFor(final Date date) {
+ final Calendar forDate = Calendar.getInstance();
+ forDate.setTime(date);
+ final int baseline = period(this.date);
+ final int comparativePeriod = period(forDate);
+ return baseline - comparativePeriod;
+ }
+
+ protected abstract int period(Calendar forDate);
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/DayCells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/DayCells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/DayCells.java
new file mode 100644
index 0000000..3913c08
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/DayCells.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.calendar;
+
+import java.util.Calendar;
+
+public class DayCells extends Cells {
+
+ public DayCells(final Cells replacing) {
+ super(replacing);
+ }
+
+ @Override
+ public int defaultColumns() {
+ return 7;
+ }
+
+ @Override
+ public int defaultRows() {
+ return 2;
+ }
+
+ @Override
+ public void add(final int interval) {
+ date.add(Calendar.DAY_OF_WEEK, interval);
+ }
+
+ @Override
+ public void roundDown() {
+ final int offset = date.get(Calendar.DAY_OF_WEEK) - date.getFirstDayOfWeek();
+ date.add(Calendar.DAY_OF_MONTH, -offset);
+ }
+
+ @Override
+ public String title(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ d.add(Calendar.DAY_OF_WEEK, cell);
+ final String displayName = dayFormat.format(d.getTime()) + " " + d.get(Calendar.DAY_OF_MONTH) + " " + monthFormat.format(d.getTime());
+ return displayName;
+ }
+
+ @Override
+ public String header(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ d.add(Calendar.DAY_OF_WEEK, cell);
+ return dayFormat.format(d.getTime());
+ }
+
+ @Override
+ protected int period(final Calendar forDate) {
+ return forDate.get(Calendar.YEAR) * 12 - forDate.get(Calendar.DAY_OF_YEAR);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/MonthCells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/MonthCells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/MonthCells.java
new file mode 100644
index 0000000..7596e63
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/MonthCells.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.calendar;
+
+import java.util.Calendar;
+
+public class MonthCells extends Cells {
+
+ public MonthCells(final Cells replacing) {
+ super(replacing);
+ }
+
+ @Override
+ public int defaultColumns() {
+ return 4;
+ }
+
+ @Override
+ public int defaultRows() {
+ return 3;
+ }
+
+ @Override
+ public void roundDown() {
+ date.set(Calendar.MONTH, 0);
+ }
+
+ @Override
+ public void add(final int interval) {
+ date.add(Calendar.MONTH, interval);
+ }
+
+ @Override
+ public String title(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ d.add(Calendar.MONTH, cell);
+ final String displayName = monthFormat.format(d.getTime()) + " " + d.get(Calendar.YEAR);
+ return displayName;
+ }
+
+ @Override
+ protected int period(final Calendar forDate) {
+ return forDate.get(Calendar.YEAR) * 12 - forDate.get(Calendar.MONTH);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/SingleDayCells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/SingleDayCells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/SingleDayCells.java
new file mode 100644
index 0000000..2726017
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/SingleDayCells.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.calendar;
+
+import java.util.Calendar;
+
+public class SingleDayCells extends Cells {
+
+ public SingleDayCells(final Cells replacing) {
+ super(replacing);
+ }
+
+ @Override
+ public int defaultColumns() {
+ return 1;
+ }
+
+ @Override
+ public int defaultRows() {
+ return 1;
+ }
+
+ @Override
+ public void add(final int interval) {
+ date.add(Calendar.DAY_OF_WEEK, interval);
+ }
+
+ @Override
+ public String title(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ d.add(Calendar.DAY_OF_WEEK, cell);
+ final String displayName = dayFormat.format(d.getTime()) + " " + d.get(Calendar.DAY_OF_MONTH) + " " + monthFormat.format(d.getTime());
+ return displayName;
+ }
+
+ @Override
+ protected int period(final Calendar forDate) {
+ return forDate.get(Calendar.YEAR) * 12 - forDate.get(Calendar.DAY_OF_YEAR);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/WeekCells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/WeekCells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/WeekCells.java
new file mode 100644
index 0000000..2e7c221
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/WeekCells.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.calendar;
+
+import java.util.Calendar;
+
+public class WeekCells extends Cells {
+
+ public WeekCells(final Cells replacing) {
+ super(replacing);
+ }
+
+ @Override
+ public int defaultColumns() {
+ return 4;
+ }
+
+ @Override
+ public int defaultRows() {
+ return 3;
+ }
+
+ @Override
+ public void add(final int interval) {
+ add(date, interval);
+ }
+
+ public void add(final Calendar d, final int interval) {
+ d.add(Calendar.DAY_OF_MONTH, 7 * interval);
+ }
+
+ @Override
+ public String title(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ add(d, cell);
+ final String displayName = d.get(Calendar.DAY_OF_MONTH) + " " + monthFormat.format(d.getTime());
+ return "w/b " + displayName;
+ }
+
+ @Override
+ protected int period(final Calendar forDate) {
+ return forDate.get(Calendar.YEAR) * 12 - forDate.get(Calendar.WEEK_OF_YEAR);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/YearCells.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/YearCells.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/YearCells.java
new file mode 100644
index 0000000..09f828a
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/calendar/YearCells.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.calendar;
+
+import java.util.Calendar;
+
+public class YearCells extends Cells {
+
+ public YearCells(final Cells replacing) {
+ super(replacing);
+ }
+
+ @Override
+ public int defaultColumns() {
+ return 4;
+ }
+
+ @Override
+ public int defaultRows() {
+ return 2;
+ }
+
+ @Override
+ public void add(final int interval) {
+ date.add(Calendar.YEAR, interval);
+ }
+
+ @Override
+ public String title(final int cell) {
+ final Calendar d = (Calendar) date.clone();
+ d.add(Calendar.YEAR, cell);
+ final String displayName = d.get(Calendar.YEAR) + "";
+ return displayName;
+ }
+
+ @Override
+ protected int period(final Calendar forDate) {
+ return forDate.get(Calendar.YEAR);
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/eb613703/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/ExpandableListSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/ExpandableListSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/ExpandableListSpecification.java
new file mode 100644
index 0000000..710bb8e
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/ExpandableListSpecification.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.combined;
+
+import org.apache.isis.viewer.dnd.form.ExpandableViewBorder;
+import org.apache.isis.viewer.dnd.icon.IconElementFactory;
+import org.apache.isis.viewer.dnd.view.ViewFactory;
+import org.apache.isis.viewer.dnd.view.composite.AbstractCollectionViewSpecification;
+
+public class ExpandableListSpecification extends AbstractCollectionViewSpecification {
+
+ public ExpandableListSpecification() {
+ builder.addSubviewDecorator(new ExpandableViewBorder.Factory());
+ }
+
+ @Override
+ protected ViewFactory createElementFactory() {
+ return new IconElementFactory();
+ }
+
+ @Override
+ public String getName() {
+ return "Expanding List (experimental)";
+ }
+
+ // TODO this should be available if an item can be given more space
+ /*
+ * @Override public boolean canDisplay(final Content content,
+ * ViewRequirement requirement) { return content.isCollection() &&
+ * requirement.is(ViewRequirement.CLOSED) &&
+ * requirement.is(ViewRequirement.SUBVIEW) &&
+ * requirement.is(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/combined/FormWithTableSpecification.java
----------------------------------------------------------------------
diff --git a/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/FormWithTableSpecification.java b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/FormWithTableSpecification.java
new file mode 100644
index 0000000..4dc499d
--- /dev/null
+++ b/component/viewer/dnd/impl/src/main/java/org/apache/isis/viewer/dnd/combined/FormWithTableSpecification.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.dnd.combined;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
+import org.apache.isis.viewer.dnd.form.FormSpecification;
+import org.apache.isis.viewer.dnd.table.InternalTableSpecification;
+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.base.Layout;
+import org.apache.isis.viewer.dnd.view.composite.GridLayout;
+import org.apache.isis.viewer.dnd.view.composite.StackLayout;
+
+public class FormWithTableSpecification extends SplitViewSpecification {
+
+ // REVIEW: confirm this rendering context
+ final Where where = Where.OBJECT_FORMS;
+
+ @Override
+ public Layout createLayout(final Content content, final Axes axes) {
+ return new StackLayout();
+ }
+
+ @Override
+ View createMainView(final Axes axes, final Content mainContent, final Content secondaryContent) {
+ final View form1 = new FormSpecification() {
+ @Override
+ protected boolean include(final Content content, final int sequence) {
+ return !secondaryContent.getId().equals(content.getId());
+ };
+
+ @Override
+ public Layout createLayout(final Content content, final Axes axes) {
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.setSize(2);
+ return gridLayout;
+ }
+ }.createView(mainContent, axes, -1);
+ return form1;
+ }
+
+ @Override
+ View createSecondaryView(final Axes axes, final Content fieldContent) {
+ return new InternalTableSpecification().createView(fieldContent, axes, -1);
+ }
+
+ @Override
+ Content determineSecondaryContent(final Content content) {
+ final ObjectSpecification spec = content.getSpecification();
+ final ObjectAdapter target = content.getAdapter();
+ final AuthenticationSession session = IsisContext.getAuthenticationSession();
+ final List<ObjectAssociation> fields = spec.getAssociations(ObjectAssociationFilters.dynamicallyVisible(session, target, where));
+ for (final ObjectAssociation field : fields) {
+ if (field.isOneToManyAssociation()) {
+ return Toolkit.getContentFactory().createFieldContent(field, target);
+ }
+ }
+ return null;
+ }
+
+ /*
+ *
+ * @Override protected void init() { addSubviewDecorator(new
+ * FieldLabelsDecorator() { public View decorate(Axes axes, View view) { if
+ * (view.getContent().isCollection()) { return view; } else { return
+ * super.decorate(axes, view); } } }); addViewDecorator(new
+ * IconBorder.Factory()); }
+ *
+ * @Override protected SubviewSpec createFieldFactory() { return new
+ * SubviewSpec() { public View createView(final Content content, Axes axes,
+ * int sequence) { if (content.isCollection()) { return new
+ * InternalTableSpecification().createView(content, axes, sequence); } else
+ * { final ViewFactory factory = Toolkit.getViewFactory(); int requirement =
+ * ViewRequirement.CLOSED | ViewRequirement.SUBVIEW; ViewRequirement
+ * viewRequirement = new ViewRequirement(content, requirement); return
+ * factory.createView(viewRequirement); } } }; }
+ */
+ @Override
+ public String getName() {
+ return "Form with table (experimental)";
+ }
+
+ @Override
+ boolean validField(final ObjectAssociation field) {
+ return false;
+ }
+}