/******************************************************************************* * 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 org.eclipse.swt.SWT; import org.eclipse.swt.widgets.DirectoryDialog; import edu.cmu.cs.hcii.cogtool.model.AAction; import edu.cmu.cs.hcii.cogtool.model.Frame; import edu.cmu.cs.hcii.cogtool.model.Transition; import edu.cmu.cs.hcii.cogtool.model.TransitionSource; import edu.cmu.cs.hcii.cogtool.util.IEllipsizer; import edu.cmu.cs.hcii.cogtool.util.KeyDisplayUtil; import edu.cmu.cs.hcii.cogtool.util.L10N; import edu.cmu.cs.hcii.cogtool.util.SWTStringUtil; import edu.cmu.cs.hcii.cogtool.util.StringUtil; import edu.cmu.cs.hcii.cogtool.util.WindowUtil; import edu.cmu.cs.hcii.cogtool.view.DesignEditorView; public class DesignEditorInteraction extends DefaultInteraction implements ActionInteraction { protected static final String needSelectionMsg = L10N.get("DE.NeedSelection", "You must select a frame or transition."); protected static final String needSingleFrameSelectionMsg = L10N.get("DE.NeedSingleFrameSelection", "You must select a single frame for renaming."); protected static final String cannotEditMultipleTransitions = L10N.get("DE.CannotEditMultipleTransitions", "We cannot edit multiple transitions at the same time."); protected static final String confirmDeleteFramesMsg = L10N.get("DE.ConfirmDeleteFrames", "Please confirm the deletion of the following Frame(s):"); protected static final String confirmDeleteTransitionsMsg = L10N.get("DE.ConfirmDeleteTransitions", "Please confirm the deletion of the selected Transition(s)."); protected static final String confirmTitle = L10N.get("DE.ConfirmTitle", "Confirm Deletion"); protected static final String dErrorTitle = L10N.get("DE.ErrorTitle", "Design Editor Error"); protected static final String frameNotUniqueMsg = L10N.get("DE.NotUniqueFrameName", "Frame names must be unique.\nWould you like to try again?"); protected static final String frameEmptyNameMsg = L10N.get("DE.EmptyFrameName", "Frame names must not be empty.\nWould you like to try again?"); protected static final String inconsistentSourceMsg = L10N.get("DE.InconsistentSource", "One cannot change a transition's source to an incompatible widget type."); protected static final String askForVoice = L10N.get("DE.AskForVoice", "Voice Command:"); protected static final String askForKeys = L10N.get("DE.AskForKeys", "Key Sequence:"); protected static final String askForGraffiti = L10N.get("DE.AskForGraffiti", "Graffiti\u00AE Gestures:"); protected static final String nonuniqueActionMsg = L10N.get("DE.NonuniqueAction", "Cannot have two transitions using this action from this source: "); protected static final String unacceptableActionMsg = L10N.get("DE.UnacceptableAction", "Unacceptable action for this source: "); /** * Initialize interaction with the given window that pop-up dialog * boxes are modal to. * * @param v target window for dialog box modality * @author mlh */ public DesignEditorInteraction(DesignEditorView v) { super(v); } /** * Present the opportunity to (re-)specify the action for a transition. * If requested, complain that the action last specified isn't unique for * the associated transition's source. * * @param transition from which to get the initial values for the dialog box * @param properties to hold the initial values for the dialog box elements * @param useWhichParts which "device" option to present at first * @param deviceTypes bitset of devices for this dialog box * @param limitMode how to limit which "device" options are available; * use ActionProperties.UNSET to use current action's * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean determineNewAction(Transition transition, ActionProperties properties, int useWhichParts, int deviceTypes, int limitMode, String title) { ((DesignEditorView) view).getDefaultProperties(properties); properties.updateProperties(transition, transition.getAction(), transition.getSource()); if (useWhichParts != ActionProperties.UNSET) { properties.useWhichParts = useWhichParts; } return determineNewAction(properties, deviceTypes, limitMode, title); } /** * Complain that no frame has been selected. * * @author mlh */ public void protestNoSelection() { reportProblem(dErrorTitle, needSelectionMsg); } /** * Complain that too many frames are selected. * * @author mlh */ public void protestMultipleFrameSelection() { reportProblem(dErrorTitle, needSingleFrameSelectionMsg); } /** * Complain that too many transitions are selected. */ public void protestMultipleTransitionSelection() { reportProblem(dErrorTitle, cannotEditMultipleTransitions); } /** * Ask the user to confirm that the given frames may be deleted. * * @param frames the frames that will be deleted * @return true if the user indicated that the operation should proceed; * false indicates a desire to cancel the operation * @author mlh */ public boolean confirmDeleteFrames(Frame[] frames) { return (SWT.OK == WindowUtil.presentConfirmItemsDialog(window, confirmTitle, confirmDeleteFramesMsg, frames)); } /** * Ask the user to confirm that the given transitions may be deleted. * * @param frames the transitions that will be deleted * @return true if the user indicated that the operation should proceed; * false indicates a desire to cancel the operation * @author mlh */ public boolean confirmDeleteTransitions(Transition[] transitions) { String msg = confirmDeleteTransitionsMsg; return (SWT.OK == WindowUtil.presentConfirmDialog(window, confirmTitle, msg)); } /** * Complain that the specified frame is not unique; * allow the user to retry. * * @return true if and only if the user wishes to retry; false * indicates a desire to cancel * @author mlh */ public boolean protestNotUniqueFrameName() { return reportAndRetry(dErrorTitle, frameNotUniqueMsg); } /** * Complain that the frame name is empty; allow the user to retry. * * @return true if and only if the user wishes to retry; false * indicates a desire to cancel * @author mlh */ public boolean protestEmptyFrameName() { return reportAndRetry(dErrorTitle, frameEmptyNameMsg); } /** * Complain that the reassignment of a transition's source has chosen * a source that does not accept the action associated with the transition. * * @author mlh */ public void protestInconsistentSource() { reportProblem(dErrorTitle, inconsistentSourceMsg); } protected boolean protestEmptyText(ActionProperties properties, int deviceTypes, int limitMode, String specificComplaint) { NewActionChangeDialog newAction = new NewActionChangeDialog(window, deviceTypes, L10N.get("DE.ChangeActionType", "Change Action Type")); newAction.setProperties(properties, limitMode, specificComplaint); Object response = newAction.open(); return (response != null) && response.equals(WindowUtil.PromptDialog.OK); } /** * Complain that the given voice command is empty; interact with the * user to get a non-empty string, which will be stored in the given * ActionProperties. * * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean protestEmptyVoice(ActionProperties properties, int deviceTypes, int limitMode) { return protestEmptyText(properties, deviceTypes, limitMode, EMPTY_VOICE_MSG); } /** * Complain that the given keyboard string is empty; interact with the * user to get a non-empty string, which will be stored in the given * ActionProperties. * * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean protestEmptyKeys(ActionProperties properties, int deviceTypes, int limitMode) { return protestEmptyText(properties, deviceTypes, limitMode, EMPTY_KEYS_MSG); } /** * Complain that the given graffiti string is empty; interact with the * user to get a non-empty string, which will be stored in the given * ActionProperties. * * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean protestEmptyGraffiti(ActionProperties properties, int deviceTypes, int limitMode) { return protestEmptyText(properties, deviceTypes, limitMode, EMPTY_GRAFFITI_MSG); } /** * Utility to pop a dialog box that prompts for a string and allows the * user to cancel * * @param dialog the box to pop * @return the string specified by the user or <code>null</code> * if the user chose to cancel the operation */ protected String promptForStringOrCancel(WindowUtil.PromptDialog dialog) { // Pop the dialog Object result = dialog.open(); // Check for positive response; if ok, return the user's response if ((result != null) && result.equals(WindowUtil.PromptDialog.OK)) { return dialog.getPromptResponse(); } // If the user canceled then return an indication of the cancel return null; } /** * Complain that the given action is not unique for the specified * transition source (a transition source may have only one transition * from it for each action); allow the user to retry if specified. * * @param action the action that is not unique for the given source * @param source the transition source that already has a transition * using the given action * @param allowRetry whether to allow the user to retry the operation; * if false, simply report the error * @return true if and only if the user wishes to retry; false * indicates a desire to cancel (thus, if allowRetry is false, * false is returned) * @author mlh */ public boolean protestNotUniqueAction(AAction action, TransitionSource source, boolean allowRetry) { String actionStr = KeyDisplayUtil.convertActionToMenuText(action.getLocalizedString()); if (allowRetry) { return reportAndRetry(dErrorTitle, nonuniqueActionMsg + actionStr + " on " + source.getName()); } reportProblem(dErrorTitle, nonuniqueActionMsg + actionStr + " on " + source.getName()); return false; } /** * Complain that the given action is not appropriate for the specified * transition source. Transition sources may restrict the actions * that a end-user may perform. * * @param action the action that is not appropriate for the given source * @param source the transition source that does not accept the action * @author mlh */ public void protestUnacceptableAction(AAction action, TransitionSource source) { String actionStr = KeyDisplayUtil.convertActionToMenuText(action.getLocalizedString()); reportProblem(dErrorTitle, unacceptableActionMsg + actionStr + " on " + source.getName()); } /** * Present the opportunity to (re-)specify the action for a transition. * * @param props the initial values for the dialog box elements * @param deviceTypes bitset of devices for this dialog box * @param limitMode how to limit which "device" options are available * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean determineNewAction(ActionProperties props, int deviceTypes, int limitMode, String title) { return determineNewAction(props, deviceTypes, limitMode, null, null, null, title); } /** * Present the opportunity to (re-)specify the action for a transition. * If requested, complain that the action last specified isn't unique for * the associated transition's source. * * @param props the initial values for the dialog box elements * @param deviceTypes bitset of devices for this dialog box * @param limitMode how to limit which "device" options are available * @param action the action that is nonunique; if not null, complain that a * conflict exists * @param source the transition source that already has a transition * for the conflicting action * @param actionTransition the existing transition from the given source * whose action is being modified; if creating * a new transition, use <code>null</code> * @return true if and only if the the user specified a new action; * false if the user indicates a desire to cancel the operation * @author mlh */ public boolean determineNewAction(ActionProperties props, int deviceTypes, int limitMode, AAction action, TransitionSource source, Transition actionTransition, String title) { NewActionChangeDialog newAction = new NewActionChangeDialog(window, deviceTypes, title); newAction.setProperties(props, limitMode, action, source, actionTransition); Object response = newAction.open(); return (response != null) && response.equals(WindowUtil.PromptDialog.OK); } public String askForImageDir() { DirectoryDialog dialog = new DirectoryDialog(window); dialog.setText(L10N.get("DE.SelectImages", "Select a directory of images")); // XXX: Is there a way to get the following formatted decently? To // see the end of the message you have to make the dialog bigger. // Note that embedded linefeeds do *not* work: the second line // gets truncated to just its top couple of pixels. dialog.setMessage(L10N.get("DE.DirectoryOfImages", "Select a directory with a set of images (.JPG, .PNG or .GIF) to import.")); return dialog.open(); } public void setTransitionStatusMessage(Transition newTransition) { // IEllipsizer ellipsizer = // new SWTStringUtil.SWTEllipsizer(150, // StringUtil.NO_FRONT, // SWTStringUtil.DEFAULT_FONT); // // setStatusMessage(newTransition.toString(true, ellipsizer)); setStatusMessage(""); } }