/******************************************************************************* * 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.view; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; import edu.cmu.cs.hcii.cogtool.CogToolPref; import edu.cmu.cs.hcii.cogtool.model.ACTR6PredictionAlgo; import edu.cmu.cs.hcii.cogtool.model.ACTRPredictionAlgo; import edu.cmu.cs.hcii.cogtool.model.AUndertaking; import edu.cmu.cs.hcii.cogtool.model.Design; import edu.cmu.cs.hcii.cogtool.model.HumanDataAlgo; import edu.cmu.cs.hcii.cogtool.model.IPredictionAlgo; import edu.cmu.cs.hcii.cogtool.model.KLMCognitiveGenerator; import edu.cmu.cs.hcii.cogtool.model.Project; import edu.cmu.cs.hcii.cogtool.model.SNIFACTPredictionAlgo; import edu.cmu.cs.hcii.cogtool.model.Script; import edu.cmu.cs.hcii.cogtool.model.TaskApplication; import edu.cmu.cs.hcii.cogtool.ui.ProjectLID; import edu.cmu.cs.hcii.cogtool.util.L10N; import edu.cmu.cs.hcii.cogtool.util.ListenerIdentifier.ILIDTransmuter; import edu.cmu.cs.hcii.cogtool.util.ListenerIdentifierMap; import edu.cmu.cs.hcii.cogtool.util.MenuUtil; import edu.cmu.cs.hcii.cogtool.util.MenuUtil.CascadingMenuItemDefinition; import edu.cmu.cs.hcii.cogtool.util.MenuUtil.MenuItemDefinition; import edu.cmu.cs.hcii.cogtool.util.MenuUtil.SimpleMenuItemDefinition; /** * This class is responsible for presenting the view of a CogTool Project. * <p> * The view is as an SWT Tree, which is a table whose rows * correspond to Task or TaskGroup instances and whose columns * correspond to Design instances. We use a Tree instead of a Table * to support the presentation of grouping and to allow the user to collapse * groups. Note that the first column contains the names of the Task * and TaskGroup instances. * <p> * The contents of a cell at the intersection of an Design and * Task/TaskGroup represents the Script used to represent how a user * performs the specified task in the specified design; the cell generally * displays the performance statistic(s) associated with that "intersection". * * @author mlh */ public class ProjectView extends View { protected Tree tree; protected Composite bodyComposite; protected StatusBar statusBar; /** * Initialize the view representing the editor for an Project instance. * <p> * Currently, other than inherited shared implementation (that is, * the window itself and the menu bar (@see neededMenus), * the only view piece is the <code>Tree</code>. * * @param listenerIDMap used to map <code>ListenerIdentifier</code> values * to application-specific, semantic code snippets * @param transformer used to convert <code>ListenerIdentifier</code> * instances to more concrete values * @author mlh */ public ProjectView(ListenerIdentifierMap listenerIDMap, ILIDTransmuter transformer, MenuFactory.IWindowMenuData<Project> menuData, Rectangle loc) { // We are responsible for creating the window for this view. super(createShell(loc), listenerIDMap, transformer, menuData); bodyComposite = new Composite(shell, SWT.NONE); bodyComposite.setLayout(new FillLayout()); tree = new Tree(bodyComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER); tree.setLinesVisible(true); statusBar = new StatusBar(shell); // Layout the ProjectView with the status bar below the tree, // with no space in between. shell.setLayout(new FormLayout()); FormData formData = new FormData(); formData.bottom = new FormAttachment(100, 0); formData.left = new FormAttachment(0, 0); formData.right = new FormAttachment(100, 0); statusBar.setLayoutData(formData); formData = new FormData(); formData.top = new FormAttachment(0, 0); formData.bottom = new FormAttachment(statusBar, 0); formData.left = new FormAttachment(0, 0); formData.right = new FormAttachment(100, 0); bodyComposite.setLayoutData(formData); shell.setMinimumSize(480, 138); } // ProjectView /** * Support for creating the view's window. * <p> * This must be a static member function since Java does not * allow us to invoke a non-static member function during * superclass initialization. * * @author mlh */ protected static Shell createShell(Rectangle loc) { GridLayout grid = new GridLayout(1, false); setNoMargins(grid); // TODO: size new windows to tree (and make it work!) // Remember + reuse last window size/location return createShell(loc, 700, 400, grid); } /** * Helper function to indicate that no margins are needed for * displaying the <code>Tree</code> for the Project. * * @param grid for indicating that no margins are needed * @author centgraf */ protected static void setNoMargins(GridLayout grid) { grid.marginHeight = 0; grid.marginTop = 0; grid.marginBottom = 0; grid.marginWidth = 0; grid.marginRight = 0; grid.marginLeft = 0; } /** * This method provides the top-level pull-downs that this View * requires in the main menu bar. * <p> * Different platforms (specifically, Windows vs. Macintosh) * have different conventions for presenting the choices for the * main menu bar when the application has multiple, different windows. * Windows tends to present only those needed by the specific window * while Macintosh presents the union of all choices and simply disables * the choices that are unavailable in the currently active window. * <p> * A Project view requires only the File, Edit, Project, and Help * menus. * * @returns the sequence of top-level pull-downs needed by this View * @author mlh */ @Override protected MenuFactory.MenuType[] neededMenus() { return new MenuFactory.MenuType[] { MenuFactory.MenuType.FileMenu, MenuFactory.MenuType.EditMenu, MenuFactory.MenuType.CreateMenu, MenuFactory.MenuType.ProjectModifyMenu, MenuFactory.MenuType.WindowMenu, MenuFactory.MenuType.HelpMenu }; } /** * Fetch the Tree being used to present the Project's tasks and designs. * * @author mlh/centgraf */ public Tree getTree() { return tree; } // Context menu definitions public static final SimpleMenuItemDefinition EDIT_DESIGN = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditDesign", "Edit Design"), ProjectLID.EditDesign, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition RENAME_DESIGN = new SimpleMenuItemDefinition(L10N.get("MI.PM.RenameDesign", "Rename Design"), ProjectLID.RenameDesign, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition DUPLICATE_DESIGN = new SimpleMenuItemDefinition(L10N.get("MI.PM.DuplicateDesign", "Duplicate Design"), ProjectLID.DuplicateDesign, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EDIT_TASK = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditTask", "Edit Task"), ProjectLID.EditTask, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition RENAME_TASK = new SimpleMenuItemDefinition(L10N.get("MI.PM.RenameTask", "Rename Task"), ProjectLID.InitiateTaskRename, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition DUPLICATE_TASK = new SimpleMenuItemDefinition(L10N.get("MI.PM.DuplicateTask", "Duplicate Task"), ProjectLID.DuplicateTask, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EDIT_TASK_GROUP = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditTaskGroup", "Edit Task Group"), ProjectLID.EditTask, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition RENAME_TASK_GROUP = new SimpleMenuItemDefinition(L10N.get("MI.PM.RenameTaskGroup", "Rename Task Group"), ProjectLID.InitiateTaskRename, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition DUPLICATE_TASK_GROUP = new SimpleMenuItemDefinition(L10N.get("MI.PM.DuplicateTaskGroup", "Duplicate Task Group"), ProjectLID.DuplicateTask, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EDIT_SCRIPT = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditScript", "Edit Script"), ProjectLID.EditScript, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition RECOMPUTE_SCRIPT = new SimpleMenuItemDefinition(L10N.get("MI.PM.RecomputeScript", "Recompute Script"), ProjectLID.RecomputeScript, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition RECOMPUTE_SCRIPTS = new SimpleMenuItemDefinition(L10N.get("MI.PM.RecomputeScripts", "Recompute All Scripts"), ProjectLID.RecomputeScript, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition GENERATE_DICT_ENTRIES = new SimpleMenuItemDefinition(L10N.get("MI.PM.GenerateEntries", "Generate Dictionary Entries..."), ProjectLID.GenerateDictionary, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EDIT_DICT = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditDict", "Edit Dictionary"), ProjectLID.EditDictionary, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition SHOW_SUM = new SimpleMenuItemDefinition(L10N.get("MI.PM.ShowSum", "Show Sum"), ProjectLID.ShowSum, SWT.NONE, SWT.RADIO, MenuUtil.DISABLED, true); public static final SimpleMenuItemDefinition SHOW_MEAN = new SimpleMenuItemDefinition(L10N.get("MI.PM.ShowMean", "Show Mean"), ProjectLID.ShowMean, SWT.NONE, SWT.RADIO, MenuUtil.DISABLED, false); public static final SimpleMenuItemDefinition SHOW_MIN = new SimpleMenuItemDefinition(L10N.get("MI.PM.ShowMin", "Show Minimum"), ProjectLID.ShowMin, SWT.NONE, SWT.RADIO, MenuUtil.DISABLED, false); public static final SimpleMenuItemDefinition SHOW_MAX = new SimpleMenuItemDefinition(L10N.get("MI.PM.ShowMax", "Show Maximum"), ProjectLID.ShowMax, SWT.NONE, SWT.RADIO, MenuUtil.DISABLED, false); public static final SimpleMenuItemDefinition DISPLAY_TRACELINES = new SimpleMenuItemDefinition(L10N.get("MI.PM.DisplayTraceLines", "Display Trace"), ProjectLID.DisplayTraces, MenuUtil.DISABLED); public static final SimpleMenuItemDefinition EXPORT_TRACELINES = new SimpleMenuItemDefinition(L10N.get("MI.PM.ExportTraceLines", "Export Result Trace"), ProjectLID.ExportTraces, MenuUtil.DISABLED); public static final SimpleMenuItemDefinition EXPORT_ACTR_MODEL = new SimpleMenuItemDefinition(L10N.get("MI.PM.ExportActrModelFile", "Export ACT-R Model"), ProjectLID.ExportActrModelFile, MenuUtil.DISABLED); public static final SimpleMenuItemDefinition EXPORT_FOR_SANLAB = new SimpleMenuItemDefinition(L10N.get("MI.PM.ExportForSanlab", "Export to SANLab-CM"), ProjectLID.ExportForSanlab, MenuUtil.DISABLED); public static final SimpleMenuItemDefinition SHOW_MODEL_VISUALIZATION = new SimpleMenuItemDefinition(L10N.get("MI.PM.ShowModelVisualization", "Show Model Visualization"), ProjectLID.ShowModelVisualization, MenuUtil.DISABLED); public static final SimpleMenuItemDefinition EDIT_HUMAN_CSV = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditHumanCSVFile", "Edit Imported CSV File"), ProjectLID.EditHumanCSVFile, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition IMPORT_HUMAN_CSV = new SimpleMenuItemDefinition(L10N.get("MI.PM.ImportHumanCSVFile", "Import Human Data from CSV..."), ProjectLID.ImportHumanCSVFile, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EXPORT_TO_XML = new SimpleMenuItemDefinition(L10N.get("MI.PM.ExportDesignToXML", "Export Design to XML"), ProjectLID.ExportToXML, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition EDIT_ACTR_MODEL_ITEM = new SimpleMenuItemDefinition(L10N.get("MI.PM.EditACTRModelFile", "Edit ACT-R Model File"), ProjectLID.EditACTRModelFile, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition GENERATE_ACTR_MODEL_ITEM = new SimpleMenuItemDefinition(L10N.get("MI.PM.GenerateACTRModelFile", "Generate ACT-R Model File"), ProjectLID.GenerateACTRModelFile, MenuUtil.ENABLED); // TODO Instead of having knowledge of the available prediction // algorithms hardcoded all over the place, there should be a // constrained process for adding an algorithm by implementing // an interface (or possibly a small set of related inferfaces, // because of package import constraints) // Create algorithm submenu for context menus // BEJohn changed menu item names to speak the CogTool user's language 25mar2011 // set algorithm state to match model // algorithm menu items public static final SimpleMenuItemDefinition ALG_ACTR6_ITEM = new SimpleMenuItemDefinition(L10N.get("MI.PM.Actr6Algorithm", // "ACT-R 6"), // Old computer-centric menu item name "Skilled Performance Time"), // BEJohn replaced it with this name in the CogTool user's language 25mar2011 ProjectLID.SetAlgorithmACTR6, SWT.NONE, SWT.RADIO, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition ALG_SNIFACT_ITEM = new SimpleMenuItemDefinition(L10N.get("MI.PM.SNIFACTAlgorithm", // "SNIF-ACT"), // Old computer-centric menu item name "Novice Exploration"), // BEJohn replaced it with this name in the CogTool user's language 25mar2011 ProjectLID.SetAlgorithmSNIFACT, SWT.NONE, SWT.RADIO, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition ALG_HUMAN_DATA_ITEM = new SimpleMenuItemDefinition(L10N.get("MI.PM.HumanData", ".csv Data"), ProjectLID.SetAlgorithmHuman, SWT.NONE, SWT.RADIO, MenuUtil.ENABLED); // TODO This is a binary choice, it should be a single, toggle-able menu // item, not a hierarchy of two choices. // Execution Style public static final SimpleMenuItemDefinition ALG_IN_BACKGROUND = new SimpleMenuItemDefinition(L10N.get("MI.PM.BackgroundRun", "Show Details While Computing"), ProjectLID.SetBackgroundComputationTrue, SWT.NONE, SWT.RADIO, MenuUtil.ENABLED); public static final SimpleMenuItemDefinition ALG_IN_FOREGROUND = new SimpleMenuItemDefinition(L10N.get("MI.PM.ForegroundRun", "Hide Details While Computing"), ProjectLID.SetBackgroundComputationFalse, SWT.NONE, SWT.RADIO, MenuUtil.ENABLED); static public final MenuItemDefinition[] EXECUTE_ITEMS = new MenuItemDefinition[] { ALG_IN_FOREGROUND, ALG_IN_BACKGROUND }; public static final MenuItemDefinition EXECUTE_CASCADE = new CascadingMenuItemDefinition(L10N.get("MI.PV.Execute", "Computation Details"), EXECUTE_ITEMS); /** * Defines the constants used to access the various contextual menus * We have different contextual menus for different states * eg. one if the user right=clicks in a table intersection * another one if the user right-clicks in blank space, etc. */ static public final int BLANK_SPACE_MENU = 0; static public final int DESIGN_MENU = 1; static public final int RESEARCH_DESIGN_MENU = 2; static public final int HCIPA_DESIGN_MENU = 3; static public final int TASK_BODY_MENU = 4; static public final int RESEARCH_TASK_BODY_MENU = 5; static public final int HCIPA_TASK_BODY_MENU = 6; static public final int GROUP_BODY_MENU = 7; static public final int RESEARCH_GROUP_BODY_MENU = 8; static public final int HCIPA_GROUP_BODY_MENU = 9; static public final int TASK_CELL_ACTR_MENU = 10; static public final int GROUP_CELL_MENU = 11; static public final int RESEARCH_GROUP_CELL_MENU = 12; static public final int HCIPA_GROUP_CELL_MENU = 13; static private final int CONTEXT_MENUS_COUNT = (HCIPA_GROUP_CELL_MENU + 1); /** * Defines the context menu for each specific static context */ static public final MenuItemDefinition[][] CONTEXT_DEFS = new MenuItemDefinition[CONTEXT_MENUS_COUNT][]; static { // Standard menu CONTEXT_DEFS[BLANK_SPACE_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuFactory.NEW_DESIGN }; // Design header CONTEXT_DEFS[DESIGN_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuUtil.SEPARATOR, MenuFactory.EDIT, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_DESIGN, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, }; CONTEXT_DEFS[RESEARCH_DESIGN_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuUtil.SEPARATOR, MenuFactory.EDIT, MenuFactory.RENAME, MenuFactory.EXPORT_DESIGN_TO_HTML, EXPORT_TO_XML, MenuUtil.SEPARATOR, MenuFactory.NEW_DESIGN, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES, EDIT_DICT }; CONTEXT_DEFS[HCIPA_DESIGN_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuUtil.SEPARATOR, MenuFactory.EDIT, MenuFactory.RENAME, MenuFactory.EXPORT_DESIGN_TO_HTML, EXPORT_TO_XML, MenuFactory.EXPORT_TO_HCIPA, MenuUtil.SEPARATOR, MenuFactory.NEW_DESIGN, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES, EDIT_DICT }; // Task body (that is, the label on the left) CONTEXT_DEFS[TASK_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS }; // Task body (that is, the label on the left) CONTEXT_DEFS[RESEARCH_TASK_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES }; // Task body (that is, the label on the left) CONTEXT_DEFS[HCIPA_TASK_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES }; // Task cell (that is, the intersection with the design) CONTEXT_DEFS[TASK_CELL_ACTR_MENU] = new MenuItemDefinition[] { SHOW_MODEL_VISUALIZATION, MenuUtil.SEPARATOR, EDIT_SCRIPT, RECOMPUTE_SCRIPT, MenuUtil.SEPARATOR, EDIT_DESIGN, RENAME_DESIGN, DUPLICATE_DESIGN, MenuUtil.SEPARATOR, DISPLAY_TRACELINES }; // Group body (that is, the label on the left) CONTEXT_DEFS[GROUP_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX }; // Group body (that is, the label on the left) CONTEXT_DEFS[RESEARCH_GROUP_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES }; // Group body (that is, the label on the left) CONTEXT_DEFS[HCIPA_GROUP_BODY_MENU] = new MenuItemDefinition[] { MenuFactory.CUT, MenuFactory.COPY, MenuFactory.PASTE, MenuFactory.DELETE, MenuFactory.DUPLICATE, MenuFactory.SELECT_ALL, MenuUtil.SEPARATOR, MenuFactory.RENAME, MenuUtil.SEPARATOR, MenuFactory.NEW_TASK, MenuFactory.NEW_TASK_GROUP, MenuUtil.SEPARATOR, RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX, MenuUtil.SEPARATOR, MenuFactory.EXPORT_TO_HCIPA, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES }; // Group cell (that is, the intersection with the design) CONTEXT_DEFS[GROUP_CELL_MENU] = new MenuItemDefinition[] { RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, EDIT_DESIGN, RENAME_DESIGN, DUPLICATE_DESIGN, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX }; CONTEXT_DEFS[RESEARCH_GROUP_CELL_MENU] = new MenuItemDefinition[] { RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, EDIT_DESIGN, RENAME_DESIGN, DUPLICATE_DESIGN, MenuFactory.EXPORT_DESIGN_TO_HTML, EXPORT_TO_XML, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES, EDIT_DICT }; CONTEXT_DEFS[HCIPA_GROUP_CELL_MENU] = new MenuItemDefinition[] { RECOMPUTE_SCRIPTS, MenuUtil.SEPARATOR, EDIT_DESIGN, RENAME_DESIGN, DUPLICATE_DESIGN, MenuFactory.EXPORT_DESIGN_TO_HTML, EXPORT_TO_XML, MenuFactory.EXPORT_TO_HCIPA, MenuUtil.SEPARATOR, SHOW_SUM, SHOW_MEAN, SHOW_MIN, SHOW_MAX, MenuUtil.SEPARATOR, GENERATE_DICT_ENTRIES, EDIT_DICT }; } // Status display methods @Override public void setStatusMessage(String message) { statusBar.setStatusMessage(message); } @Override public void setStatusMessage(String message, int duration) { statusBar.setStatusMessage(message, duration); } // Methods that define the current context for the contextual menus public void showContextMenuForBlankSpace() { contextMenus.setContextSelection(View.SELECTION); contextMenus.getMenu(BLANK_SPACE_MENU).setVisible(true); } public void showContextMenuForDesign(boolean context) { int menu = CogToolPref.RESEARCH.getBoolean() ? (CogToolPref.HCIPA.getBoolean() ? HCIPA_DESIGN_MENU : RESEARCH_DESIGN_MENU) : DESIGN_MENU; contextMenus.setContextSelection(context); contextMenus.getMenu(menu).setVisible(true); } public Menu getContextMenuForIntersection(Project project, AUndertaking undertaking, Design design) { // Get the task application being clicked on TaskApplication ta = project.getTaskApplication(undertaking, design); boolean hasExternalFile = false; boolean isVisualizable = false; Set<IPredictionAlgo> algsWithResults = new HashSet<IPredictionAlgo>(); IPredictionAlgo algo = null; if (ta != null) { // TODO: mlh make access to model gen algo generic Script script = ta.getScript(KLMCognitiveGenerator.ONLY); if (script != null) { if (script.getAssociatedPath() != null) { hasExternalFile = true; } // as well as the list of algorithms with results in the ta Iterator<IPredictionAlgo> algsIt = ta.getPredictionAlgs(script.getModelGenerator()); while (algsIt.hasNext()) { IPredictionAlgo i = algsIt.next(); if (i != null) { algsWithResults.add(i); } } } // And whether or not ta has a visualizable result isVisualizable = ta.hasResultSteps(ta.determineActiveAlgorithm(project)); algo = ta.getActiveAlgorithm(); } // TODO now that we no longer have the notion of a user-settable // "default algorithm" it would be best to go back and ensure // that null is never used as the algorithm. Until we've done // that the following test will have to suffice. if (algo == null) { algo = ACTR6PredictionAlgo.ONLY; } contextMenus.setContextSelection(View.CONTEXT); if (undertaking.isTaskGroup()) { if (CogToolPref.HCIPA.getBoolean()) { return contextMenus.getMenu(HCIPA_GROUP_CELL_MENU); } if (CogToolPref.RESEARCH.getBoolean()) { return contextMenus.getMenu(RESEARCH_GROUP_CELL_MENU); } return contextMenus.getMenu(GROUP_CELL_MENU); } // create cascading menus for algorithm (now called "Usability Metric" BEJoh 25mar2011) MenuItemDefinition algCascade = null; if (CogToolPref.RESEARCH.getBoolean()) { List<MenuItemDefinition> algList = new ArrayList<MenuItemDefinition>(); algList.add(ALG_ACTR6_ITEM); algList.add(ALG_SNIFACT_ITEM); if (algsWithResults.contains(HumanDataAlgo.ONLY)) { algList.add(ALG_HUMAN_DATA_ITEM); } algCascade = new CascadingMenuItemDefinition(L10N.get("MI.PV.AlgorithmType", // "Algorithm Type"), "Usability Metric"), algList.toArray(new MenuItemDefinition[algList.size()])); // test for active algorithm // TODO Do we really want to use this idiom? It seems nauseating on // at least three counts: // 1) setting a field of a constant is confusing--no one // looking at these constants elsewhere is going to be // expecting them to mutate out from under them // 2) while it does seem unlikely re-entrancy will in practice // be an issue here, using application-wide globals as a way // of passing essentially local information is suspect // 3) it's a dangerously fragile idiom--for any of these // fields you ever fiddle, you really, truly HAVE to set them to // either true or false every time--can't count on any defaults, // or you'll be using stale data from the previous time around ALG_ACTR6_ITEM.selectedInitially = (algo == ACTR6PredictionAlgo.ONLY); ALG_HUMAN_DATA_ITEM.selectedInitially = (algo == HumanDataAlgo.ONLY); ALG_SNIFACT_ITEM.selectedInitially = (algo == SNIFACTPredictionAlgo.ONLY); // TODO speaking of "it's a dangerously fragile idiom," the following // code wasn't originally correct, as nothing ever got // deselected, demonstrating my point #3, above! // [while this is now fixed, I believe, I'm leaving a TODO here // as a sort of continuation of the one above to which it refers] // test for background run Boolean computeInBkg = null; if (ta != null) { computeInBkg = ta.getComputeInBackground(); } // TODO Since we've elimintated the never-completely-implemented // notion of a user settable default for this, we should go // and ensure getComputeInBackground() can never be null; until // we do the following test will have to suffice. if (computeInBkg == null) { computeInBkg = TaskApplication.RUN_IN_FOREGROUND; } ALG_IN_BACKGROUND.selectedInitially = (computeInBkg == TaskApplication.RUN_IN_BACKGROUND); ALG_IN_FOREGROUND.selectedInitially = (computeInBkg == TaskApplication.RUN_IN_FOREGROUND); } // build custom menu List<MenuItemDefinition> taskCellContextMenuDef = new ArrayList<MenuItemDefinition>(); SHOW_MODEL_VISUALIZATION.enabledInitially = isVisualizable; taskCellContextMenuDef.add(SHOW_MODEL_VISUALIZATION); taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(EDIT_SCRIPT); IPredictionAlgo a = (algo != null ? algo : project.getDefaultAlgo()); if (a instanceof ACTRPredictionAlgo || a instanceof SNIFACTPredictionAlgo) { if (CogToolPref.RESEARCH.getBoolean()) { // TODO it is disgusting the way this stuff is all cloned; when // we have time we need to think through a consistent design // to be shared across all backends EDIT_ACTR_MODEL_ITEM.enabledInitially = hasExternalFile; GENERATE_ACTR_MODEL_ITEM.enabledInitially = (ta != null); taskCellContextMenuDef.add(EDIT_ACTR_MODEL_ITEM); taskCellContextMenuDef.add(GENERATE_ACTR_MODEL_ITEM); } taskCellContextMenuDef.add(MenuUtil.SEPARATOR); } taskCellContextMenuDef.add(RECOMPUTE_SCRIPT); if (algCascade != null) { taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(algCascade); taskCellContextMenuDef.add(EXECUTE_CASCADE); } taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(EDIT_DESIGN); taskCellContextMenuDef.add(RENAME_DESIGN); taskCellContextMenuDef.add(DUPLICATE_DESIGN); taskCellContextMenuDef.add(MenuUtil.SEPARATOR); if (CogToolPref.RESEARCH.getBoolean()) { taskCellContextMenuDef.add(IMPORT_HUMAN_CSV); taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(MenuFactory.EXPORT_DESIGN_TO_HTML); } taskCellContextMenuDef.add(MenuFactory.EXPORT_SCRIPT_TO_CSV); taskCellContextMenuDef.add(MenuFactory.EXPORT_RESULTS_TO_CSV); if (CogToolPref.RESEARCH.getBoolean()) { taskCellContextMenuDef.add(EXPORT_TO_XML); taskCellContextMenuDef.add(EXPORT_ACTR_MODEL); taskCellContextMenuDef.add(EXPORT_TRACELINES); taskCellContextMenuDef.add(EXPORT_FOR_SANLAB); if (CogToolPref.HCIPA.getBoolean()) { taskCellContextMenuDef.add(MenuFactory.EXPORT_TO_HCIPA); } taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(DISPLAY_TRACELINES); } if (CogToolPref.RESEARCH.getBoolean()) { taskCellContextMenuDef.add(MenuUtil.SEPARATOR); taskCellContextMenuDef.add(GENERATE_DICT_ENTRIES); taskCellContextMenuDef.add(EDIT_DICT); } return contextMenus.createDynamicMenu(taskCellContextMenuDef); } // getContextMenuForIntersection public void showContextMenuForUndertaking(boolean isTaskGroup, boolean context) { int menu; if (isTaskGroup) { menu = CogToolPref.RESEARCH.getBoolean() ? (CogToolPref.HCIPA.getBoolean() ? HCIPA_GROUP_BODY_MENU : RESEARCH_GROUP_BODY_MENU) : GROUP_BODY_MENU; } else { menu = CogToolPref.RESEARCH.getBoolean() ? (CogToolPref.HCIPA.getBoolean() ? HCIPA_TASK_BODY_MENU : RESEARCH_TASK_BODY_MENU) : TASK_BODY_MENU; } contextMenus.setContextSelection(context); contextMenus.getMenu(menu).setVisible(true); } // Override to pass our set of context menus to the manager @Override public MenuItemDefinition[][] getContextMenuDefinitions() { return CONTEXT_DEFS; } }