/******************************************************************************* * CogTool Copyright Notice and Distribution Terms * CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * CogTool is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * CogTool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CogTool; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * CogTool makes use of several third-party components, with the * following notices: * * Eclipse SWT version 3.448 * Eclipse GEF Draw2D version 3.2.1 * * Unless otherwise indicated, all Content made available by the Eclipse * Foundation is provided to you under the terms and conditions of the Eclipse * Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this * Content and is also available at http://www.eclipse.org/legal/epl-v10.html. * * CLISP version 2.38 * * Copyright (c) Sam Steingold, Bruno Haible 2001-2006 * This software is distributed under the terms of the FSF Gnu Public License. * See COPYRIGHT file in clisp installation folder for more information. * * ACT-R 6.0 * * Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere & * John R Anderson. * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * Apache Jakarta Commons-Lang 2.1 * * This product contains software developed by the Apache Software Foundation * (http://www.apache.org/) * * jopt-simple version 1.0 * * Copyright (c) 2004-2013 Paul R. Holser, Jr. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Mozilla XULRunner 1.9.0.5 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/. * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The J2SE(TM) Java Runtime Environment version 5.0 * * Copyright 2009 Sun Microsystems, Inc., 4150 * Network Circle, Santa Clara, California 95054, U.S.A. All * rights reserved. U.S. * See the LICENSE file in the jre folder for more information. ******************************************************************************/ package edu.cmu.cs.hcii.cogtool.ui; import java.util.EventObject; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import edu.cmu.cs.hcii.cogtool.CogTool; import edu.cmu.cs.hcii.cogtool.CogToolLID; import edu.cmu.cs.hcii.cogtool.FrameTemplateSupport; import edu.cmu.cs.hcii.cogtool.model.AAction; import edu.cmu.cs.hcii.cogtool.model.ActionType; import edu.cmu.cs.hcii.cogtool.model.Design; import edu.cmu.cs.hcii.cogtool.model.DeviceType; import edu.cmu.cs.hcii.cogtool.model.DoubleRectangle; import edu.cmu.cs.hcii.cogtool.model.DoubleSize; import edu.cmu.cs.hcii.cogtool.model.Frame; import edu.cmu.cs.hcii.cogtool.model.GraffitiAction; import edu.cmu.cs.hcii.cogtool.model.IWidget; import edu.cmu.cs.hcii.cogtool.model.KeyAction; import edu.cmu.cs.hcii.cogtool.model.Project; import edu.cmu.cs.hcii.cogtool.model.SkinType; import edu.cmu.cs.hcii.cogtool.model.TextAction; import edu.cmu.cs.hcii.cogtool.model.Transition; import edu.cmu.cs.hcii.cogtool.model.TransitionSource; import edu.cmu.cs.hcii.cogtool.model.VoiceAction; import edu.cmu.cs.hcii.cogtool.ui.DesignEditorSelectionState.FrameSelectionChange; import edu.cmu.cs.hcii.cogtool.ui.DesignEditorSelectionState.TransitionSelectionChange; import edu.cmu.cs.hcii.cogtool.uimodel.DesignEditorFrame; import edu.cmu.cs.hcii.cogtool.uimodel.DesignEditorTransition; import edu.cmu.cs.hcii.cogtool.uimodel.DesignEditorUIModel; import edu.cmu.cs.hcii.cogtool.uimodel.StructureViewUIModel; import edu.cmu.cs.hcii.cogtool.util.ClipboardUtil; import edu.cmu.cs.hcii.cogtool.util.AlertHandler; import edu.cmu.cs.hcii.cogtool.util.L10N; import edu.cmu.cs.hcii.cogtool.util.ListenerIdentifier; import edu.cmu.cs.hcii.cogtool.util.ListenerIdentifierMap; import edu.cmu.cs.hcii.cogtool.util.MenuUtil; import edu.cmu.cs.hcii.cogtool.util.NameChangeAlert; import edu.cmu.cs.hcii.cogtool.util.OSUtils; import edu.cmu.cs.hcii.cogtool.util.PrecisionUtilities; import edu.cmu.cs.hcii.cogtool.util.SWTStringUtil; import edu.cmu.cs.hcii.cogtool.util.SWTTextEditor; import edu.cmu.cs.hcii.cogtool.util.StringUtil; import edu.cmu.cs.hcii.cogtool.util.UndoManager; import edu.cmu.cs.hcii.cogtool.util.WindowUtil; import edu.cmu.cs.hcii.cogtool.view.ActionPropertySet; import edu.cmu.cs.hcii.cogtool.view.ActionSet; import edu.cmu.cs.hcii.cogtool.view.DesignEditorView; import edu.cmu.cs.hcii.cogtool.view.InteractionDrawingEditor; import edu.cmu.cs.hcii.cogtool.view.MenuFactory; import edu.cmu.cs.hcii.cogtool.view.ResizeThumb; import edu.cmu.cs.hcii.cogtool.view.StandardDrawingEditor; import edu.cmu.cs.hcii.cogtool.view.View; public class DesignEditorUI extends ZoomableUI { protected class FrameNameEditor extends SWTTextEditor { public FrameNameEditor() { super(view.getEditor().getSWTEditorSubstrate(), CENTER_TEXT); } @Override public boolean confirm(int focusRule) { return confirmRenameFrame(); } @Override protected int computeHeight(Rectangle bounds, double scale, int offset) { DesignEditorFrame frameFig = (DesignEditorFrame) getData(); return PrecisionUtilities.round(frameFig.getLabelHeight() * scale); } public void editFrameName(DesignEditorFrame frameFigure) { Frame frame = frameFigure.getFrame(); editingInProgress = false; editText(frame.getName(), frameFigure, structureView.getZoom()); } @Override protected Font getFontToUse() { return ((DesignEditorFrame) getData()).getLabel().getFont(); } } /** * Parameters for MoveFrames operation * * @author mlh */ public static class MoveParameters { public double dx; public double dy; public FrameSelectionState selection; public MoveParameters(double deltaX, double deltaY, FrameSelectionState selnState) { dx = deltaX; dy = deltaY; selection = selnState; } } /** * Parameters for DuplicateFrames operation * * @author mlh */ public static class DuplicateParameters { public double dx; public double dy; public DesignEditorSelectionState selection; public DuplicateParameters(double deltaX, double deltaY, DesignEditorSelectionState selnState) { dx = deltaX; dy = deltaY; selection = selnState; } } /** * Parameters for CreateTransition operation * * @author mlh */ public static class NewTransitionParameters { public TransitionSource source; public Frame target; public double x; public double y; // Ok for target to be null -- means that a new Frame should be built public NewTransitionParameters(TransitionSource transitionSource, Frame targetFrame, double atX, double atY) { source = transitionSource; target = targetFrame; x = atX; y = atY; } } public static class EditTransitionParameters { public DesignEditorSelectionState selection; public int useWhichParts; public EditTransitionParameters(DesignEditorSelectionState seln, int whichParts) { selection = seln; useWhichParts = whichParts; } } public static class DesignRenameParameters { public Design design; public String newText; public DesignRenameParameters(Design d, String text) { design = d; newText = text; } } /** * Parameters for ChangeTarget operation * * @author mlh */ public static class ChangeTargetParameters { public Transition transition; public Frame newDestination; public ChangeTargetParameters(Transition t, Frame f) { transition = t; newDestination = f; } } /** * Parameters for ChangeSource operation * * @author mlh */ public static class ChangeSourceParameters { public Transition transition; public TransitionSource newSource; public ChangeSourceParameters(Transition t, TransitionSource s) { transition = t; newSource = s; } } /** * Parameters for ChangeWidgetAction/ChangeDeviceAction operations * * @author mlh */ public static class ChangeActionParameters { public DesignEditorSelectionState selection; public ActionProperties properties; public ChangeActionParameters(ActionProperties p, DesignEditorSelectionState s) { properties = p; selection = s; } } public static class ChangeDelayParameters { public DesignEditorSelectionState selection; public double delayInSecs; public String delayLabel; public ChangeDelayParameters(double duration, String label, DesignEditorSelectionState s) { delayInSecs = duration; delayLabel = label; selection = s; } } public static class PasteBackgroundImageParms { public FrameSelectionState selection; public byte[] imageData; public PasteBackgroundImageParms(FrameSelectionState seln, byte[] imgData) { selection = seln; imageData = imgData; } } public static class CopyBackgroundImageParms { public byte[] imageData; public Frame selectedFrame; public CopyBackgroundImageParms(byte[] imgData, Frame frame) { imageData = imgData; selectedFrame = frame; } } // For renaming a Frame public static class FrameRenameParameters { public Frame frame; public String newName; public FrameRenameParameters(Frame frameToRename, String newFrameName) { frame = frameToRename; newName = newFrameName; } } // Constants for DesignEditorTransition resize thumb positions // (used by DesignEditorMouseState) public static final int SOURCE = DesignEditorTransition.SOURCE; public static final int TARGET = DesignEditorTransition.TARGET; protected DesignEditorView view; protected DesignEditorSelectionState selection; protected DesignEditorSelectionState contextSelection; protected static final DesignEditorSelectionState emptySelection = new DesignEditorSelectionState(); protected DesignEditorInteraction interaction; protected FrameNameEditor editor = null; protected boolean editingInProgress = false; protected DesignEditorUIModel uiModel; protected StructureViewUIModel structureView; // cached from uiModel! protected DelayedSelection delayedFrameSelection; protected DelayedSelection delayedTransitionSelection; // Constants for delayedRepainting; powers of 2! protected static final int REPAINT_SELECT_HANDLES = 1; protected static final int REPAINT_EDITOR = 2; protected static final int PERFORM_LWS_UPDATE = 4; // protected static final int REPAINT_VIEW = 8; protected static final int ZOOM_REPAINT = REPAINT_EDITOR | REPAINT_SELECT_HANDLES; protected static final int UPDATE_REPAINT = REPAINT_SELECT_HANDLES | PERFORM_LWS_UPDATE; protected static final int REPAINT_ALL = DelayedRepaint.REPAINT_ALL; protected DelayedRepaint delayedRepainting; protected DesignEditorUI.EditTransitionParameters editTransitionParms; protected Design design; protected static final String DESIGN_PREFIX = L10N.get("WT.DesignPrefix", "Design"); protected static final String FRAME_LABEL = L10N.get("WT.FrameLabel", "Frame"); protected static final String FRAMES_LABEL = L10N.get("WT.FramesLabel", "Frames"); protected static final String TRANSITION_LABEL = L10N.get("WT.TransitionLabel", "Transition"); protected static final String TRANSITIONS_LABEL = L10N.get("WT.TransitionsLabel", "Transitions"); protected static final String SELECT_ALL_FRAMES = L10N.get("DE.SelectAllFrames", "Select All Frames"); protected static final String SET_FRAME_BKG_IMAGE = L10N.get("DE.SetFrameBkgImage", "Set Background Image..."); protected static final String REMOVE_FRAME_BKG_IMAGE = L10N.get("DE.RemoveFrameBkgImage", "Remove Background Image"); protected static String buildWindowMenuLabel(Design design) { String designName = SWTStringUtil.insertEllipsis(design.getName(), StringUtil.EQUAL, SWTStringUtil.DEFAULT_FONT); return DESIGN_PREFIX + ": " + designName; } public DesignEditorUI(final Design designToEdit, Project designProject, UndoManager undoMgr) { super(designProject, buildWindowMenuLabel(designToEdit), buildLeadItems(designProject), undoMgr); design = designToEdit; selection = new DesignEditorSelectionState(); contextSelection = new DesignEditorSelectionState(); delayedFrameSelection = new DelayedSelection(selection) { @Override protected void selectItem(Object item) { selection.selectFrame((DesignEditorFrame) item); } }; delayedTransitionSelection = new DelayedSelection(selection) { @Override protected void selectItem(Object item) { selection.selectTransition((DesignEditorTransition) item); } }; delayedRepainting = new DelayedRepaint() { @Override protected void performRepaint() { InteractionDrawingEditor viewEditor = view.getEditor(); if (isRepaintNeeded(REPAINT_EDITOR)) { repaintEditor(); } // Don't know why, but this must come // *before* repaintSelectHandles! if (isRepaintNeeded(PERFORM_LWS_UPDATE)) { viewEditor.getLWS().getUpdateManager().performUpdate(); } if (isRepaintNeeded(REPAINT_SELECT_HANDLES)) { repaintSelectHandles(); } updateView(false); // if (isRepaintNeeded(REPAINT_VIEW)) { // viewEditor.repaint(); // } } @Override public void doWork() { // Must do Draw2D changes before requesting refresh uiModel.resetHiddenTransitionSources(); super.doWork(); undoMgrViewHandler.resetView(undoManager); // Update the enabled items selection state. setViewEnabledState(selection, ListenerIdentifierMap.NORMAL); } @Override public void reset(boolean notCanceled) { // TODO: for now, reset text box regardless of what // action was actually canceled if (! notCanceled) { if (selection.getSelectedTransitionCount() == 1) { Transition t = selection.getSelectedTransitions()[0]; AAction a = t.getAction(); ActionPropertySet aps = view.getActionPropertySet(); if (t.getSource() instanceof IWidget) { aps.resetMode(a); } if (a instanceof TextAction) { String newString = ((TextAction) a).getText(); if (a instanceof KeyAction) { aps.setKeyboardString(newString); } else if (a instanceof GraffitiAction) { aps.setGraffitiString(newString); } else if (a instanceof VoiceAction) { aps.setVoiceString(newString); } } } } } }; CogTool.selectionPhase.addDelayedWork(delayedFrameSelection); CogTool.selectionPhase.addDelayedWork(delayedTransitionSelection); CogTool.repaintPhase.addDelayedWork(delayedRepainting); uiModel = new DesignEditorUIModel(design, designProject, new AlertHandler() { public void handleAlert(EventObject a) { delayedRepainting.requestRepaint(UPDATE_REPAINT); } }, new AlertHandler() { public void handleAlert(EventObject a) { updateView(false); } }); // Cache the structure view since it's used so often here structureView = uiModel.getStructureView(); final DesignEditorMouseState mouseState = new DesignEditorMouseState(this); int deviceTypes = DeviceType.buildDeviceSet(design.getDeviceTypes()); editTransitionParms = new DesignEditorUI.EditTransitionParameters(selection, ActionProperties.UNSET); view = new DesignEditorView(deviceTypes, lIDMap, this, editTransitionParms, menuData, structureView.getContents(), mouseState, mouseState, this, getWindowLocation()); //... check out deleteKeyL and other addKeyL calls in FrameEditorUIModel view.getActionPropertySet().updateEmptyComposite(design, true); SelectionListener treeListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { boolean needToDeselect = true; Tree t = (Tree) evt.getSource(); TreeItem[] items = t.getSelection(); for (TreeItem item : items) { Object data = item.getData(); if (data instanceof Frame) { if (needToDeselect) { selection.deselectAll(); needToDeselect = false; } DesignEditorFrame frameFig = structureView.getFrameFigure((Frame) data); selection.selectFrame(frameFig); centerSelectedRegion(); } else if (data instanceof Transition) { if (needToDeselect) { selection.deselectAll(); needToDeselect = false; } DesignEditorTransition transFig = structureView.getTransitionFigure((Transition) data); selection.selectTransition(transFig); centerSelectedRegion(); } } mouseState.cleanup(); } }; view.getActionPropertySet().setTreeListener(treeListener); // Add them to the contents. InteractionDrawingEditor drawingEditor = view.getEditor(); setZoomEditor(drawingEditor); // Let mouseState handle delete key events drawingEditor.getInteractionFigure().addKeyListener(mouseState); Canvas editorSubstrate = drawingEditor.getSWTEditorSubstrate(); //TODO: This code is used in a number of places. Should it be moved to // interaction drawing editor? editorSubstrate.addListener(SWT.MenuDetect, mouseState); setUpDropImageSupport(editorSubstrate); updateTitle(); interaction = new DesignEditorInteraction(view); editorSubstrate.addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { if (editingInProgress) { confirmRenameFrame(); } else { editingInProgress = true; } } @Override public void mouseDown(MouseEvent e) { if (editingInProgress) { confirmRenameFrame(); } else { editingInProgress = true; } } }); // Restore zoom level restoreZoom(); selection.addHandler(this, FrameSelectionChange.class, createFrameSelectionHandler()); selection.addHandler(this, TransitionSelectionChange.class, createTransitionSelectionHandler()); structureView.addHandler(this, StructureViewUIModel.FrameAdd.class, createFrameAddHandler()); structureView.addHandler(this, StructureViewUIModel.FrameShapeChange.class, createFrameShapeChangeHandler()); structureView.addHandler(this, StructureViewUIModel.FrameNameChange.class, createFrameNameChangeHandler()); structureView.addHandler(this, StructureViewUIModel.FrameRecovery.class, createFrameRecoveryHandler()); structureView.addHandler(this, StructureViewUIModel.TransitionAddRemove.class, createTransitionAddRemoveHandler()); project.addHandler(this, Project.DesignChange.class, new AlertHandler() { public void handleAlert(EventObject alert) { Project.DesignChange chg = (Project.DesignChange) alert; if ((! chg.isAdd) && (chg.element == designToEdit)) { closeOpenController(); } } }); setFrameChangeHandlers(design); // Some items should always be enabled. setInitiallyEnabled(true); } // ctor protected void setUpDropImageSupport(final Canvas editorSubstrate) { setUpDropImage(editorSubstrate, new ExternalImageDropTarget() { protected DesignEditorFrame dropTargetFrame = null; @Override public void dragOperationChanged(DropTargetEvent evt) { if (dropTargetFrame == null) { evt.detail = DND.DROP_NONE; } else { super.dragOperationChanged(evt); } } @Override public void dragOver(DropTargetEvent evt) { super.dragOver(evt); if (dropTargetFrame == null) { evt.detail = DND.DROP_NONE; } } @Override protected void cancelHighlight(DropTargetEvent evt) { if (dropTargetFrame != null) { dropTargetFrame.dynamicHighlight(false); } } @Override protected void highlight(DropTargetEvent evt) { org.eclipse.swt.graphics.Point pt = editorSubstrate.toControl(evt.x, evt.y); DesignEditorFrame frameFig = structureView.getFrameAtXY(pt.x, pt.y); if (dropTargetFrame != frameFig) { cancelHighlight(evt); if (frameFig != null) { frameFig.dynamicHighlight(true); } dropTargetFrame = frameFig; } } @Override protected Object buildParameters(DropTargetEvent evt, byte[] imgData) { org.eclipse.swt.graphics.Point pt = editorSubstrate.toControl(evt.x, evt.y); DesignEditorFrame frameFig = structureView.getFrameAtXY(pt.x, pt.y); if (frameFig != null) { return new DesignEditorUI.CopyBackgroundImageParms(imgData, frameFig.getFrame()); } return null; } }); } /** * Support for resetting transition source anchors for those transitions * whose sources may be "hidden". */ public void resetHiddenTransitionSources() { uiModel.resetHiddenTransitionSources(); performRepaintUpdates(); } @Override protected void updateTitle() { view.setWindowTitle(modificationFlag + DESIGN_PREFIX + ": " + project.getName() + " > " + uiModel.getDesign().getName() + ((OSUtils.MACOSX) ? "" : UI.WINDOW_TITLE)); } @Override protected String buildWindowMenuLabel() { return buildWindowMenuLabel(uiModel.getDesign()); } /** * Recover any system resources being used to support this window/view. * * @author mlh */ @Override public void dispose() { if (editor != null) { editor.dispose(); } CogTool.selectionPhase.removeDelayedWork(delayedFrameSelection); CogTool.selectionPhase.removeDelayedWork(delayedTransitionSelection); CogTool.repaintPhase.removeDelayedWork(delayedRepainting); structureView.removeAllHandlers(this); uiModel.getDesign().removeAllHandlers(this); uiModel.dispose(); selection.removeAllHandlers(this); // Need to remove structure view before disposing the display, since // the structure view dispose will try and deselect all before // disposing its self. super.dispose(); } @Override protected Object getModelObject() { return uiModel.getDesign(); } public DesignEditorInteraction getInteraction() { return interaction; } /** * Standard interaction needed by AController; * leaf subclasses must implement. * * @author mlh */ @Override public Interaction getStandardInteraction() { return interaction; } /* * Selection */ public DesignEditorSelectionState getSelection() { return selection; } public void selectAllFrames() { // deselect any selected transitions selection.deselectAllTransitions(); Iterator<DesignEditorFrame> frameFigures = structureView.getAllFrameFigures(); while (frameFigures.hasNext()) { DesignEditorFrame frameFigure = frameFigures.next(); selection.selectFrame(frameFigure); } } public DesignEditorSelectionState getSelectionState() { return selection; } @Override public View getView() { return view; } // Really want a keyword for "package" visibility! protected InteractionDrawingEditor getViewEditor() { return view.getEditor(); } // For use solely by DesignEditorControllerTest! public DesignEditorUIModel getUIModel() { return uiModel; } protected AlertHandler createFrameSelectionHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { FrameSelectionChange evt = (FrameSelectionChange) alert; ActionPropertySet actionProps = view.getActionPropertySet(); if (evt != null) { if (evt.changedFrameFigure != null) { evt.changedFrameFigure.setSelected(evt.selected); // Handle property sheet selection Frame[] selectedFrames = selection.getSelectedFrames(); int selectedFrameCount = selectedFrames.length; if (selectedFrameCount > 0) { actionProps.setComposite(ActionPropertySet.FRAME); if (selectedFrameCount == 1) { actionProps.setFrameName(selectedFrames[0]); } } else { actionProps.setComposite(ActionSet.USE_NONE); } actionProps.enableFrameName(selectedFrameCount == 1); } else { actionProps.setComposite(ActionSet.USE_NONE); Iterator<DesignEditorFrame> frameFigures = selection.getSelectedFrameFigures(); while (frameFigures.hasNext()) { DesignEditorFrame frameFigure = frameFigures.next(); frameFigure.setSelected(evt.selected); } } // Repaint the frame contents delayedRepainting.requestRepaint(REPAINT_ALL); } } }; } // createFrameSelectionHandler protected AlertHandler createTransitionSelectionHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { TransitionSelectionChange evt = (TransitionSelectionChange) alert; if (evt != null) { InteractionDrawingEditor editor = view.getEditor(); if (evt.changedTransitionFigure != null) { evt.changedTransitionFigure.setSelected(editor, evt.selected); } else { Iterator<DesignEditorTransition> transitionFigures = selection.getSelectedTransitionFigures(); while (transitionFigures.hasNext()) { DesignEditorTransition transitionFigure = transitionFigures.next(); transitionFigure.setSelected(editor, evt.selected); } } // Repaint the contents delayedRepainting.requestRepaint(REPAINT_ALL); updateView(evt.changedTransitionFigure == null); } } }; } // createTransitionSelectionHandler public void resetVisibleArea() { StandardDrawingEditor e = view.getEditor(); e.getLWS().getUpdateManager().performUpdate(); DoubleSize extent = structureView.getPreferredSize(); e.setMinVisibleArea(PrecisionUtilities.round(extent.width), PrecisionUtilities.round(extent.height), false); } protected void ensureRectIsVisible(Rectangle frameBounds) { resetVisibleArea(); StandardDrawingEditor e = view.getEditor(); org.eclipse.swt.graphics.Rectangle visibleBounds = e.getVisibleBounds(); double scale = structureView.getZoom(); double right = frameBounds.x + frameBounds.width; double bottom = frameBounds.y + frameBounds.height; int frameX = PrecisionUtilities.round(frameBounds.x * scale); int frameY = PrecisionUtilities.round(frameBounds.y * scale); int frameWidth = PrecisionUtilities.round(right * scale) - frameX; int frameHeight = PrecisionUtilities.round(bottom * scale) - frameY; int newOriginX; int newOriginY; // If possible, move the origin to contain the frame if (visibleBounds.width >= frameWidth) { if (frameX < visibleBounds.x) { newOriginX = frameX; } else { newOriginX = visibleBounds.x; int frameRight = frameX + frameWidth; int visibleRight = visibleBounds.x + visibleBounds.width; if (frameRight > visibleRight) { newOriginX += (frameRight - visibleRight); } } } else { // Otherwise, center the frame horizontally newOriginX = frameX + (frameWidth / 2) - (visibleBounds.width / 2); } // If possible, move the origin to contain the frame if (visibleBounds.height >= frameHeight) { if (frameY < visibleBounds.y) { newOriginY = frameY; } else { newOriginY = visibleBounds.y; int frameBottom = frameY + frameHeight; int visibleBottom = visibleBounds.y + visibleBounds.height; if (frameBottom > visibleBottom) { newOriginY += (frameBottom - visibleBottom); } } } else { // Otherwise, use the top of the frame newOriginY = frameY; } e.setScrollOrigin(newOriginX, newOriginY); } // ensureRectIsVisible protected AlertHandler createFrameAddHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { StructureViewUIModel.FrameAdd evt = (StructureViewUIModel.FrameAdd) alert; ensureRectIsVisible(evt.frameFigure.getBounds()); } }; } protected AlertHandler createFrameShapeChangeHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { StructureViewUIModel.FrameShapeChange evt = (StructureViewUIModel.FrameShapeChange) alert; resetVisibleArea(); if ((editor != null) && editor.getVisible() && (evt.getFrameFigure() == (DesignEditorFrame) editor.getData())) { delayedRepainting.requestRepaint(REPAINT_EDITOR); } delayedRepainting.requestRepaint(REPAINT_SELECT_HANDLES); // Ensure that the frame is still visible. ensureRectIsVisible(evt.getFrameFigure().getBounds()); } }; } protected AlertHandler createFrameNameChangeHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { StructureViewUIModel.FrameNameChange evt = (StructureViewUIModel.FrameNameChange) alert; Frame f = evt.getFrame(); if (selection.isFrameSelected(f)) { view.getActionPropertySet().setFrameName(f); } } }; } protected AlertHandler createFrameRecoveryHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { StructureViewUIModel.FrameRecovery evt = (StructureViewUIModel.FrameRecovery) alert; if (evt != null) { DesignEditorFrame frameFigure = evt.getFrameFigure(); selection.deselectFrame(frameFigure); // If removing the DesignEditorFrame for the // rename text editor, cancel the rename // operation and clean up. cleanupFrameEditor(frameFigure); } } }; } protected AlertHandler createTransitionAddRemoveHandler() { return new AlertHandler() { public void handleAlert(EventObject alert) { StructureViewUIModel.TransitionAddRemove evt = (StructureViewUIModel.TransitionAddRemove) alert; if (evt != null) { DesignEditorTransition transitionFigure = evt.getTransitionFigure(); if (evt.isAdd) { delayedTransitionSelection.addToSelection(transitionFigure.getTransition(), transitionFigure); } else if (transitionFigure.isSelected()) { selection.deselectTransition(transitionFigure); delayedTransitionSelection.removeFromSelection(transitionFigure.getTransition()); } } } }; } protected void setFrameChangeHandlers(final Design design) { design.addHandler(this, NameChangeAlert.class, renameHandler); AlertHandler frameChangeHandler = new AlertHandler() { public void handleAlert(EventObject alert) { Design.FrameChange chg = (Design.FrameChange) alert; if (chg != null) { updateView(false); Frame frame = (Frame) chg.element; if (chg.isAdd) { DesignEditorFrame frameFigure = structureView.getFrameFigure(frame); // A newly created frame should be selected. delayedFrameSelection.addToSelection(frame, frameFigure); } else { delayedFrameSelection.removeFromSelection(frame); } delayedRepainting.requestRepaint(REPAINT_ALL); } } }; design.addHandler(this, Design.FrameChange.class, frameChangeHandler); frameChangeHandler = new AlertHandler() { public void handleAlert(EventObject alert) { Design.FrameSetChange chg = (Design.FrameSetChange) alert; if (chg != null) { updateView(false); if (chg.isAdd) { for (Frame frame : chg.frames) { DesignEditorFrame frameFigure = structureView.getFrameFigure(frame); // A newly created frame should be selected. delayedFrameSelection.addToSelection(frameFigure.getFrame(), frameFigure); } delayedRepainting.requestRepaint(REPAINT_ALL); } else { for (Frame frame : chg.frames) { delayedFrameSelection.removeFromSelection(frame); } } } } }; design.addHandler(this, Design.FrameSetChange.class, frameChangeHandler); design.addHandler(this, Design.DeviceTypeChange.class, new AlertHandler() { public void handleAlert(EventObject alert) { Set<DeviceType> deviceTypeSet = design.getDeviceTypes(); int deviceTypes = DeviceType.buildDeviceSet(deviceTypeSet); view.resetDeviceTypes(deviceTypes); } }); } // setFrameChangeHandlers @Override public void setZoom(double scale) { super.setZoom(scale); delayedRepainting.requestRepaint(ZOOM_REPAINT); } /** * Sets the "always-enabled" widgets; * call this at the end of the subclass constructor! * * @author mlh */ @Override protected void setInitiallyEnabled(boolean forConstruction) { super.setInitiallyEnabled(forConstruction); setEnabled(CogToolLID.NewFrame, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.AddDesignDevices, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ZoomNormal, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ZoomIn, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ZoomOut, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ZoomToFit, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.SkinNone, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.SkinWireFrame, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.SkinWinXP, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.SkinMacOSX, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.SkinPalm, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.RenderAll, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.UnRender, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ExportDesignToHTML, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setEnabled(CogToolLID.ExportToXML, ListenerIdentifierMap.ALL, MenuUtil.ENABLED, L10N.get("DE.ExportXMLLabel", "Export Design to XML")); setEnabled(DesignEditorLID.ImportImageDirectory, ListenerIdentifierMap.ALL, MenuUtil.ENABLED); setViewEnabledState(selection, ListenerIdentifierMap.NORMAL); } public void setLIDEnabledState() { setViewEnabledState(selection, ListenerIdentifierMap.NORMAL); } /** * Enables or disables LIDs as appropriate * @param sel the selection state on which to base enabling/disabling * @param availability NORMAL or CONTEXT * @see ListenerIdentifierMap */ protected void setViewEnabledState(DesignEditorSelectionState sel, Boolean availability) { String label = ""; int frameCount = sel.getSelectedFrameCount(); if (frameCount > 0) { if (frameCount > 1) { label = " " + FRAMES_LABEL; } else { label = " " + FRAME_LABEL; } } int transitionCount = sel.getSelectedTransitionCount(); if (transitionCount > 0) { if (transitionCount > 1) { label = " " + TRANSITIONS_LABEL; } else { label = " " + TRANSITION_LABEL; } } Text t = WindowUtil.getFocusedText(); boolean editing = ((editor != null) && editor.getVisible()); String cutCopyLabel = (editing || (t != null)) ? "" : label; boolean enabled = (frameCount > 0) || (transitionCount == 1); String editString = MenuFactory.EDIT_STRING; if (enabled) { editString += label; } setEnabled(CogToolLID.Edit, availability, enabled, editString); enabled = (frameCount > 0) || (transitionCount > 0); String deleteString = MenuFactory.DELETE_STRING + label; setEnabled(CogToolLID.Delete, availability, enabled, deleteString); // Enable move/reorder items if any frames are selected enabled = (frameCount > 0); String cutString = MenuFactory.CUT_STRING; if (enabled) { cutString += cutCopyLabel; } setEnabled(CogToolLID.Cut, availability, enabled, cutString); String copyString = MenuFactory.COPY_STRING; if (enabled) { copyString += cutCopyLabel; } setEnabled(CogToolLID.Copy, availability, enabled, copyString); setEnabled(CogToolLID.NudgeLeft, availability, enabled); setEnabled(CogToolLID.NudgeRight, availability, enabled); setEnabled(CogToolLID.NudgeDown, availability, enabled); setEnabled(CogToolLID.NudgeUp, availability, enabled); // TODO: For now, don't allow duplication of transitions String dupString = MenuFactory.DUPLICATE_STRING; if (enabled) { dupString += label; } setEnabled(CogToolLID.Duplicate, availability, enabled, dupString); // the following 3 menu items involve code snippets copied from // FrameEditor classes setEnabled(CogToolLID.SetBackgroundImage, availability, enabled, SET_FRAME_BKG_IMAGE); setEnabled(CogToolLID.SetWidgetColor, availability, enabled); // only enable RemoveBackgroundImage if there are selected frames if (enabled) { // and at least one of those frames has a background image boolean foundBackgroundImage = false; Frame[] selFrames = sel.getSelectedFrames(); for (Frame selFrame : selFrames) { if (selFrame.getBackgroundImage() != null) { foundBackgroundImage = true; break; } } setEnabled(CogToolLID.RemoveBackgroundImage, availability, foundBackgroundImage, REMOVE_FRAME_BKG_IMAGE); } else { setEnabled(CogToolLID.RemoveBackgroundImage, availability, enabled, REMOVE_FRAME_BKG_IMAGE); } // setEnabled(CogToolLID.BringToFront, availability, enabled); // setEnabled(CogToolLID.BringForward, availability, enabled); // setEnabled(CogToolLID.SendBackward, availability, enabled); // setEnabled(CogToolLID.SendToBack, availability, enabled); // Enable alignment items if multiple frames are selected enabled = (frameCount > 1); setEnabled(CogToolLID.AlignTop, availability, enabled); setEnabled(CogToolLID.AlignBottom, availability, enabled); setEnabled(CogToolLID.AlignLeft, availability, enabled); setEnabled(CogToolLID.AlignRight, availability, enabled); setEnabled(CogToolLID.AlignCenter, availability, enabled); setEnabled(CogToolLID.AlignHorizCenter, availability, enabled); setEnabled(CogToolLID.AlignVertCenter, availability, enabled); // Enable spacing items if at least 3 frames are selected enabled = (frameCount >= 3); setEnabled(CogToolLID.SpaceVertically, availability, enabled); setEnabled(CogToolLID.SpaceHorizontally, availability, enabled); // Edit and Rename enabled if a single selection enabled = (frameCount == 1); String renameString = MenuFactory.RENAME_STRING; if (enabled) { renameString += label; } setEnabled(CogToolLID.Rename, availability, enabled, renameString); Design modelDesign = uiModel.getDesign(); enabled = (modelDesign.getFrames().size() > 0); setEnabled(CogToolLID.SelectAll, availability, enabled, SELECT_ALL_FRAMES); // Draws the dot to indicate that the correct skin type is selected setSelected(CogToolLID.SkinNone, availability, false); setSelected(CogToolLID.SkinWireFrame, availability, false); setSelected(CogToolLID.SkinMacOSX, availability, false); setSelected(CogToolLID.SkinWinXP, availability, false); setSelected(CogToolLID.SkinPalm, availability, false); SkinType skin = modelDesign.getSkin(); CogToolLID id = null; if (skin == SkinType.None) { id = CogToolLID.SkinNone; } else if (skin == SkinType.WireFrame) { id = CogToolLID.SkinWireFrame; } else if (skin == SkinType.MacOSX) { id = CogToolLID.SkinMacOSX; } else if (skin == SkinType.WinXP) { id = CogToolLID.SkinWinXP; } else if (skin == SkinType.Palm) { id = CogToolLID.SkinPalm; } if (id != null) { setSelected(id, availability, true); } setEnabled(CogToolLID.ClearFrameTemplate, ListenerIdentifierMap.ALL, FrameTemplateSupport.hasFrameTemplate(design)); } // LID Transmuter Stuff @Override public ListenerIdentifier transmute(ListenerIdentifier id, boolean isContextSelection) { ListenerIdentifier specificLID = super.transmute(id, isContextSelection); // Check if super has already specialized this if (specificLID != id) { return specificLID; } DesignEditorSelectionState seln = isContextSelection ? contextSelection : selection; // Give priority to frame stuff if (seln.getSelectedFrameCount() > 0) { if ((id == CogToolLID.Paste) && ClipboardUtil.hasImageData()) { return CogToolLID.PasteBackgroundImage; } specificLID = DesignEditorLID.frameLIDs.get(id); } // Fallback to undertaking stuff if necessary else { specificLID = DesignEditorLID.transitionLIDs.get(id); } return (specificLID != null) ? specificLID : id; } /** * Do any set-up before <code>performAction</code> is invoked. * * @param id the transmuted key specifying the semantic nature of the * action to be performed */ @Override protected void setUpPerformAction(ListenerIdentifier id) { super.setUpPerformAction(id); int selectionMask = canIDCauseSelection(id); if (isSelectionFlagSet(selectionMask, DesignEditorLID.CAUSES_FRAME_SELECTION)) { delayedFrameSelection.setActive(true); } if (isSelectionFlagSet(selectionMask, DesignEditorLID.CAUSES_TRANSITION_SELECTION)) { delayedTransitionSelection.setActive(true); } } @Override public Object getParameters(ListenerIdentifier originalLID, ListenerIdentifier transmutedLID, boolean isContextSelection) { Object parameters = super.getParameters(originalLID, transmutedLID, isContextSelection); if (parameters != UNSET) { return parameters; } setUpPerformAction(transmutedLID); DesignEditorSelectionState selnStateToUse = isContextSelection ? contextSelection : selection; if (transmutedLID == CogToolLID.PasteBackgroundImage) { return new DesignEditorUI.PasteBackgroundImageParms(selnStateToUse, ClipboardUtil.fetchImageData()); } // Merged paths for editing widgets, since GRAFFITI crosses both if ((transmutedLID == DesignEditorLID.ChangeWidgetAction) || (transmutedLID == DesignEditorLID.ChangeDeviceAction)) { return new DesignEditorUI.ChangeActionParameters(view.getActionProperties(), selnStateToUse); } if (transmutedLID == DesignEditorLID.ChangeDelay) { ActionProperties properties = view.getActionProperties(); return new DesignEditorUI.ChangeDelayParameters(properties.delayInSecs, properties.delayLabel, selnStateToUse); } if (transmutedLID == DesignEditorLID.DuplicateFrame) { return new DesignEditorUI.DuplicateParameters(16.0, 16.0, selnStateToUse); } if (transmutedLID == DesignEditorLID.EditTransition) { return new DesignEditorUI.EditTransitionParameters(selnStateToUse, ActionProperties.UNSET); } if (transmutedLID == DesignEditorLID.AlignTop || transmutedLID == DesignEditorLID.AlignBottom || transmutedLID == DesignEditorLID.AlignLeft || transmutedLID == DesignEditorLID.AlignRight || transmutedLID == DesignEditorLID.AlignCenter || transmutedLID == DesignEditorLID.AlignHorizCenter || transmutedLID == DesignEditorLID.AlignVertCenter || transmutedLID == DesignEditorLID.SpaceHorizontally || transmutedLID == DesignEditorLID.SpaceVertically) { Frame[] frames = selection.getSelectedFrames(); Map<Frame, DoubleRectangle> frameMap = new HashMap<Frame, DoubleRectangle>(); for (Frame frame : frames) { DesignEditorFrame figure = structureView.getFrameFigure(frame); Rectangle bounds = figure.getBounds(); frameMap.put(frame, new DoubleRectangle(bounds.x, bounds.y, bounds.width, bounds.height)); } return frameMap; } return selnStateToUse; } /** * Allows the interfaces to clean up any feedback provided to the * user before and during a performAction. * * @param okToContinue the return value from performAction * @param menuHidden whether or not the context menu is dismissed * without selecting an operation to perform * @author mlh */ @Override public void cleanup(boolean okToContinue, boolean menuHidden) { if (menuHidden) { Iterator<DesignEditorFrame> frameFigs; if (selection.getSelectedFrameCount() > 0) { frameFigs = selection.getSelectedFrameFigures(); while (frameFigs.hasNext()) { DesignEditorFrame fig = frameFigs.next(); fig.dynamicHighlight(false); } } if (contextSelection.getSelectedFrameCount() > 0) { frameFigs = contextSelection.getSelectedFrameFigures(); while (frameFigs.hasNext()) { DesignEditorFrame fig = frameFigs.next(); fig.dynamicHighlight(false); } } } super.cleanup(okToContinue, menuHidden); } /** * Triggers the frame-renaming functionality in the UI on the given * frame. */ public void initiateFrameRename(Frame frameToRename) { DesignEditorFrame renameFrameFigure = structureView.getFrameFigure(frameToRename); initiateFrameRename(renameFrameFigure); } /** * Triggers the frame-renaming functionality in the UI on the given * selection. */ public void initiateFrameRename(FrameSelectionState frameToRename) { // Can progress only if one frame is selected if (frameToRename.getSelectedFrameCount() == 1) { // Rename the selected frame initiateFrameRename(frameToRename.getSelectedFrames()[0]); } } public void initiateFrameRename(DesignEditorFrame frameFigure) { // The editor control must be a child of an SWT object (the canvas) if (editor == null) { editor = new FrameNameEditor(); } if (frameFigure != null) { editor.editFrameName(frameFigure); } setViewEnabledState(selection, ListenerIdentifierMap.NORMAL); } protected void repaintEditor() { if (editor != null) { editor.repaintTextEditor(structureView.getZoom()); } } protected boolean confirmRenameFrame() { boolean success = true; if ((editor != null) && editor.inUse()) { String newName = editor.getText(); DesignEditorFrame frameFigure = (DesignEditorFrame) editor.getData(); Frame frameToRename = frameFigure.getFrame(); cleanupFrameEditor(frameFigure); success = performAction(DesignEditorLID.RenameFrame, new DesignEditorUI.FrameRenameParameters(frameToRename, newName), false); } return success; } /** * Removes stale Text control and selection listener, but only * if the editor is for the given DesignEditorFrame; if the given * frame figure is <code>null</code>, simply clean up. */ protected void cleanupFrameEditor(DesignEditorFrame frameFig) { // Prevent access to the frame name Text editor // frameFig is null or is editing the given frame's name if ((editor != null) && editor.inUse() && (frameFig == editor.getData())) { editor.cleanup(); setViewEnabledState(selection, ListenerIdentifierMap.NORMAL); } } /** * Removes stale Text control and selection listener. */ protected void cleanupFrameEditor() { if (editor != null) { editor.cleanup(); } } protected void showContextMenu(DesignEditorSelectionState seln, boolean context) { setViewEnabledState(seln, ListenerIdentifierMap.CONTEXT); if (seln.getSelectedFrameCount() > 0) { view.showFrameMenu(context); } else if (seln.getSelectedTransitionCount() > 0) { view.showTransitionMenu(context); } else { view.showStandardMenu(); } } @Override public void showContextMenu() { showContextMenu(selection, View.SELECTION); } // Context menu stuff @Override public void showContextMenu(int x, int y) { // Check which region was hit IFigure fig = structureView.getFigureAtXY(x, y, StructureViewUIModel.NO_SOURCE); // Invocation in empty space if (fig == null) { contextSelection.deselectAll(); showContextMenu(contextSelection, View.CONTEXT); } // Invocation on a Transition else if (fig instanceof DesignEditorTransition) { DesignEditorTransition transitionFig = (DesignEditorTransition) fig; //fig.setToolTip(null); if (transitionFig.isSelected()) { showContextMenu(); } else { // Populate the context selection contextSelection.setSelectedTransition(transitionFig); showContextMenu(contextSelection, View.CONTEXT); } } // Invocation on a Frame else { // fig instanceof DesignEditorFrame DesignEditorFrame frameFig = (DesignEditorFrame) fig; if (frameFig.isSelected()) { // Indicate the selection to be used visually Iterator<DesignEditorFrame> figs = selection.getSelectedFrameFigures(); while (figs.hasNext()) { frameFig = figs.next(); frameFig.dynamicHighlight(true); } showContextMenu(); } else { // Indicate the context selection visually frameFig.dynamicHighlight(true); // Populate the context selection contextSelection.setSelectedFrame(frameFig); showContextMenu(contextSelection, View.CONTEXT); } view.getEditor().getLWS().getUpdateManager().performUpdate(); } } // showContextMenu protected void setFigureOrigin(IFigure f, double x, double y) { f.setLocation(new Point(PrecisionUtilities.round(x), PrecisionUtilities.round(y))); } protected void repaintSelectHandles() { Iterator<DesignEditorTransition> selectedTransitions = selection.getSelectedTransitionFigures(); while (selectedTransitions.hasNext()) { DesignEditorTransition selectedTransition = selectedTransitions.next(); // May be in the midst of deselecting; check! if (selectedTransition.isSelected()) { selectedTransition.repaintSelection(view.getEditor()); } } } /** * Support for refresh during dynamic operations * (e.g., DesignEditorMouseState). */ protected void performRepaintUpdates() { view.getEditor().getLWS().getUpdateManager().performUpdate(); repaintSelectHandles(); } /** * Support for centering selection when zooming */ @Override protected Rectangle getSelectedRegion() { Iterator<DesignEditorFrame> selectedFigs = selection.getSelectedFrameFigures(); Rectangle r = computeUnion(selectedFigs); if (r != null) { return r; } if (selection.getSelectedTransitionCount() > 0) { Iterator<DesignEditorTransition> transitionFigs = selection.getSelectedTransitionFigures(); return computeUnion(transitionFigs); } return super.getSelectedRegion(); } protected void updateView(boolean deselectAll) { if (view.isDisposed()) { return; } ActionPropertySet actionProps = view.getActionPropertySet(); int selectedTransitionCount = selection.getSelectedTransitionCount(); int selectedFrameCount = selection.getSelectedFrameCount(); if (deselectAll || (selectedFrameCount + selectedTransitionCount == 0)) { actionProps.useParameters(ActionSet.USE_NONE); } else if (selectedTransitionCount == 1) { Transition transition = selection.getSelectedTransitions()[0]; AAction action = transition.getAction(); DeviceType type = action.getDefaultDeviceType(); int device = ActionSet.USE_NONE; if (action instanceof GraffitiAction) { device = ActionSet.USE_GRAFFITI_WIDGET; } else if (type == DeviceType.Mouse) { device = ActionSet.USE_MOUSE; } else if (type == DeviceType.Touchscreen) { device = ActionSet.USE_TOUCHSCREEN; } else if (type == DeviceType.Keyboard) { device = ActionSet.USE_KEYBOARD; } else if (type == DeviceType.Voice) { device = ActionSet.USE_VOICE; } else if (type == null) { // Generally, a hover action; pick whichever is active if (actionProps.isMouseSelected()) { device = ActionSet.USE_MOUSE; } else if (actionProps.isTouchSelected()) { device = ActionSet.USE_TOUCHSCREEN; } } actionProps.setComposite(device); ActionProperties properties = view.getActionProperties(); view.getDefaultProperties(properties); properties.updateProperties(transition, transition.getAction(), transition.getSource()); int limitMode = ActionProperties.determineChangeActionMode(transition.getSource()); actionProps.setLimitMode(limitMode, properties.useWhichParts); actionProps.setProperties(properties, properties.useWhichParts); } else if (selectedTransitionCount > 1) { actionProps.useParameters(ActionPropertySet.MULT_TRANS); } if (selectedFrameCount == 1) { actionProps.updateFrameComposite(selection.getSelectedFrames()[0]); } else if ((selectedFrameCount == 0) && (selectedTransitionCount == 0)) { actionProps.updateEmptyComposite(design, false); } } // TODO: same as widgetResizeUnderXY in FrameEditorUI! public ResizeThumb getResizeAtXY(int x, int y) { IFigure f = view.getEditor().getInteractionFigure().findFigureAt(x, y); if (f instanceof ResizeThumb) { return (ResizeThumb) f; } return null; } public ActionType getCurrentActionType() { return view.getActionType(); } public void getDefaultProperties(TransitionSource source, ActionProperties properties) { view.getDefaultProperties(properties); ActionType transitionType = getCurrentActionType(); Set<DeviceType> deviceTypes = uiModel.getDesign().getDeviceTypes(); properties.setInitialActionType(source, transitionType, deviceTypes); } public DoubleRectangle getFrameDisplayBounds(Frame f) { double zoom = structureView.getZoom(); DesignEditorFrame figure = structureView.getFrameFigure(f); Rectangle r = figure.getBounds(); return new DoubleRectangle(r.x * zoom, r.y * zoom, r.width * zoom, r.height * zoom); } }