/*******************************************************************************
* 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.controller;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import edu.cmu.cs.hcii.cogtool.CogTool;
import edu.cmu.cs.hcii.cogtool.CogToolClipboard;
import edu.cmu.cs.hcii.cogtool.CogToolFileTypes;
import edu.cmu.cs.hcii.cogtool.CogToolLID;
import edu.cmu.cs.hcii.cogtool.CogToolPref;
import edu.cmu.cs.hcii.cogtool.FrameTemplateSupport;
import edu.cmu.cs.hcii.cogtool.ResultDisplayPolicy;
import edu.cmu.cs.hcii.cogtool.model.ACTR6PredictionAlgo;
import edu.cmu.cs.hcii.cogtool.model.ACTRPredictionAlgo;
import edu.cmu.cs.hcii.cogtool.model.APredictionResult;
import edu.cmu.cs.hcii.cogtool.model.AUndertaking;
import edu.cmu.cs.hcii.cogtool.model.CognitiveModelGenerator;
import edu.cmu.cs.hcii.cogtool.model.Demonstration;
import edu.cmu.cs.hcii.cogtool.model.Design;
import edu.cmu.cs.hcii.cogtool.model.DeviceType;
import edu.cmu.cs.hcii.cogtool.model.DoublePoint;
import edu.cmu.cs.hcii.cogtool.model.DoubleRectangle;
import edu.cmu.cs.hcii.cogtool.model.ExportCogToolXML;
import edu.cmu.cs.hcii.cogtool.model.Frame;
import edu.cmu.cs.hcii.cogtool.model.GroupNature;
import edu.cmu.cs.hcii.cogtool.model.HumanCSVParser;
import edu.cmu.cs.hcii.cogtool.model.HumanDataAlgo;
import edu.cmu.cs.hcii.cogtool.model.IPredictionAlgo;
import edu.cmu.cs.hcii.cogtool.model.ISimilarityDictionary;
import edu.cmu.cs.hcii.cogtool.model.ITermSimilarity;
import edu.cmu.cs.hcii.cogtool.model.IdentityModelGenerator;
import edu.cmu.cs.hcii.cogtool.model.ImportCogToolXML;
import edu.cmu.cs.hcii.cogtool.model.ImportConverter;
import edu.cmu.cs.hcii.cogtool.model.KLMCognitiveGenerator;
import edu.cmu.cs.hcii.cogtool.model.PredictionResultProxy;
import edu.cmu.cs.hcii.cogtool.model.Project;
import edu.cmu.cs.hcii.cogtool.model.Project.ITaskDesign;
import edu.cmu.cs.hcii.cogtool.model.ResultStep;
import edu.cmu.cs.hcii.cogtool.model.SNIFACTExecContext;
import edu.cmu.cs.hcii.cogtool.model.SNIFACTPredictionAlgo;
import edu.cmu.cs.hcii.cogtool.model.SNIFACTPredictionAlgo.SNIFACTGroupParameters;
import edu.cmu.cs.hcii.cogtool.model.SNIFACTPredictionAlgo.SNIFACTParameters;
import edu.cmu.cs.hcii.cogtool.model.Script;
import edu.cmu.cs.hcii.cogtool.model.SimilarityDictionary;
import edu.cmu.cs.hcii.cogtool.model.Task;
import edu.cmu.cs.hcii.cogtool.model.TaskApplication;
import edu.cmu.cs.hcii.cogtool.model.TaskGroup;
import edu.cmu.cs.hcii.cogtool.model.TaskParent;
import edu.cmu.cs.hcii.cogtool.model.TimePredictionResult;
import edu.cmu.cs.hcii.cogtool.model.TraceParser;
import edu.cmu.cs.hcii.cogtool.model.URLCrawlEntry;
import edu.cmu.cs.hcii.cogtool.model.WidgetAttributes;
import edu.cmu.cs.hcii.cogtool.ui.DesignSelectionState;
import edu.cmu.cs.hcii.cogtool.ui.Interaction.ITraceWindow;
import edu.cmu.cs.hcii.cogtool.ui.ProjectContextSelectionState;
import edu.cmu.cs.hcii.cogtool.ui.ProjectInteraction;
import edu.cmu.cs.hcii.cogtool.ui.ProjectLID;
import edu.cmu.cs.hcii.cogtool.ui.ProjectSelectionState;
import edu.cmu.cs.hcii.cogtool.ui.ProjectUI;
import edu.cmu.cs.hcii.cogtool.ui.SNIFACTDialog;
import edu.cmu.cs.hcii.cogtool.ui.SelectionState;
import edu.cmu.cs.hcii.cogtool.ui.TaskSelectionState;
import edu.cmu.cs.hcii.cogtool.ui.UI;
import edu.cmu.cs.hcii.cogtool.util.AListenerAction;
import edu.cmu.cs.hcii.cogtool.util.AUndoableEdit;
import edu.cmu.cs.hcii.cogtool.util.CSVSupport;
import edu.cmu.cs.hcii.cogtool.util.ClipboardUtil;
import edu.cmu.cs.hcii.cogtool.util.CompoundUndoableEdit;
import edu.cmu.cs.hcii.cogtool.util.FileUtil;
import edu.cmu.cs.hcii.cogtool.util.GraphicsUtil;
import edu.cmu.cs.hcii.cogtool.util.IListenerAction;
import edu.cmu.cs.hcii.cogtool.util.IUndoableEdit;
import edu.cmu.cs.hcii.cogtool.util.IUndoableEditSequence;
import edu.cmu.cs.hcii.cogtool.util.L10N;
import edu.cmu.cs.hcii.cogtool.util.NamedObjectUtil;
import edu.cmu.cs.hcii.cogtool.util.NullSafe;
import edu.cmu.cs.hcii.cogtool.util.OSUtils;
import edu.cmu.cs.hcii.cogtool.util.ObjectLoader;
import edu.cmu.cs.hcii.cogtool.util.ObjectSaver;
import edu.cmu.cs.hcii.cogtool.util.RcvrCannotUndoRedoException;
import edu.cmu.cs.hcii.cogtool.util.RcvrClipboardException;
import edu.cmu.cs.hcii.cogtool.util.RcvrIOException;
import edu.cmu.cs.hcii.cogtool.util.RcvrIOSaveException;
import edu.cmu.cs.hcii.cogtool.util.RcvrIOTempException;
import edu.cmu.cs.hcii.cogtool.util.RcvrIllegalStateException;
import edu.cmu.cs.hcii.cogtool.util.RcvrImageException;
import edu.cmu.cs.hcii.cogtool.util.RcvrImportException;
import edu.cmu.cs.hcii.cogtool.util.RcvrOutOfMemoryException;
import edu.cmu.cs.hcii.cogtool.util.RcvrParsingException;
import edu.cmu.cs.hcii.cogtool.util.RcvrUnimplementedFnException;
import edu.cmu.cs.hcii.cogtool.util.RcvrXMLParsingException;
import edu.cmu.cs.hcii.cogtool.util.RecoverableException;
import edu.cmu.cs.hcii.cogtool.util.ThreadManager;
import edu.cmu.cs.hcii.cogtool.util.UndoManager;
/**
* The Controller for semantic actions specific to the Project editor window.
* <p>
* Semantic actions and parameters:
* Undo <no parameters>
* Redo <no parameters>
* SelectAll <no parameters> (selects all tasks)
* DeselectAll ISelectionState (objects to be deselected)
*
* Paste AProjectSelectionState (controls where to paste)
* CopyDesign IDesignSelectionState (what to copy)
* CutDesign IDesignSelectionState (what to cut)
* CopyTask ITaskSelectionState (what to copy)
* CutTask ITaskSelectionState (what to cut)
*
* NewDesign IDesignSelectionState (controls where to place)
* EditDesign IDesignSelectionState (what to edit)
* RenameDesign IDesignSelectionState (what to rename)
* DeleteDesign IDesignSelectionState (what to delete)
* DuplicateDesign IDesignSelectionState (what to duplicate)
* ReorderDesigns Design[] (new design order)
*
* NewTask ITaskSelectionState (controls where to place)
* NewTaskGroup ITaskSelectionState (controls where to place)
* EditTask ITaskSelectionState (what to edit/rename)
* InitiateTaskRename ITaskSelectionState (what to rename)
* RenameTask ProjectUI.TaskRenameEvent (what/how to rename)
* DeleteTask ITaskSelectionState (what to delete)
* DuplicateTask ITaskSelectionState (what to duplicate)
* MoveTask* ITaskSelectionState (what to move)
* {Pro,De)moteTask ITaskSelectionState (what to promote/demote)
* ChangeTaskPosition ProjectUI.ChangeTaskPositionParms (what to move/where)
* DuplicateTaskFull ProjectUI.ChangeTaskPositionParms (what to dup/where)
*
* EditScript AProjectSelectionState (specifies the cell)
* ShowSum ITaskSelectionState (which groups to alter display)
* ShowMean ITaskSelectionState (which groups to alter display)
* ShowMin ITaskSelectionState (which groups to alter display)
* ShowMax ITaskSelectionState (which groups to alter display)
*
* SetProjDefaultAlgo*
* SetProjExec*
*
* ShowModelVisualization AProjectSelectionState (which cells to visualize)
* RecomputeScript AProjectSelectionState (which cells to recompute)
* RegenerateScript AProjectSelectionState (which cells to regenerate)
* DisplayTraces AProjectSelectionState (which cells to display traces)
* ExportTraces AProjectSelectionState (which cells to export)
*
* ExportActrModelFile AProjectSelectionState (which .lisp file to export)
* ImportHumanCSVFile AProjectSelectionState (into which cells to import)
* GenerateACTRModelFile AProjectSelectionState (which cells to generate)
* SelectStrategy AProjectSelectionState (which cells to select strategy)
*
* ImportXML (imports a design or demonstration from an xml file)
* ExportDesignToHTML AProjectSelectionState (which design to export)
* ExportScriptToCSV AProjectSelectionState (which script to export)
* ExportResultsToCSV <no parameters>
* CopyResultsToClipboard <no parameters>
*
* @author mlh
*/
public class ProjectController extends DefaultController
{
// For now, we know only of the standard algorithms
// TODO: why isn't the following final? If it's not supposed to be, it
// probably shouldn't be spelled all caps
protected static CognitiveModelGenerator MODELGEN_ALG =
KLMCognitiveGenerator.ONLY;
protected static ObjectLoader.IObjectLoader<Design> designLoader =
Design.getImportLoader();
protected static ObjectLoader.IObjectLoader<Frame> frameLoader =
Frame.getImportLoader();
protected static final int NUM_SNIF_ACT_TRIALS = 3;
protected static final int SNIF_ACT_K_VALUE = 600;
protected static final String DEFAULT_PROJECT_PREFIX =
L10N.get("PM.NewProjectName", "Untitled Project");
protected static final String DEFAULT_TASK_PREFIX =
L10N.get("PM.NewTaskName", "Task");
protected static final String DEFAULT_TASK_GROUP_PREFIX =
L10N.get("PM.NewTaskGroupName", "Task Group");
// Status messages
protected static final String importXMLPresentation =
L10N.get("UNDO.PC.ImportXML", "Import XML");
protected static final String IMPORT_HUMAN_CSV =
L10N.get("UNDO.PC.ImportHumanCSV", "Import human data");
protected static final String IMPORT_SUCCESS_MSG =
L10N.get("PC.ImportSuccess",
"Data import complete.");
protected static final String IMPORT_FAIL_NOFILE_MSG =
L10N.get("PC.ImportFailureNoFile",
"Data import failed because the file does not exist.");
protected static final String IMPORT_FAIL_NOREAD_MSG =
L10N.get("PC.ImportFailureNoRead",
"Data import failed because the file could not be read.");
protected static final String IMPORT_FAIL_PARSE_IMPL_MSG =
L10N.get("PC.ImportFailureParseImpl",
"Data import failed because the parse implementation failed.");
protected static final String IMPORT_FAIL_PARSE_MSG =
L10N.get("PC.ImportFailureParse",
"Data import failed because the file was not in the correct format.");
protected static final String PASTE = L10N.get("UNDO.Paste", "Paste");
protected static final String NEW_DESIGN =
L10N.get("UNDO.PM.NewDesign", "New Design");
protected static final String tracesWindowLabel =
L10N.get("PC.TracesLabel", "Traces");
protected static final String RENAME_DESIGN =
L10N.get("UNDO.PM.RenameDesign", "Rename Design");
protected static final String DELETE_DESIGN =
L10N.get("UNDO.PM.DeleteDesign", "Delete Design");
protected static final String NEW_TASK =
L10N.get("UNDO.PM.NewTask", "New Task");
protected static final String NEW_TASK_GROUP =
L10N.get("UNDO.PM.NewTaskGroup", "New Task Group");
protected static final String RENAME_TASK =
L10N.get("UNDO.PM.RenameTask", "Rename Task");
protected static final String RENAME_TASK_GROUP =
L10N.get("UNDO.PM.RenameTaskGroup", "Rename Task Group");
protected static final String DELETE_TASKS =
L10N.get("UNDO.PM.DeleteTasks", "Delete Tasks");
protected static final String DELETE_TASK =
L10N.get("UNDO.PM.DeleteTask", "Delete Task");
protected static final String MOVE_TASKS =
L10N.get("UNDO.PM.MoveTasks", "Move Tasks");
protected static final String MOVE_TASK =
L10N.get("UNDO.PM.MoveTask", "Move Task");
protected static final String CHANGE_GROUP_TYPE =
L10N.get("UNDO.PM.ChangeTaskGroupNature", "Change Group Type(s)");
protected static final String visualizationNotCreated =
L10N.get("PC.VIS_ERROR", "Visualization Not Created");
protected static final String noResultsToVisualize =
L10N.get("PC.VIS_ERROR_STRING",
"There are no results to visualize from the selected cell(s).");
protected static final String REGENERATE_SCRIPTS =
L10N.get("UNDO.PM.RegenerateScripts", "Regenerate Scripts");
protected static final String REGENERATE_SCRIPT =
L10N.get("UNDO.PM.RegenerateScript", "Regenerate Script");
protected static final String RECOMPUTE_SCRIPTS =
L10N.get("UNDO.PM.RecomputeScripts", "Recompute Scripts");
protected static final String RECOMPUTE_SCRIPT =
L10N.get("UNDO.PM.RecomputeScript", "Recompute Script");
protected static final String TASK_LABEL =
L10N.get("PC.TaskLabel", "Task:");
protected static final String DESIGN_LABEL =
L10N.get("PC.DesignLabel", "Design:");
protected static final String uncomputedInvalidDemosMsg =
L10N.get("PC.UncomputedInvalidDemos",
"The following scripts were not computed because their demonstrations are currently invalid:");
protected static final String uncomputedObsoleteScriptsMsg =
L10N.get("PC.UncomputedObsoleteScripts",
"The following scripts were not computed because they need to be regenerated:");
protected static final String xmlParseFailed =
L10N.get("PC.ParseFailed", "XML parse failed.");
protected static final String DUPLICATE_DESIGN =
L10N.get("UNDO.PM.DuplicateDesign", "Duplicate Design");
protected static final String DUPLICATE_TASK =
L10N.get("UNDO.PM.DuplicateTask", "Duplicate Task");
protected static final String DUPLICATE_TASKS =
L10N.get("UNDO.PM.DuplicateTasks", "Duplicate Tasks");
protected static final String REORDER_DESIGNS =
L10N.get("UNDO.PM.ReorderDesigns", "Reorder Designs");
protected static final String COMPUTE_SCRIPT =
L10N.get("UNDO.PM.ComputeScript", "Compute Script");
protected static final String SET_ALG_ACTR6 =
L10N.get("UNDO.PM.SetACTR6Algorithm", "Set Algorithm to ACT-R 6");
protected static final String SET_ALG_SNIFACT =
L10N.get("UNDO.PM.SetSNIFACTAlgorithm", "Set Algorithm to SNIF-ACT");
protected static final String SET_RUN_BKG_DEFAULT =
L10N.get("UNDO.PM.SetProjExecBackground",
"Execute algorithms in background by default.");
protected static final String SET_RUN_FG_DEFAULT =
L10N.get("UNDO.PM.SetProjExecForeground",
"Execute algorithms in foreground by default.");
protected static final String SET_PROJ_DEFAULT_ACTR =
L10N.get("UNDO.PM.SetProjDefaultACTR",
"Set Default Algorithm to ACTR");
protected static final String SET_PROJ_DEFAULT_SNIFACT =
L10N.get("UNDO.PM.SetProjDefaultSNIFACT",
"Set Default Algorithm to SNIF-ACT");
protected static final String SET_RUN_FOREGROUND =
L10N.get("UNDO.PM.SetRunInForeground",
"Execute algorithm in the foreground.");
protected static final String SET_RUN_BACKGROUND =
L10N.get("UNDO.PM.SetRunInBackground",
"Execute algorithm in the background.");
protected static final String SET_RUN_PROJECT_DEFAULT =
L10N.get("UNDO.PM.SetRunProjectDefault",
"Execute algorithm using project default.");
protected static final String PROMOTE_TASK =
L10N.get("UNDO.PM.PromoteTask", "Promote Task");
protected static final String PROMOTE_TASKS =
L10N.get("UNDO.PM.PromoteTasks", "Promote Tasks");
protected static final String DEMOTE_TASK =
L10N.get("UNDO.PM.DemoteTask", "Demote Task");
protected static final String DEMOTE_TASKS =
L10N.get("UNDO.PM.DemoteTasks", "Demote Tasks");
protected static final String MOVE_TASK_EARLIER =
L10N.get("UNDO.PM.MoveTaskEarlier", "Move Task Earlier");
protected static final String MOVE_TASKS_EARLIER =
L10N.get("UNDO.PM.MoveTasksEarlier", "Move Tasks Earlier");
protected static final String MOVE_TASK_LATER =
L10N.get("UNDO.PM.MoveTaskLater", "Move Task later");
protected static final String MOVE_TASKS_LATER =
L10N.get("UNDO.PM.MoveTasksLater", "Move Tasks Later");
protected static final String MOVE_TASKAPP =
L10N.get("UNDO.PM.MoveTaskApplication", "Move Script/Result");
protected static final String DUPLICATE_TASKAPP =
L10N.get("UNDO.PM.DuplicateTaskApplication", "Duplicate Script/Result");
protected static final String SNIFACT_COMPUTATION =
L10N.get("UNDO.PM.SnifActComputation", "SNIF-ACT Computation");
protected static final String allDesignsExportedToXml =
L10N.get("PC.ProjectExportedToXML", "Project exported to XML:");
protected static final String designExportedToXml =
L10N.get("PC.DesignExportedToXML", "Design exported to XML:");
protected static final String cannotPromoteTaskError =
L10N.get("PC.CannotPromoteTaskError", "Cannot promote top-level task");
protected static final String cannotDemoteTaskError =
L10N.get("PC.CannotDemoteTaskError",
"Cannot demote the first child task");
protected static final String cannotDemoteIntoGroupError =
L10N.get("PC.CannotDemoteIntoGroupError",
"Cannot add tasks to this group.");
protected static final String taskIsOnlyChild =
L10N.get("PC.TaskIsOnlyChild",
"No move occurred; task is the only child");
protected static final String computeHadNoResult =
L10N.get("PC.ComputeHadNoResult",
"Computation did not generate a prediction result.");
protected static final String cannotRecomputeInvalid =
L10N.get("PC.CannotRecomputeInvalid",
"Cannot compute; not valid or properly generated.");
protected static final String cannotRecomputeNoDemo =
L10N.get("PC.CannotRecomputeNoDemo",
"Cannot compute; no demonstration.");
protected static final String noStartFrameChosen =
L10N.get("PC.NoStartFrameChosen",
"The demonstration must have a selected start frame.");
protected static final String cannotRecomputeNoAssocPath =
L10N.get("PC.CannotRecomputeNoAssocPath",
"Cannot compute; no associated path.");
protected static final String algDisallowsComputation =
L10N.get("PC.AlgDisallowsComputation",
"The current active algorithm does not allow computation; please change the active algorithm");
protected static final String mustSpecifyFileError =
L10N.get("PC.MustSpecifyFile", "Must specify a file");
protected static final String impossibleSituationError =
L10N.get("PC.ImpossibleSituation", "Impossible situation");
protected static final String noURLsToCrawlError =
L10N.get("PC.NoURLsToCrawl", "No URLs to Crawl");
protected static final String generateEntriesMessage =
L10N.get("PM.GoalMessage",
"The task names will be used as the goal strings.");
protected static final String nothingPasted =
L10N.get("PM.NothingPasted", "Nothing pasted");
protected static final String pasteComplete =
L10N.get("PM.PasteComplete", "object(s) pasted");
protected static final String DESIGN_COPIED =
L10N.get("PM.DesignCopied", "Design copied to the clipboard");
protected static final String TASK_COPIED =
L10N.get("PM.TaskCopied", "Task copied to the clipboard");
protected static final String TASKS_COPIED =
L10N.get("PM.TasksCopied", "Tasks copied to the clipboard");
// The associated view object
protected ProjectUI ui;
// The interaction support from the associated view object (cached)
protected ProjectInteraction interaction;
// To help generate unique design names
protected int nextNewDesignSuffix = 1;
protected static int nextNewProjectSuffix = 1;
protected static DesignSelectionState emptyDesignSelectionState =
new DesignSelectionState()
{
public Design getSelectedDesign()
{
return null;
}
};
protected static TaskSelectionState emptyTaskSelectionState =
new TaskSelectionState()
{
protected AUndertaking[] emptySelection =
new AUndertaking[0];
public AUndertaking getSelectedTask()
{
throw new IllegalStateException("No selection to return");
}
public AUndertaking[] getSelectedTasks(int flags)
{
return emptySelection;
}
public int getSelectedTaskCount()
{
return 0;
}
public TaskGroup getSelectedTaskParent()
{
return null;
}
public TaskGroup[] getSelectedTaskParents()
{
return null;
}
public boolean isTaskSelected(AUndertaking t)
{
return false;
}
public boolean isInSelectedHierarchy(AUndertaking task)
{
return false;
}
};
/**
* Constructor to construct a window on a completely new
* <code>Project</code> instance. The new instance is unregistered and
* unmodified.
*
* @author mlh
*/
public ProjectController()
{
this(new Project(DEFAULT_PROJECT_PREFIX + " " + nextNewProjectSuffix++),
true, true);
}
/**
* Constructor to construct an editor window for a given
* <code>Project</code> instance.
*
* @param proj the Project to edit
* @param unregistered whether or not the project has been registered
* with the persistence manager; if not, the project
* will be registered
* @param unmodified whether or not the project instance should be
* considered to be modified (and therefore requiring
* a save to persist the changes)
* @throws RcvrIOTempException if the persistence manager registration
* fails
* @author mlh/centgraf
*/
public ProjectController(Project proj,
boolean unregistered,
boolean unmodified)
{
// All CogTool model controllers record the associated Project
super(proj);
// Fetch the undo manager for this instance, creating one if one
// does not already exist for this instance
undoMgr = UndoManager.getUndoManager(project);
if (unmodified) {
// This is by definition a save point
try {
// Do this only to the Project's undo manager because
// we should not ever get into this code when other windows
// are open unless the project is at a save point; thus,
// this statement will have no effect. If no other windows
// for this project are currently open, then this will be
// (clearly) the first, and only this manager must be set!
undoMgr.markSavePoint();
}
catch (IllegalStateException ex) {
throw new RcvrCannotUndoRedoException("Marking save point", ex);
}
}
// Check if registration with the persistence manager is required
if (unregistered) {
try {
persist.registerForPersistence(project);
}
catch (IOException e) {
throw new RcvrIOTempException("Error persisting new project: "
+ e.getMessage(),
e);
}
}
// Create the associated view support
ui = new ProjectUI(project, undoMgr);
// Cache the view support's user interaction utility
interaction = ui.getInteraction();
// Register the semantic actions for this class and its superclasses
assignActions();
// Show the window
ui.setVisible(true);
}
/**
* Return the Project model being managed by this controller
*
* @return the Project model being managed by this controller
*/
public Project getModel()
{
return project;
}
/**
* Return the primary model object this controller is responsible for
* editing.
* <p>
* In this case, the <code>Project</code> instance is that object.
*
* @return the primary model object this controller is responsible for
* editing
* @author mlh
*/
@Override
protected Object getModelObject()
{
return getModel();
}
/**
* Perform the action to open an existing project.
*/
public boolean openExistingProject(DoublePoint loc)
{
return performAction(ProjectLID.OpenProject, loc, false);
}
/**
* On the assumption that the project is brand new, populate it
* with a new design and a new task, allowing the user to specify
* their names.
*
* @author mlh
*/
public void populateProject()
{
// Create a default design and task to help prevent
// the blank screen problem.
// NewDesign requires a design selection state; create one
// indicating an empty selection.
if (performAction(ProjectLID.NewProjectNewDesign,
emptyDesignSelectionState,
false)) {
// NewTask requires a task selection state; create one
// indicating an empty selection.
performAction(ProjectLID.NewTask, emptyTaskSelectionState, false);
}
// Open up the one design
List<Design> projectDesigns = project.getDesigns();
if (projectDesigns.size() > 0) {
Design design = projectDesigns.get(0);
Controller c =
DesignEditorController.openController(design,
project);
DoubleRectangle projectWinExtent = getExtent();
c.setLocation(projectWinExtent.x + 0.5 * projectWinExtent.width,
projectWinExtent.y + 0.5 * projectWinExtent.height);
}
}
/**
* Registers the set of <code>IListenerAction</code> instances
* that implement the semantic actions that are possible.
* <p>
* For this class, this consists of the actions for a project editor.
*
* @author mlh
*/
@Override
public void assignActions()
{
super.assignActions();
ui.setAction(ProjectLID.Undo,
new UndoController.UndoAction(undoMgr,
interaction));
ui.setAction(ProjectLID.Redo,
new UndoController.RedoAction(undoMgr,
interaction));
ui.setAction(ProjectLID.DeselectAll,
new IListenerAction() {
public Class<?> getParameterClass()
{
return SelectionState.class;
}
public boolean performAction(Object prms)
{
SelectionState selection =
(SelectionState) prms;
selection.deselectAll();
return true;
}
});
ui.setAction(ProjectLID.CopyResultsToClipboard,
createCopyResultsAction());
ui.setAction(ProjectLID.Paste, createPasteAction());
ui.setAction(ProjectLID.CaptureBehavior, createCaptureAction());
ui.setAction(ProjectLID.CopyDesign, createCopyDesignAction());
ui.setAction(ProjectLID.CopyTask, createCopyTaskAction());
ui.setAction(ProjectLID.CutDesign, createCutDesignAction());
ui.setAction(ProjectLID.CutTask, createCutTaskAction());
ui.setAction(ProjectLID.SelectAll,
new AListenerAction() {
public boolean performAction(Object prms)
{
ui.selectAllTasks();
return true;
}
});
ui.setAction(ProjectLID.NewDesign, createNewDesignAction());
ui.setAction(ProjectLID.NewDesignFromImport, createNewDesignForImport());
ui.setAction(ProjectLID.AddDesignDevices,
createAddDesignDevicesAction());
ui.setAction(ProjectLID.NewProjectNewDesign,
createNameProjectNewDesignAction());
ui.setAction(ProjectLID.EditDesign, createEditDesignAction());
ui.setAction(ProjectLID.EditTask,
new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
int selectedTaskCount =
selection.getSelectedTaskCount();
if (selectedTaskCount == 1) {
AUndertaking selectedTask =
selection.getSelectedTask();
ui.initiateTaskRename(selectedTask);
return true;
}
if (selectedTaskCount == 0) {
interaction.protestNoSelection();
}
else {
interaction.protestTooManySelectedTasks();
}
return false;
}
});
ui.setAction(ProjectLID.RenameDesign, createRenameDesignAction());
ui.setAction(ProjectLID.InitiateTaskRename,
createInitiateTaskRenameAction());
ui.setAction(ProjectLID.HCIPARenameTask,
new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.TaskRenameEvent.class;
}
public boolean performAction(Object prms)
{
ProjectUI.TaskRenameEvent evt =
(ProjectUI.TaskRenameEvent) prms;
return hcipaRenameTask(evt.task,
evt.task.getName(),
evt.newName);
}
});
ui.setAction(ProjectLID.RenameTask,
new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.TaskRenameEvent.class;
}
public boolean performAction(Object prms)
{
ProjectUI.TaskRenameEvent evt =
(ProjectUI.TaskRenameEvent) prms;
return renameTask(evt.task,
evt.task.getName(),
evt.newName,
evt.parent);
}
});
ui.setAction(ProjectLID.EditScript, createScriptEditorAction());
ui.setAction(ProjectLID.ViewGroupScript,
createScriptViewerAction());
ui.setAction(ProjectLID.DeleteDesign, createDeleteDesignAction());
ui.setAction(ProjectLID.DeleteTask, createDeleteTaskAction());
ui.setAction(ProjectLID.NewTask, createNewTaskAction());
ui.setAction(ProjectLID.NewTaskGroup, createNewTaskGroupAction());
ui.setAction(ProjectLID.ReorderDesigns,
createReorderDesignsAction());
ui.setAction(ProjectLID.ShowSum,
createShowNatureAction(GroupNature.SUM,
ProjectLID.ShowSum));
ui.setAction(ProjectLID.ShowMean,
createShowNatureAction(GroupNature.MEAN,
ProjectLID.ShowMean));
ui.setAction(ProjectLID.ShowMin,
createShowNatureAction(GroupNature.MIN,
ProjectLID.ShowMin));
ui.setAction(ProjectLID.ShowMax,
createShowNatureAction(GroupNature.MAX,
ProjectLID.ShowMax));
ui.setAction(ProjectLID.RegenerateScript,
createRegenerateScriptAction());
ui.setAction(ProjectLID.RecomputeScript,
createRecomputeScriptAction());
ui.setAction(ProjectLID.ShowModelVisualization,
createShowModelVisualizationAction());
ui.setAction(ProjectLID.DisplayTraces, createDisplayTraces());
ui.setAction(ProjectLID.ExportTraces, createExportTraces());
ui.setAction(ProjectLID.ExportForSanlab, createExportForSanlab());
ui.setAction(ProjectLID.ExportActrModelFile,
createExportActrModelFile());
ui.setAction(ProjectLID.ExportDesignToHTML,
createExportDesignToHTMLAction());
ui.setAction(ProjectLID.ExportToHCIPA,
createExportToHCIPAAction());
ui.setAction(ProjectLID.ExportResultsToCSV,
createExportResultsToCSVAction());
ui.setAction(ProjectLID.ImportXML,
createImportAction());
/*for(CogToolLID lid : ProjectLID.getCollection())
{
this.ui.setAction(lid,
createImportAction());
}*/
/*this.ui.setAction(ProjectLID.ImportXML,
new IListenerAction() {
public Class<?> getParameterClass()
{
return Class.class;
}
<<<<<<< .mine
public boolean performAction(Object prms)
{
Class convClass = (Class)prms;
createImportAction(convClass);
return true;
}
});*/
ui.setAction(ProjectLID.ImportWebCrawl,
createImportWebCrawlAction());
ui.setAction(ProjectLID.ExportScriptToCSV,
createExportScriptToCSVAction());
ui.setAction(ProjectLID.ExportToXML,
createExportDesignToXML());
ui.setAction(ProjectLID.DuplicateDesign,
createDuplicateDesignAction());
ui.setAction(ProjectLID.DuplicateTask,
createDuplicateTasksAction());
ui.setAction(ProjectLID.ImportHumanCSVFile,
createImportHumanCSVFileAction());
ui.setAction(ProjectLID.SetAlgorithmACTR6,
createSetAlgorithmAction(ACTR6PredictionAlgo.ONLY,
ProjectLID.SetAlgorithmACTR6,
SET_ALG_ACTR6));
ui.setAction(ProjectLID.SetAlgorithmSNIFACT,
createSetAlgorithmAction(SNIFACTPredictionAlgo.ONLY,
ProjectLID.SetAlgorithmSNIFACT,
SET_ALG_SNIFACT));
ui.setAction(ProjectLID.SetAlgorithmHuman,
createSetAlgorithmHumanAction());
ui.setAction(ProjectLID.EditACTRModelFile,
createEditACTRModelAction());
ui.setAction(ProjectLID.SetBackgroundComputationDefault,
createSetBackgroundComputeAction(TaskApplication.USE_PROJECT_DEFAULT,
ProjectLID.SetBackgroundComputationDefault,
SET_RUN_PROJECT_DEFAULT));
ui.setAction(ProjectLID.SetBackgroundComputationTrue,
createSetBackgroundComputeAction(TaskApplication.RUN_IN_BACKGROUND,
ProjectLID.SetBackgroundComputationTrue,
SET_RUN_BACKGROUND));
ui.setAction(ProjectLID.SetBackgroundComputationFalse,
createSetBackgroundComputeAction(TaskApplication.RUN_IN_FOREGROUND,
ProjectLID.SetBackgroundComputationFalse,
SET_RUN_FOREGROUND));
ui.setAction(ProjectLID.GenerateACTRModelFile,
createGenerateACTRModelAction());
ui.setAction(ProjectLID.SetProjDefaultAlgoACTR,
createSetProjDefaultAlg(ProjectLID.SetProjDefaultAlgoACTR,
SET_PROJ_DEFAULT_ACTR,
ACTR6PredictionAlgo.ONLY));
ui.setAction(ProjectLID.SetProjDefaultAlgoSNIFACT,
createSetProjDefaultAlg(ProjectLID.SetProjDefaultAlgoSNIFACT,
SET_PROJ_DEFAULT_SNIFACT,
SNIFACTPredictionAlgo.ONLY));
ui.setAction(ProjectLID.SetProjExecBackground,
createSetProjDefaultExecBkg(ProjectLID.SetProjExecBackground,
SET_RUN_BKG_DEFAULT,
true));
ui.setAction(ProjectLID.SetProjExecForeground,
createSetProjDefaultExecBkg(ProjectLID.SetProjExecForeground,
SET_RUN_FG_DEFAULT,
false));
ui.setAction(ProjectLID.ChangeTaskPosition,
createChangeTaskPositionAction());
ui.setAction(ProjectLID.DuplicateTaskFull,
createDuplicateTaskFullAction());
ui.setAction(ProjectLID.Ungroup, createUngroupAction());
ui.setAction(ProjectLID.PromoteTask,
createPromoteTaskAction());
ui.setAction(ProjectLID.DemoteTask,
createDemoteTaskAction());
ui.setAction(ProjectLID.MoveTaskEarlier,
createMoveTaskEarlierAction());
ui.setAction(ProjectLID.MoveTaskLater,
createMoveTaskLaterAction());
ui.setAction(ProjectLID.GenerateDictionary,
createGenerateDictionaryAction());
ui.setAction(ProjectLID.EditDictionary,
createOpenDictionaryAction());
ui.setAction(ProjectLID.ExportDictToCSV,
createExportDictionaryAction());
ui.setAction(ProjectLID.ImportDict,
createImportDictionaryAction());
ui.setAction(ProjectLID.MoveTaskApplication,
createMoveTaskAppAction());
ui.setAction(ProjectLID.DuplicateTaskApplication,
createDuplicateTaskAppAction());
} // assignActions
protected boolean computeSnifAct(Design design,
AUndertaking task,
IUndoableEditSequence editSequence,
SNIFACTGroupParameters defaults)
{
// TODO: L10N required for error titles and messages.
if (design == null) {
interaction.reportProblem("SNIF-ACT",
"No design is selected.");
return false;
}
if (design.getFrames().size() == 0) {
interaction.reportProblem("SNIF-ACT",
"Selected design is empty.");
return false;
}
if (task.isTaskGroup()) {
// We can only recompute with this algorithm if the
// group was generated by a previous SNIF-ACT
// computation (and thus has the execution
// context attribute)
Object contextAttr =
task.getAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR);
if (NullSafe.equals(contextAttr,
WidgetAttributes.NO_CONTEXT))
{
interaction.reportProblem("SNIF-ACT",
"Can't recompute with this algorithm from this cell.");
return false;
}
}
ISimilarityDictionary dict =
(ISimilarityDictionary) design.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
if (dict == null) {
interaction.reportProblem("Export Dictionary",
"No dictionary exists for the selected design");
return false;
}
List<Frame> sortedFrames =
NamedObjectUtil.getSortedList(design.getFrames());
SNIFACTParameters parms;
int addGroupMode;
boolean hasScript = false;
final SNIFACTExecContext prevContext;
if (task.isTaskGroup()) {
// Since we got this far, we know the group already has
// parameters associated with it, so use those values as
// defaults in the dialog box
prevContext =
(SNIFACTExecContext) task.getAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR);
parms = prevContext.getParameters();
addGroupMode = SNIFACTDialog.ENABLED;
}
else {
// Otherwise, create a new set of default values for this
// execution
String defaultName = sortedFrames.get(0).getName();
List<String> targets = new ArrayList<String>();
targets.add(defaultName);
parms = new SNIFACTParameters(task.getName(),
NUM_SNIF_ACT_TRIALS,
SNIF_ACT_K_VALUE,
defaultName,
targets,
ITermSimilarity.ALL);
addGroupMode = SNIFACTDialog.NONE;
prevContext = null;
TaskApplication ta =
project.getTaskApplication(task, design);
hasScript = (ta != null) && ta.hasScript();
}
SNIFACTGroupParameters groupParms = null;
if (defaults == null) {
groupParms =
interaction.requestSNIFACTParameters(hasScript,
sortedFrames,
parms,
dict.getAlgorithmsInUse(),
addGroupMode);
} else {
groupParms = new SNIFACTGroupParameters(defaults.taskName,
defaults.numRuns,
defaults.kValue,
defaults.startFrame,
defaults.targetFrames,
defaults.algorithm,
((addGroupMode != SNIFACTDialog.NONE) && defaults.addToGroup));
}
if (groupParms == null) {
return false;
}
SNIFACTPredictionAlgo.ONLY.setParameters(groupParms);
TaskParent parent = task.getTaskGroup();
if (parent == null) {
parent = project;
}
final TaskGroup group;
if (groupParms.addToGroup) {
// user wants to add new trial tasks to the same group
group = (TaskGroup) task;
}
else {
Collection<AUndertaking> siblings = parent.getUndertakings();
group = new TaskGroup(SNIFACTCmd.getGroupName(groupParms,
siblings),
GroupNature.MEAN);
}
final SNIFACTExecContext context =
SNIFACTCmd.computeInBackground(project,
design,
interaction,
group,
groupParms);
if (context == null) {
return true;
}
group.setAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR, context);
CompoundUndoableEdit snifActEditSeq =
new CompoundUndoableEdit(SNIFACT_COMPUTATION,
ProjectLID.RecomputeScript);
if (! task.isTaskGroup()) {
snifActEditSeq.addEdit(HCIPACmd.replaceTask(project,
parent,
task,
group,
SNIFACT_COMPUTATION));
}
else {
if (groupParms.addToGroup) {
snifActEditSeq.addEdit(SNIFACTCmd.addTasksToGroup(project,
group,
context,
SNIFACT_COMPUTATION));
}
else {
snifActEditSeq.addEdit(SNIFACTCmd.addGroup(project,
parent,
group,
SNIFACT_COMPUTATION));
}
}
snifActEditSeq.addEdit(new AUndoableEdit(ProjectLID.RecomputeScript) {
@Override
public String getPresentationName()
{
return SNIFACT_COMPUTATION;
}
@Override
public void redo()
{
super.redo();
group.setAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR,
context);
}
@Override
public void undo()
{
super.undo();
group.setAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR,
prevContext);
}
});
snifActEditSeq.end();
if (editSequence != null) {
editSequence.addEdit(snifActEditSeq);
}
return true;
}
protected IListenerAction createImportDictionaryAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState seln =
(ProjectSelectionState) actionParms;
Design design = seln.getSelectedDesign();
if (design == null) {
interaction.reportProblem("Import Dictionary",
"No design is selected");
return false;
}
ISimilarityDictionary prevDict =
(ISimilarityDictionary) design.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
// Leonghwee says he wants the imported dictionary to replace
// the old one
ISimilarityDictionary dict = new SimilarityDictionary();
design.setAttribute(WidgetAttributes.DICTIONARY_ATTR, dict);
boolean success = DictionaryEditorCmd.importDictionary(design,
dict,
prevDict,
interaction,
undoMgr, null);
if (success) {
DictionaryEditorController.openController(dict,
design,
project);
}
return success;
}
};
}
protected IListenerAction createExportDictionaryAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState seln =
(ProjectSelectionState) actionParms;
Design design = seln.getSelectedDesign();
if (design == null) {
interaction.reportProblem("Export Dictionary",
"No design is selected");
return false;
}
ISimilarityDictionary dict =
(ISimilarityDictionary) design.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
if (dict == null) {
interaction.reportProblem("Export Dictionary",
"No dictionary exists for the selected design");
return false;
}
return DictionaryEditorCmd.exportDictionaryToCSV(dict,
interaction);
}
};
}
protected IListenerAction createOpenDictionaryAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
Design design = seln.getSelectedDesign();
if (design != null) {
openDictionaryEditor(design);
}
return true;
}
};
}
protected void openDictionaryEditor(Design design)
{
ISimilarityDictionary dict =
(ISimilarityDictionary) design.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
if (NullSafe.equals(dict, WidgetAttributes.NO_DICTIONARY)) {
dict = new SimilarityDictionary();
design.setAttribute(WidgetAttributes.DICTIONARY_ATTR, dict);
}
DictionaryEditorController.openController(dict,
design,
project);
}
protected IListenerAction createGenerateDictionaryAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
Design d = seln.getSelectedDesign();
boolean hasDict = false;
ITermSimilarity defaultAlg = ISimilarityDictionary.DEFAULT_ALG;
if (d != null) {
ISimilarityDictionary dict =
(ISimilarityDictionary) d.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
if (! NullSafe.equals(dict, WidgetAttributes.NO_DICTIONARY))
{
hasDict = true;
defaultAlg = dict.getCurrentAlgorithm();
}
}
else {
// No design selected, so just show the compute options
hasDict = true;
}
ProjectInteraction.GenerateEntriesData requestData =
requestGenerateParms(generateEntriesMessage,
defaultAlg,
hasDict);
if (requestData == null) {
return false;
}
GenerateDictEntriesWorkThread workThread =
new GenerateDictEntriesWorkThread(interaction,
d,
tasks,
project,
undoMgr,
requestData);
CogTool.logger.info(String.format(
"Generating dictionary for design %s in project %s.",
d.getName(), getProject().getName()));
ThreadManager.startNewThread(workThread);
return true;
}
};
}
protected ProjectInteraction.GenerateEntriesData requestGenerateParms(String request,
ITermSimilarity defaultAlg,
boolean hasDict)
{
return interaction.requestGenerateDictionaryParms(request,
defaultAlg,
hasDict);
}
protected IListenerAction createScriptViewerAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
if (prms != null) {
ProjectSelectionState seln =
(ProjectSelectionState) prms;
// Must have selected tasks and design
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
if ((design == null) ||
(tasks == null) ||
(tasks.length == 0))
{
return false;
}
boolean viewSuccessful = false;
// Viewing a script only applies to task groups
for (AUndertaking task : tasks) {
if (task.isTaskGroup()) {
TaskGroup group = (TaskGroup) task;
List<AUndertaking> childTasks =
group.getUndertakings();
if (childTasks.size() > 0) {
AUndertaking firstTask = childTasks.get(0);
TaskApplication ta =
project.getTaskApplication(firstTask,
design);
if (ta != null) {
ITaskDesign td =
project.getTaskDesign(task, design);
ScriptViewerController.openController(td,
project);
viewSuccessful = true;
}
}
}
}
if (! viewSuccessful) {
interaction.setStatusMessage(L10N.get("PC.NoScriptsToView",
"No scripts to view."));
}
return true;
}
interaction.protestNoSelection();
return false;
}
};
}
protected boolean hcipaRenameTask(AUndertaking task,
String oldName,
String newName)
{
// Check if newTaskName is empty; retry if user desires
if (oldName.length() == 0) {
if (interaction.protestEmptyTaskName()) {
ui.initiateTaskRename(task);
return true;
}
return false;
}
TaskGroup parent = task.getTaskGroup();
// Check uniqueness of new name; if not, complain
if (isTaskNameUnique(newName, oldName, parent)) {
// If renaming the group, change both labels
if (task.isTaskGroup()) {
TaskGroup group = (TaskGroup) task;
// Just a rename; not changing nature
undoMgr.addEdit(HCIPACmd.updateLabels(group,
newName,
RENAME_TASK));
}
else if (! newName.equals(oldName)) {
// Rename only if the name has changed
if (parent == null) {
// Create task group; generate subtasks
AUndertaking[] subtasks =
HCIPACmd.addHCIPATasks(project,
task,
newName,
MODELGEN_ALG,
RENAME_TASK,
undoMgr);
ui.initiateTaskRename(subtasks[1], false);
}
else {
if (parent.getUndertakings().indexOf(task) == 1) {
// changing function name
HCIPACmd.setFunctionName(project,
task,
newName,
MODELGEN_ALG,
RENAME_TASK,
undoMgr);
return true;
}
// not the select function step, so rename normally
return renameTask(task, oldName, newName, parent);
}
}
return true;
}
// Not unique; complain and retry if user desires
if (interaction.protestNotUniqueTaskName()) {
ui.initiateTaskRename(task);
return true;
}
return false;
}
protected void displayTraces(AUndertaking task, Design design)
{
if (task.isTaskGroup()) {
Iterator<AUndertaking> allSubtasks =
((TaskGroup) task).getUndertakings().iterator();
while (allSubtasks.hasNext()) {
displayTraces(allSubtasks.next(), design);
}
}
else {
TaskApplication taskApp =
project.getTaskApplication(task, design);
if (taskApp != null) {
StringBuilder labelText = new StringBuilder();
Iterator<CognitiveModelGenerator> modelGens =
taskApp.getModelGenerators();
while (modelGens.hasNext()) {
CognitiveModelGenerator modelGen = modelGens.next();
Iterator<IPredictionAlgo> computeAlgs =
taskApp.getPredictionAlgs(modelGen);
while (computeAlgs.hasNext()) {
IPredictionAlgo computeAlg = computeAlgs.next();
APredictionResult result =
taskApp.getResult(modelGen, computeAlg);
int resultState = result.getResultState();
if ((result != null) &&
((resultState == APredictionResult.IS_COMPUTED) ||
(resultState == APredictionResult.COMPUTE_FAILED)))
{
labelText.delete(0, labelText.length());
labelText.append(tracesWindowLabel);
labelText.append(": ");
labelText.append(project.getName());
labelText.append(" > ");
labelText.append(design.getName());
labelText.append(" > ");
labelText.append(task.getName());
String labelStr = labelText.toString();
ITraceWindow traceWin =
interaction.createTraceWindow(labelStr
+ (OSUtils.MACOSX
? ""
: UI.WINDOW_TITLE),
null,
labelStr);
traceWin.appendOutputLines(result.getTraceLines());
traceWin.scrollToTop();
traceWin.appendErrorLines(result.getErrorLines());
traceWin.scrollToTop();
}
}
}
}
}
}
// Action for DisplayTraces
protected IListenerAction createDisplayTraces()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState sel =
(ProjectSelectionState) actionParms;
Design design = sel.getSelectedDesign();
AUndertaking[] tasks =
sel.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
if (design != null) {
if ((tasks != null) && (tasks.length > 0)) {
for (AUndertaking task : tasks) {
displayTraces(task, design);
}
}
else {
Iterator<AUndertaking> allTasks =
project.getUndertakings().iterator();
while (allTasks.hasNext()) {
displayTraces(allTasks.next(),
design);
}
}
}
else if ((tasks != null) && (tasks.length > 0)) {
for (AUndertaking task : tasks) {
Iterator<Design> allDesigns =
project.getDesigns().iterator();
while (allDesigns.hasNext()) {
displayTraces(task,
allDesigns.next());
}
}
}
return true;
}
};
}
// TODO there's way too much cloning of code in the next three methods; refactor them
// Action for ExportTraces
protected IListenerAction createExportTraces()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState sel =
(ProjectSelectionState) actionParms;
// Fetch traces for the default algorithm (TODO:)
List<String> traces =
getTraces(sel, MODELGEN_ALG, project.getDefaultAlgo());
// Ask user for location of saved file.
File exportFile =
interaction.selectExportLocation("Exported ACT-R trace",
CogToolFileTypes.TEXT_FILE_EXT);
// User canceled
if (exportFile == null) {
return false;
}
boolean okToProceed = false;
// TODO: should we move this file write somewhere else?
PrintWriter writer = null;
try {
// Attempt to open the output file
FileOutputStream out = new FileOutputStream(exportFile);
writer = new PrintWriter(out);
// Put each trace line on its own output line
Iterator<String> iter = traces.iterator();
while (iter.hasNext()) {
String s = iter.next();
writer.println(s);
}
writer.flush();
okToProceed = true;
}
catch (IOException e) {
throw new RcvrIOSaveException("Writing the trace logs"
+ "failed. \n\n"
+ "Please try again.", e);
}
finally {
if (writer != null) {
writer.close();
}
}
return okToProceed;
}
};
}
// Action for ExportDesignFiles
// XXX: does this really belong in ProjectController? It seems like
// something that's tied to whichever backend we're really using,
// and so should be somewhere else
protected IListenerAction createExportActrModelFile()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState sel =
(ProjectSelectionState) actionParms;
// Must have selected tasks and design
Design design = sel.getSelectedDesign();
AUndertaking[] tasks =
sel.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
if ((design == null) || (tasks == null) || (tasks.length == 0))
{
return false;
}
// Ask user for location of saved file.
File exportFile =
interaction.selectExportLocation("Exported ACT-R Model",
CogToolFileTypes.LISP_FILE_EXT);
// User canceled
if (exportFile == null) {
return false;
}
for (AUndertaking task : tasks) {
// If no script set exists for this cell, create
TaskApplication ta =
project.getTaskApplication(task, design);
if (ta != null) {
if (ta.getDesign() != design) {
throw new RcvrIllegalStateException(
"Unexpected Design mis-match (" +
ta.getDesign() + ", " + design + ")");
}
// If no script exists for this cell, create one
Script script =
DemoStateManager.ensureScript(ta, MODELGEN_ALG);
try {
IPredictionAlgo taAlg =
ta.determineActiveAlgorithm(project);
if (! (taAlg instanceof ACTRPredictionAlgo)) {
throw new RcvrIllegalStateException(
"Can't export ACT-R Model from a non ACT-R task.");
}
if (script.getAssociatedPath() != null) {
File f = new File(script.getAssociatedPath());
// The following will throw an IOException if
// the input file doesn't exist; this is exactly
// the same behaviour as if we're trying to do
// a recompute, and is better than silently
// substituting a generated model file
FileUtil.copyTextFileToFile(f, exportFile);
return true;
}
ACTRPredictionAlgo algo =
(ACTRPredictionAlgo) taAlg;
algo.outputModel(design,
task,
ta.getDemonstration().getStartFrame(),
script,
exportFile,
null);
}
catch (UnsupportedOperationException ex) {
throw new RcvrUnimplementedFnException(ex);
}
catch (IOException ex) {
throw new RcvrIOException(
("IOException exporting model file for task " +
task.getName() + " in design " +
design.getName()),
ex);
}
}
}
return true;
}
};
}
private static final Pattern TRACE_PAT = Pattern.compile(
"\\s+[0-9.]+\\s+[A-Z-]+\\s+.*");
protected IListenerAction createExportForSanlab()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState sel =
(ProjectSelectionState) actionParms;
// Must have selected tasks and design
Design design = sel.getSelectedDesign();
AUndertaking[] tasks =
sel.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
if ((design == null) || (tasks == null) || (tasks.length == 0))
{
return false;
}
// Fetch traces for the default algorithm (TODO:)
List<String> traces =
getTraces(sel, MODELGEN_ALG, project.getDefaultAlgo());
// Ask user for location of saved file.
File exportFile =
interaction.selectExportLocation("cogtool-sanlab",
CogToolFileTypes.TEXT_FILE_EXT);
// User canceled
if (exportFile == null) {
return false;
}
boolean okToProceed = false;
for (AUndertaking task : tasks) {
// If no script set exists for this cell, create
TaskApplication ta =
project.getTaskApplication(task, design);
if (ta != null) {
if (ta.getDesign() != design) {
throw new RcvrIllegalStateException(
"Unexpected Design mis-match for SANLab (" +
ta.getDesign() + ", " + design + ")");
}
// If no script exists for this cell, create one
Script script =
DemoStateManager.ensureScript(ta, MODELGEN_ALG);
try {
IPredictionAlgo taAlg =
ta.determineActiveAlgorithm(project);
if (! (taAlg instanceof ACTRPredictionAlgo)) {
throw new RcvrIllegalStateException(
"Can't export model for SANLab from a non ACT-R task.");
}
if (script.getAssociatedPath() != null) {
File f = new File(script.getAssociatedPath());
// The following will throw an IOException if
// the input file doesn't exist; this is exactly
// the same behaviour as if we're trying to do
// a recompute, and is better than silently
// substituting a generated model file
FileUtil.copyTextFileToFile(f, exportFile);
return true;
}
ACTRPredictionAlgo algo =
(ACTRPredictionAlgo) taAlg;
algo.outputModel(design,
task,
ta.getDemonstration().getStartFrame(),
script,
exportFile,
null);
}
catch (UnsupportedOperationException ex) {
throw new RcvrUnimplementedFnException(ex);
}
catch (IOException ex) {
throw new RcvrIOException(
("IOException exporting SANLab model file for task " +
task.getName() + " in design " +
design.getName()),
ex);
}
}
}
// TODO: should we move this file write somewhere else?
PrintWriter writer = null;
try {
// Attempt to open the output file
FileOutputStream out = new FileOutputStream(exportFile, true);
writer = new PrintWriter(out);
writer.println("\n\n;;; TRACE STARTS HERE");
Matcher mt = TRACE_PAT.matcher("");
// Put each trace line on its own output line
Iterator<String> iter = traces.iterator();
while (iter.hasNext()) {
String s = iter.next();
if (mt.reset(s).matches()) {
writer.println(s);
}
}
writer.flush();
okToProceed = true;
}
catch (IOException e) {
throw new RcvrIOSaveException("Writing the trace logs for "
+ "SANLab failed. \n\n"
+ "Please try again.", e);
}
finally {
if (writer != null) {
writer.close();
}
}
return okToProceed;
}
};
}
/**
* Utility to accumulate all of the (ACT-R) trace lines for the given
* task, design, and algorithm.
* <p>
* If the given task is an <code>TaskGroup</code>, the trace lines
* are accumulated recursively by appending together those associated
* with descendant tasks.
* Traces are associated with results, which are determined for the
* given task and design by which algorithm generated the cognitive model
* and which prediction algorithm computed the result from that model.
*
* @param task the task for which to find results associated with
* the given algorithm
* @param design the design for which to find results associated with
* the given algorithm
* @param modelGen the algorithm for generating cognitive models (i.e.,
* scripts) from demonstrations
* @param computeAlg the algorithm for generating results from
* cognitive models
* @author mlh/alex
*/
protected List<String> getTraces(AUndertaking task,
Design design,
CognitiveModelGenerator modelGen,
IPredictionAlgo computeAlg)
{
List<String> traces = new ArrayList<String>();
// If an TaskGroup, get the traces for each child (recursively)
// and append to the current state.
if (task.isTaskGroup()) {
Iterator<AUndertaking> allTasks =
((TaskGroup) task).getUndertakings().iterator();
traces.add("For TaskGroup " + task.getName());
while (allTasks.hasNext()) {
traces.addAll(getTraces(allTasks.next(),
design,
modelGen,
computeAlg));
}
return traces;
}
// Base case; find the result for the given task/design/algorithm
TaskApplication taskApp =
project.getTaskApplication(task, design);
// Result must exist and be current
if (taskApp != null) {
APredictionResult result =
taskApp.getResult(modelGen, computeAlg);
// Result may be null (although unlikely at this point).
if ((result != null) &&
(result.getResultState() == APredictionResult.IS_COMPUTED))
{
traces.add("Standard OUTPUT from Task " + task.getName());
// Add the trace lines from the result
traces.addAll(result.getTraceLines());
traces.add("\nStandard ERROR from Task " + task.getName());
traces.addAll(result.getErrorLines());
}
}
return traces;
} // getTraces
/**
* Utility to accumulate all of the (ACT-R) trace lines for the given
* selected task and design intersections and the given algorithm.
* <p>
* If there are no selected tasks, accumulate all trace lines for the
* selected design and all tasks. If there is no selected design,
* accumulate all trace lines for selected tasks and all designs.
* An empty list is returned if nothing is selected.
*
* @param sel the selected tasks and design for which to find results
* associated with the given algorithm
* @param modelGen the algorithm for generating cognitive models (i.e.,
* scripts) from demonstrations
* @param computeAlg the algorithm for generating results from
* cognitive models
* @author mlh/alex
*/
protected List<String> getTraces(ProjectSelectionState sel,
CognitiveModelGenerator modelGen,
IPredictionAlgo computeAlg)
{
Design design = sel.getSelectedDesign();
AUndertaking[] tasks =
sel.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
List<String> traces = new ArrayList<String>();
// If a design was selected, fetch trace lines for valid results
// either for selected tasks or for all tasks (if none selected).
if (design != null) {
traces.add("For Design " + design.getName());
// Get for selected tasks
if ((tasks != null) && (tasks.length > 0)) {
for (AUndertaking task : tasks) {
traces.addAll(getTraces(task, design,
modelGen, computeAlg));
}
}
else {
// No tasks selected; get traces from all undertakings
Iterator<AUndertaking> allTasks =
project.getUndertakings().iterator();
while (allTasks.hasNext()) {
traces.addAll(getTraces(allTasks.next(),
design,
modelGen,
computeAlg));
}
}
}
else if ((tasks != null) && (tasks.length > 0)) {
// Design was null, get for selected tasks and all designs.
for (AUndertaking task : tasks) {
Iterator<Design> allDesigns =
project.getDesigns().iterator();
while (allDesigns.hasNext()) {
Design d = allDesigns.next();
traces.add("For Design " + d.getName());
traces.addAll(getTraces(task, d, modelGen, computeAlg));
}
}
}
return traces;
} // getTraces
/**
* Close the associated window, recovering all associated resources.
*
* @author mlh
*/
@Override
public void dispose()
{
super.dispose();
// If the policy has been set so that the "project manages" the
// objects it contains, then close all other windows for objects
// that are part of this project.
if (CogTool.projectManagesOthers) {
CogTool.controllerNexus.closeControllers(project, false);
}
}
/**
* Debugging utility
*/
protected void printTree(List<AUndertaking> tasks, String indent)
{
for (AUndertaking u : tasks) {
if (u.isTaskGroup()) {
System.out.println(indent + "TaskGroup: "
+ u.getClass().getName());
printTree(((TaskGroup) u).getUndertakings(), indent + " ");
}
else {
System.out.println(indent + "Task : " + u);
}
}
}
/**
* Utility to ensure that the given design has a unique name relative
* to the designs held by the Project.
*
* @param design the design whose name must not conflict within the project
* @author mlh
*/
protected void makeDesignNameUnique(Design design)
{
design.setName(NamedObjectUtil.makeNameUnique(design.getName(),
project.getDesigns()));
}
/**
* Utility to ensure that the given task has a unique name relative
* to the given parent task group.
*
* @param parent the parent task group defining the name scope
* @param task the task whose name must not conflict within the parent
* @author mlh
*/
protected void makeTaskNameUnique(TaskParent parent, AUndertaking task)
{
task.setName(NamedObjectUtil.makeNameUnique(task.getName(),
parent.getUndertakings()));
}
/**
* Returns true if the given task is used; false if a project's
* existing task is used.
*/
protected boolean pasteTask(AUndertaking task,
TaskParent taskParent,
int index,
IUndoableEditSequence editSeq,
String presentationName)
{
if (taskParent == null) {
taskParent = project;
}
// Either using the given task always (i.e., usedTasks is null)
// or there is no corresponding task already in the project
// or the user said not to reuse an existing corresponding task
makeTaskNameUnique(taskParent, task);
taskParent.addUndertaking(index, task);
// Add an undo step after creating/placing
editSeq.addEdit(createNewTaskUndo(taskParent,
index,
task,
ProjectLID.Paste,
presentationName));
return true;
}
// Utility to help both copyResults and exportResultsToCSV
protected void addTaskResults(Iterator<AUndertaking> tasks,
StringBuilder buffer,
String separator)
{
while (tasks.hasNext()) {
AUndertaking t = tasks.next();
String[] resultStrs =
ResultDisplayPolicy.getTaskRowStrings(project,
t,
ResultDisplayPolicy.NO_SECS);
if (resultStrs.length > 0) {
buffer.append(CSVSupport.quoteCell(resultStrs[0]));
for (int i = 1; i < resultStrs.length; i++) {
buffer.append(separator);
buffer.append(CSVSupport.quoteCell(resultStrs[i]));
}
}
CSVSupport.addLineEnding(buffer);
if (t.isTaskGroup()) {
addTaskResults(((TaskGroup) t).getUndertakings().iterator(),
buffer,
separator);
}
}
}
protected static final String CLIPBOARD_SEPARATOR = "\t";
protected static final String CSV_SEPARATOR =
Character.toString(CSVSupport.CELL_SEPARATOR);
protected static final String FORMAT_VERSION = "1.0";
// Utility to help both copyResults and exportResultsToCSV
protected StringBuilder exportResults(String separator, Date now)
{
StringBuilder buffer = new StringBuilder();
buffer.append(CSVSupport.quoteCell("Format version:"));
buffer.append(separator);
buffer.append(CSVSupport.quoteCell(FORMAT_VERSION));
CSVSupport.addLineEnding(buffer);
buffer.append(CSVSupport.quoteCell("Date and Time:"));
buffer.append(separator);
String date = DateFormat.getDateTimeInstance().format(now);
buffer.append(CSVSupport.quoteCell(date));
CSVSupport.addLineEnding(buffer);
buffer.append(CSVSupport.quoteCell("All times are in seconds"));
CSVSupport.addLineEnding(buffer);
buffer.append(CSVSupport.quoteCell("Project:"));
buffer.append(separator);
buffer.append(CSVSupport.quoteCell(project.getName()));
CSVSupport.addLineEnding(buffer);
buffer.append(CSVSupport.quoteCell("Tasks"));
List<Design> designs = project.getDesigns();
Iterator<Design> allDesigns = designs.iterator();
while (allDesigns.hasNext()) {
Design design = allDesigns.next();
buffer.append(separator);
buffer.append(CSVSupport.quoteCell(design.getName()));
}
CSVSupport.addLineEnding(buffer);
addTaskResults(project.getUndertakings().iterator(), buffer, separator);
return buffer;
}
// Action for copying results to clipboard; uses TAB as separator!
protected IListenerAction createCopyResultsAction()
{
return new AListenerAction() {
public boolean performAction(Object prms)
{
StringBuilder buffer =
exportResults(CLIPBOARD_SEPARATOR, new Date());
ClipboardUtil.copyTextData(buffer.toString());
interaction.setStatusMessage(L10N.get("PS.ResultDataCopied",
"Result data copied."));
return true;
}
};
}
protected void mapProjectTasks(AUndertaking task,
TaskParent parent,
Map<AUndertaking, AUndertaking> reuseTasks,
IUndoableEditSequence editSeq,
String presentationName)
{
AUndertaking correspondingTask = parent.getUndertaking(task.getName());
if (correspondingTask != null) {
reuseTasks.put(task, correspondingTask);
if ((task instanceof TaskGroup) &&
(correspondingTask instanceof TaskGroup))
{
TaskGroup correspondingGroup = (TaskGroup) correspondingTask;
Iterator<AUndertaking> childTasks =
((TaskGroup) task).getUndertakings().iterator();
while (childTasks.hasNext()) {
AUndertaking childTask = childTasks.next();
mapProjectTasks(childTask,
correspondingGroup,
reuseTasks,
editSeq,
presentationName);
}
}
}
else {
pasteTask(task, parent, parent.getUndertakings().size(),
editSeq, presentationName);
}
}
// Action for Paste
protected IListenerAction createPasteAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
try {
// Check for CogTool objects to paste
Collection<Object> objects =
CogToolClipboard.fetchCogToolObjects(project);
int numObjectsPasted = 0; // designs and tasks only
if ((objects != null) && (objects.size() > 0)) {
// Paste tasks as children of the selected TaskGroup
AUndertaking[] selectedTasks =
seln.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
TaskGroup taskParent = seln.getSelectedTaskParent();
int index;
// If there is a selected TaskGroup, determine the
// index at which new pasted Tasks will be placed.
if (taskParent != null) {
AUndertaking last =
selectedTasks[selectedTasks.length - 1];
index =
taskParent.getUndertakings().indexOf(last) + 1;
}
else {
index = findLastSelectedRoot(selectedTasks);
}
// Create undo support
String presentationName = PASTE;
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(presentationName,
ProjectLID.Paste);
// If task applications are pasted, they will have
// null Design fields; they should "arrive" after
// the Design being pasted at the same time!
Design newDesign = null;
// Existing tasks are to be re-used if the paste
// is within the same project as the copy/cut.
Map<AUndertaking, AUndertaking> reuseTasks = null;
Iterator<Object> objIt = objects.iterator();
while (objIt.hasNext()) {
Object o = objIt.next();
// We can paste Design instances; ensure a
// unique name and create and place the design.
if (o instanceof Design) {
newDesign = (Design) o;
makeDesignNameUnique(newDesign);
// Add an undo step after creating/placing
ProjectCmd.addNewDesign(project,
newDesign,
seln.getSelectedDesign(),
presentationName,
editSeq);
numObjectsPasted++;
}
// We can also paste task instances; ensure a
// unique name relative to the TaskGroup (if one)
// or to the Project. Create and place.
else if (o instanceof AUndertaking) {
AUndertaking task = (AUndertaking) o;
// For now, the reuseTasks map will be null
// if pasting a copied design into a different
// project or pasting copied tasks
if (reuseTasks == null) {
pasteTask(task,
taskParent,
index++,
editSeq,
presentationName);
numObjectsPasted++;
}
else {
// In this case, a copied design is
// being pasted into the same project.
// Map each undertaking to the
// corresponding one in the current project
mapProjectTasks(task,
project,
reuseTasks,
editSeq,
presentationName);
}
}
// For now, TaskApplication instances only come
// along when copying an Design.
else if (o instanceof TaskApplication) {
TaskApplication taskApp = (TaskApplication) o;
if (reuseTasks != null) {
AUndertaking reuseTask =
reuseTasks.get(taskApp.getTask());
if (reuseTask != null) {
taskApp.setTask(reuseTask);
}
}
// The undo edit for adding the Design will
// remove and restore the task-applications;
// simply add to the project.
project.setTaskApplication(taskApp);
}
else if (o instanceof CogToolClipboard.ProjectScope)
{
CogToolClipboard.ProjectScope projectScope =
(CogToolClipboard.ProjectScope) o;
// Currently, only reusing tasks if pasting
// a copied design into the same project
if (projectScope.getProject() != null) {
reuseTasks = new HashMap<AUndertaking,
AUndertaking>();
}
}
}
// Done with undo/redo steps; add the compound change
// to the undo manager.
editSeq.end();
undoMgr.addEdit(editSeq);
interaction.setStatusMessage(numObjectsPasted + " "
+ pasteComplete);
}
else {
interaction.setStatusMessage(nothingPasted);
}
return true;
}
catch (IOException e) {
throw new RcvrClipboardException(e);
}
catch (SAXException e) {
throw new RcvrClipboardException(e);
}
catch (ParserConfigurationException e) {
throw new RcvrClipboardException(e);
}
catch (ClipboardUtil.ClipboardException e) {
throw new RcvrClipboardException(e);
}
}
};
} // createPasteAction
// Support for copying design and associated TA's to clipboard
protected void saveDesignToClipboard(Design design, ObjectSaver saver)
{
try {
saver.saveObject(design);
Iterator<AUndertaking> rootTasks =
project.getUndertakings().iterator();
while (rootTasks.hasNext()) {
AUndertaking childTask = rootTasks.next();
saver.saveObject(childTask);
}
Map<ITaskDesign, TaskApplication> associatedTAs =
project.taskApplicationsForDesign(design);
Iterator<TaskApplication> taskApps =
associatedTAs.values().iterator();
while (taskApps.hasNext()) {
TaskApplication ta = taskApps.next();
saver.saveObject(ta);
}
}
catch (IOException ex) {
throw new RcvrClipboardException(ex);
}
}
// Action for CopyDesign
protected IListenerAction createCopyDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState seln = (DesignSelectionState) prms;
Design design = seln.getSelectedDesign();
// Can only copy if a design is currently selected.
if (design != null) {
try {
ObjectSaver s =
CogToolClipboard.startClipboardDesignSave(project,
CogToolClipboard.SAVE_TO_CLIPBOARD);
saveDesignToClipboard(design, s);
s.finish();
interaction.setStatusMessage(DESIGN_COPIED);
return true;
}
catch (IOException e) {
throw new RcvrClipboardException(e);
}
catch (OutOfMemoryError error) {
throw new RcvrOutOfMemoryException("Copying Design", error);
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
}
// Action for CutDesign
protected IListenerAction createCutDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection =
(DesignSelectionState) prms;
Design selectedDesign = selection.getSelectedDesign();
// Can only cut if a design is currently selected.
if (selectedDesign != null) {
if (interaction.confirmDeleteDesign(selectedDesign)) {
try {
ObjectSaver s =
CogToolClipboard.startClipboardDesignSave(project,
CogToolClipboard.SAVE_TO_CLIPBOARD);
// Delete selected design, copying to the clipboard
deleteDesign(selectedDesign, s);
s.finish();
return true;
}
catch (IOException e) {
throw new RcvrClipboardException(e);
}
catch (OutOfMemoryError error) {
throw new RcvrOutOfMemoryException("Cutting Design", error);
}
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
} // createCutDesignAction
protected String buildNextNewDesignName()
{
// Find a unique name to act as the new design's default name
String defaultDesignName = "NewDesign" + nextNewDesignSuffix;
while (project.getDesign(defaultDesignName) != null) {
defaultDesignName = "NewDesign" + ++nextNewDesignSuffix;
}
return defaultDesignName;
}
protected ProjectInteraction.DesignRequestData
requestNewDesignParms(boolean newProjectMode)
{
String defaultDesignName = buildNextNewDesignName();
// Give the user the opportunity to select a name
// and the set of device types the design purports to use.
ProjectInteraction.DesignRequestData requestData =
new ProjectInteraction.DesignRequestData();
requestData.designName = defaultDesignName;
requestData.deviceTypes = new HashSet<DeviceType>();
// TODO: What should be the default set of device types
boolean notDone = true;
// Repeatedly ask the user for the information until the user
// selects a unique name and a non-empty set
// of device types or the user cancels the operation.
while (notDone) {
if (! interaction.requestNewDesignName(requestData,
newProjectMode,
project))
{
return null; // canceled!
}
if (requestData.designName.equals("")) {
if (! interaction.protestEmptyDesignName()) {
return null;
}
}
else if (requestData.deviceTypes.isEmpty()) {
if (! interaction.protestNoDeviceTypes()) {
return null;
}
}
else if (project.getDesign(requestData.designName) != null) {
if (! interaction.protestNotUniqueDesignName()) {
return null;
}
}
else {
// If the user used the default name, indicate
// that the next suffix should be tried first.
if (requestData.designName.equals(defaultDesignName)) {
nextNewDesignSuffix++;
}
notDone = false;
}
}
return requestData;
}
protected boolean createNewDesign(Object prms, boolean newProjectMode)
{
DesignSelectionState selection = (DesignSelectionState) prms;
ProjectInteraction.DesignRequestData requestData =
requestNewDesignParms(newProjectMode);
if (requestData == null) {
return false; // canceled!
}
// Create the new design and insert before the
// selected design, if any.
createNewDesign(requestData.designName,
requestData.deviceTypes,
selection);
return true;
} // createNewDesign
// Action for NewDesign
protected IListenerAction createNewDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
return createNewDesign(prms, false);
}
};
} // createNewDesignAction
// Action for NewDesign2, createNewDesignForImport
protected IListenerAction createNewDesignForImport()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
// return Class.class;
}
public boolean performAction(Object prms)
{
//call convert on the converter file
Class<ImportConverter> translatorClass = CogToolLID.NewDesignFromImport.getClassAttribute();
//CogToolLID.NewDesignFromImport.setClassAttribute(null);
Object converter = null;
try {
converter = translatorClass.newInstance();
}
catch (InstantiationException e) {
throw new RcvrImportException("Translator class cannot be instantiated.");
}
catch (IllegalAccessException e) {
throw new RcvrImportException("The translator class is not accessible.");
}
Design design = null;
Method isInputFileDirectory = null;
try {
isInputFileDirectory = translatorClass.getMethod("isInputFileDirectory", new Class[0]);
}
catch (SecurityException e) {
throw new RcvrImportException("The security manager does not allow access to this method.");
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
throw new RcvrImportException("isInputFileDirectory does not exist in the converter file.");
}
boolean reqDir = false;
try {
reqDir = (Boolean)isInputFileDirectory.invoke(converter);
}
catch (IllegalArgumentException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
catch (IllegalAccessException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
catch (InvocationTargetException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
//parameters needed to be passed to importDesign. A file and design are passed.
Class<?>[] parameters = new Class<?>[2];
parameters[0] = File.class;
parameters[1] = Design.class;
Method importDesignMethod = null;
try {
importDesignMethod = translatorClass.getMethod("importDesign", parameters);
}
catch (SecurityException e) {
throw new RcvrImportException("The security manager does not allow access to this method.");
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String designName = "";
/*Instead of a inputFile, a directory was specified. Every file in the directory
needs to be parsed */
Method allowedExtsMethod = null;
try {
allowedExtsMethod = translatorClass.getMethod("allowedExtensions", new Class[0]);
}
catch (SecurityException e) {
throw new RcvrImportException("The security manager does not allow access to this method.");
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String[] extensions = null;
try {
extensions = (String[]) allowedExtsMethod.invoke(converter);
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(reqDir)
{
/*TODO: Need to confirm that directory name is guaranteed to only accept a directory*/
String directoryName = interaction.askUserForDirectory("Choose a directory of files", "This directory contains the files that you wish to import.");
if(directoryName != null)
{
File directory = new File(directoryName);
if(directory != null)
{
//TODO: What to do about importing it twice, designName [2];
designName = directory.getName();
Set<DeviceType> deviceTypeSet = new HashSet<DeviceType>();
Method selectedDevicesMethod = null;
try {
selectedDevicesMethod = translatorClass.getMethod("selectedDevices", new Class[0]);
}
catch (SecurityException e) {
throw new RcvrImportException("The security manager does not allow access to this method.");
}
catch (NoSuchMethodException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
deviceTypeSet = (Set<DeviceType>) selectedDevicesMethod.invoke(converter);
}
catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (InvocationTargetException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ProjectInteraction.DesignRequestData requestData =
new ProjectInteraction.DesignRequestData();
requestData.designName = designName;
requestData.deviceTypes = deviceTypeSet;
//TODO: may need to keep checking the value that this returns
interaction.requestNewDesignName(requestData,
false,
project, false);
design = new Design(requestData.designName, requestData.deviceTypes);
makeDesignNameUnique(design);
// Collection<DeviceType> deviceTypes = (Collection<DeviceType>)
// designLoader.createCollection(design, Design.deviceTypesVAR, 1);
// Collection<?> frames =
//designLoader.createCollection(design, Design.framesVAR, 1);
File[] directoryContents = directory.listFiles();
for (File file : directoryContents) {
String fileName = file.getName();
//If there is no extension then null is the file extension
String fileExt = (fileName.lastIndexOf(".") == -1) ? null:
fileName.substring(fileName.lastIndexOf('.'));
//removes the '.' from the extension.
//Example: ".txt" will now be "txt" and . will now be ""
if(fileExt != null){
fileExt = (fileExt.length()) > 1 ? fileExt = fileExt.substring(1):
"";
}
for (String extension : extensions) {
if(extension == null || extension.equalsIgnoreCase(fileExt))
{
try {
importDesignMethod.invoke(converter, file, design);
break;
/* Break is needed if the converter author placed the same
* extension in the array twice then this conversion will
* not occur more than once. */
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e) {
//throw new RcvrImportXmlException("Not a valid XML file to parse.");
//ignore
System.out.println("fileName " + fileName);
break;
}
}
}
}
}
}
}
else
{
File importFile = interaction.selectFile(true, null, extensions);
try {
designName = importFile.getName();
//TODO: ask user for design name since it can be different from the filename
Set<DeviceType> deviceTypeSet = new HashSet<DeviceType>();
design = new Design(designName, deviceTypeSet);
makeDesignNameUnique(design);
//Collection<DeviceType> deviceTypes = (Collection<DeviceType>)
//designLoader.createCollection(design, Design.deviceTypesVAR, 1);
//Collection<?> frames =
// designLoader.createCollection(design, Design.framesVAR, 1);
System.out.println("design " + design.getName());
importDesignMethod.invoke(converter,importFile, design);
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//change inputfile to the specific file
}
if( design != null)
{
ProjectCmd.addNewDesign(project,
design,
((DesignSelectionState)prms).getSelectedDesign(),
NEW_DESIGN,
undoMgr);
}
// Test to see if all of the names are unique
//testDesign(project, design);
return true;
}
};
} // createNewDesignAction2
protected IListenerAction createAddDesignDevicesAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection =
(DesignSelectionState) prms;
Design design = selection.getSelectedDesign();
if (design != null) {
return DesignCmd.addDevices(project, design, interaction);
}
interaction.protestNoSelection();
return true;
}
};
}
// Action for NameProjectNewDesign
protected IListenerAction createNameProjectNewDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
return createNewDesign(prms, true);
}
};
} // createNameProjectNewDesignAction
/**
* Interact with the user to solicit a new name for an
* <code>Design</code>. The new name must be unique and not be empty.
*
* @param selectedDesign the design to rename
* @author mlh
*/
protected boolean interactToRenameDesign(Design selectedDesign)
{
String oldDesignName = selectedDesign.getName();
String designName = oldDesignName;
// Repeatedly ask the user for a new name until the user
// cancels or specifies a non-empty name that is unique.
while (true) {
designName = interaction.requestDesignRename(designName);
if (designName == null) {
return false; // canceled!
}
if (designName.equals("")) {
if (interaction.protestEmptyDesignName()) {
designName = oldDesignName;
}
else {
return false;
}
}
else if (designName.equals(oldDesignName) ||
(project.getDesign(designName) == null))
{
renameDesign(selectedDesign,
oldDesignName,
designName);
return true;
}
else if (! interaction.protestNotUniqueDesignName()) {
return false;
}
}
// If one ever gets here, uncomment the next line (Java!!)
// return false;
}
/**
* Interact with the user to solicit a new name for an
* <code>AUndertaking</code>. The new name must not be empty and must be
* unique within the <code>TaskGroup</code> that contains the given task
* or, if not a child, unique among the top-level tasks for the
* <code>Project</code>.
* <p>
* For a task that is an <code>TaskGroup</code>, the user is also
* allowed to change the group's <code>GroupNature</code>.
* <p>
* Currently unused.
*
* @param selectedDesign the design to rename
* @author mlh
*/
protected boolean interactToRenameTask(AUndertaking selectedTask,
TaskSelectionState selection)
{
String oldTaskName = selectedTask.getName();
ProjectInteraction.TaskRequestData requestData =
new ProjectInteraction.TaskRequestData();
requestData.taskName = oldTaskName;
requestData.flags = ProjectInteraction.TaskRequestData.ASK_NOTHING;
GroupNature oldNature = GroupNature.MEAN;
// If an TaskGroup, allow the user to specify a new GroupNature.
if (selectedTask.isTaskGroup()) {
requestData.flags = ProjectInteraction.TaskRequestData.ASK_NATURE;
oldNature = ((TaskGroup) selectedTask).getNature();
}
requestData.nature = oldNature;
// Repeatedly ask the user for a new name until the user
// cancels or specifies a non-empty name that is unique.
while (true) {
if (! interaction.requestNewTaskName(requestData)) {
return false; // canceled!
}
if (requestData.taskName.equals("")) {
if (! interaction.protestEmptyTaskName()) {
return false;
}
}
else {
TaskGroup parent = selection.getSelectedTaskParent();
if (isTaskNameUnique(requestData.taskName,
oldTaskName,
parent))
{
if (selectedTask.isTaskGroup() &&
(requestData.nature != oldNature))
{
modifyTaskGroup((TaskGroup) selectedTask,
oldTaskName,
requestData.taskName,
oldNature,
requestData.nature);
return true;
}
return renameTask(selectedTask,
oldTaskName,
requestData.taskName,
parent);
}
else {
if (! interaction.protestNotUniqueTaskName()) {
return false;
}
}
}
}
// If one ever gets here, uncomment the next line (Java!!)
// return false;
} // interactToRenameTask
// Action for EditDesign
protected IListenerAction createEditDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection =
(DesignSelectionState) prms;
// FrameUIModel.LoadingTime = 0;
// long start = System.currentTimeMillis();
// System.out.println("\nEditDesign:" + start + " { ");
Design selectedDesign = selection.getSelectedDesign();
// Can only edit a selected design.
if (selectedDesign != null) {
// Open or create a window for the selected design
DesignEditorController.openController(selectedDesign,
project);
return true;
}
interaction.protestNoSelection();
// long end = System.currentTimeMillis();
// System.out.println("\n" + (end-start) + " } " + end);
// System.out.println(FrameUIModel.LoadingTime);
return false;
}
};
} // createEditDesignAction
// Action for RenameDesign
protected IListenerAction createRenameDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection =
(DesignSelectionState) prms;
Design selectedDesign = selection.getSelectedDesign();
// Can only rename a selected design.
if (selectedDesign != null) {
return interactToRenameDesign(selectedDesign);
}
interaction.protestNoSelection();
return false;
}
};
} // createRenameDesignAction
// Action for CopyTask
protected IListenerAction createCopyTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState seln = (TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
// Can only copy to clipboard if one or more tasks are selected
if ((tasks != null) && (tasks.length > 0)) {
try {
ObjectSaver s =
CogToolClipboard.startClipboardSave(CogToolClipboard.CopyTasks,
CogToolClipboard.SAVE_TO_CLIPBOARD);
for (AUndertaking task : tasks) {
s.saveObject(task);
}
s.finish();
if (tasks.length == 1) {
interaction.setStatusMessage(TASK_COPIED);
}
else {
interaction.setStatusMessage(TASKS_COPIED);
}
return true;
}
catch (IOException e) {
throw new RcvrClipboardException(e);
}
catch (OutOfMemoryError error) {
throw new RcvrOutOfMemoryException("Copying Tasks", error);
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
}
// Action for CutTask
protected IListenerAction createCutTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
AUndertaking[] selectedTasks =
selection.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
// Can only cut if one or more tasks are currently selected.
if ((selectedTasks != null) && (selectedTasks.length > 0)) {
try {
ObjectSaver saver =
CogToolClipboard.startClipboardSave(CogToolClipboard.CopyTasks,
CogToolClipboard.SAVE_TO_CLIPBOARD);
deleteTasks(selectedTasks, saver, undoMgr);
saver.finish(); // flush!
return true;
}
catch (IOException e) {
throw new RcvrClipboardException("Could not execute cut",
e);
}
catch (OutOfMemoryError error) {
throw new RcvrOutOfMemoryException("Cutting Tasks", error);
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
} // createCutTaskAction
// Action for InitiateTaskRename
protected IListenerAction createInitiateTaskRenameAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
int selectedTaskCount = selection.getSelectedTaskCount();
// Can only rename interactively if a single task is selected
// No need, therefore, to prune the task list!
if (selectedTaskCount == 1) {
ui.initiateTaskRename(selection.getSelectedTask());
return true;
}
if (selectedTaskCount == 0) {
interaction.protestNoSelection();
}
else {
interaction.protestTooManySelectedTasks();
}
return false;
}
};
} // createInitiateTaskRenameAction
// Action for DeleteDesign
protected IListenerAction createDeleteDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection =
(DesignSelectionState) prms;
Design selectedDesign = selection.getSelectedDesign();
// Can only delete if a design is currently selected.
if (selectedDesign != null) {
if (interaction.confirmDeleteDesign(selectedDesign)) {
// Delete selected design, without copying
// to the clipboard.
deleteDesign(selectedDesign, null);
return true;
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
} // createDeleteDesignAction
// Action for DeleteTask
protected IListenerAction createDeleteTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
AUndertaking[] selectedTasks =
selection.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
// Can only delete if one or more tasks are currently selected.
if ((selectedTasks != null) && (selectedTasks.length > 0)) {
if (interaction.confirmDeleteTasks(selectedTasks)) {
// Delete tasks without copying to the clipboard.
deleteTasks(selectedTasks, null, undoMgr);
return true;
}
}
else {
interaction.protestNoSelection();
}
return false;
}
};
} // createDeleteTaskAction
/**
* The semantic application action to create a new <code>Design</code>
* instance with the given name and device types and add it to the project
* at the position determined by the currently selected design, if one.
* If no currently selected design, the new design is placed at the end.
* Also adds the appropriate undo/redo to the controller's undo manager.
* <p>
* The name for the new design should already have been checked to be
* non-empty and unique. The set of device types should have been checked
* to be non-null and non-empty.
*
* @param newDesignName name for the new design
* @param deviceTypes the set of device types for the design
* @param selection the currently selected design that determines the new
* design's position in the project
* @author mlh
*/
protected void createNewDesign(String newDesignName,
Set<DeviceType> deviceTypes,
DesignSelectionState selection)
{
Design design = new Design(newDesignName, deviceTypes);
Frame frame = new Frame(DesignEditorController.INITIAL_FRAME_NAME,
design.getDeviceTypes());
frame.setFrameOrigin(16.0, 16.0);
design.addFrame(frame);
// Add design to project, then add undo/redo step to the undo manager
ProjectCmd.addNewDesign(project,
design,
selection.getSelectedDesign(),
NEW_DESIGN,
undoMgr);
}
protected void recoverScriptManagers(Map<ITaskDesign, TaskApplication> associatedTAs,
boolean stopTrackingEdits)
{
UndoManagerRecovery.recoverScriptManagers(project,
associatedTAs,
stopTrackingEdits);
}
protected void recoverManagers(AUndertaking undertaking,
Map<ITaskDesign, TaskApplication> associatedTAs)
{
UndoManagerRecovery.recoverScriptManagers(project,
associatedTAs,
true);
}
protected void recoverManagers(Design design,
Map<ITaskDesign, TaskApplication> associatedTAs)
{
UndoManagerRecovery.recoverManagers(project,
design,
associatedTAs);
FrameTemplateSupport.clearFrameTemplate(design);
}
protected void recoverManagers(TaskApplication taskApp)
{
UndoManagerRecovery.recoverScriptManagers(project, taskApp, true);
}
/**
* The semantic application action to rename a given design from the given
* "old" name to the given "new" name.
* Adds the appropriate undo/redo to the controller's undo manager.
*
* @param renamedDesign the design to rename
* @param oldDesignName the design's old name
* @param newDesignName the desired new name for the design
* @author mlh
*/
protected void renameDesign(final Design renamedDesign,
final String oldDesignName,
final String newDesignName)
{
// Nothing need be done if the two names are identical (ie, no change)
if (! newDesignName.equals(oldDesignName)) {
renamedDesign.setName(newDesignName);
// Create undo/redo step and add to the undo manager
undoMgr.addEdit(new AUndoableEdit(ProjectLID.RenameDesign)
{
@Override
public String getPresentationName()
{
return RENAME_DESIGN;
}
@Override
public void redo()
{
super.redo();
renamedDesign.setName(newDesignName);
}
@Override
public void undo()
{
super.undo();
renamedDesign.setName(oldDesignName);
}
});
}
}
/**
* Delete the specified design from the project, copying to the
* clipboard if an <code>ObjectSaver</code> is provided.
*
* @param designToDelete design to delete
* @param saver the clipboard's saver to hold the copied design
* @throw java.io.IOException if saving a copy to the clipboard fails
* @author mlh
*/
protected void deleteDesign(final Design designToDelete,
ObjectSaver saver)
{
// Find the location of the design to delete
final int designIndex =
project.getDesigns().indexOf(designToDelete);
// Delete the design, saving a copy to the clipboard if requested
project.removeDesign(designToDelete);
if (saver != null) {
saveDesignToClipboard(designToDelete, saver);
}
// Create undo/redo step and add to the undo manager
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.DeleteDesign)
{
// Save any associated ITaskApplications for undo restoration
protected Map<ITaskDesign, TaskApplication> associatedTAs =
project.taskApplicationsForRemovedDesign(designToDelete);
protected boolean recoverMgr = true;
@Override
public String getPresentationName()
{
return DELETE_DESIGN;
}
@Override
public void redo()
{
super.redo();
recoverMgr = true;
associatedTAs =
project.taskApplicationsForRemovedDesign(designToDelete);
project.removeDesign(designToDelete);
}
@Override
public void undo()
{
super.undo();
recoverMgr = false;
project.addDesign(designIndex, designToDelete);
project.restoreRemovedTaskApplications(associatedTAs);
}
@Override
public void die()
{
super.die();
if (recoverMgr) {
recoverManagers(designToDelete, associatedTAs);
}
}
};
undoMgr.addEdit(edit);
} // deleteDesign
protected String computeNewTaskName(TaskParent parent, String base)
{
String newTaskName;
int nextNewTaskSuffix = 0;
// Check for duplicate name
do {
newTaskName = base + " " + ++nextNewTaskSuffix;
} while (parent.getUndertaking(newTaskName) != null);
return newTaskName;
}
// Action for NewTask
protected IListenerAction createNewTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
// Figure out what the selection is
AUndertaking[] selectedTasks =
selection.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
Task newTask = null;
if ((selectedTasks == null) || (selectedTasks.length == 0)) {
// No task selection -- add a new root task
String newTaskName =
computeNewTaskName(project, DEFAULT_TASK_PREFIX);
newTask = addTask(project,
project.getUndertakings().size(),
newTaskName);
}
else {
// At least one selected task: add a new sibling after
// Multiple selected tasks:
// if all tasks have same parent,
// add new sibling after last selection
// if tasks do not have same parent,
// add new root task after last selected root
// but, if no selected root, add new root at end
// Get parent
TaskGroup parent = selection.getSelectedTaskParent();
if (parent == null) {
String newTaskName =
computeNewTaskName(project, DEFAULT_TASK_PREFIX);
newTask = addTask(project,
findLastSelectedRoot(selectedTasks),
newTaskName);
}
else {
String newTaskName =
computeNewTaskName(parent, DEFAULT_TASK_PREFIX);
AUndertaking last =
selectedTasks[selectedTasks.length - 1];
newTask =
addTask(parent,
parent.getUndertakings().indexOf(last) + 1,
newTaskName);
}
}
// Task is automatically selected when added -- rename
// Cannot put this into the ui because of undo/redo
ui.initiateTaskRename(newTask);
return true;
}
};
} // createNewTaskAction
/**
* Search backwards through list of selected tasks for a selected root
* task and return the next index.
*
* @param selectedTasks an array of the selected tasks
* @return the index one greater than the selected root task with the
* highest index, if any exists, otherwise the number of root
* undertakings
*/
protected int findLastSelectedRoot(AUndertaking[] selectedTasks)
{
for (int i = selectedTasks.length - 1; i >= 0; i--) {
AUndertaking task = selectedTasks[i];
if (task.getTaskGroup() == null) {
return project.getUndertakings().indexOf(task) + 1;
}
}
return project.getUndertakings().size();
}
/**
* Add a new task to a task group. Assign its position based on the
* given task, or at the beginning if the given task is <code>null</code>.
* Returns the created task.
* Also adds the appropriate undo/redo to the controller's undo manager.
*
* @param parent the task group where the task will be added
* @param atIndex the index at which to place the task
* @param newTaskName the name for the new task
* @param lid the undo/redo command token
* @param presentationName the undo/redo command label
* @param editSeq the undo/redo sequence to hold the new edit
*/
protected Task addTask(TaskParent parent,
int atIndex,
String newTaskName,
CogToolLID lid,
String presentationName,
IUndoableEditSequence editSeq)
{
// Create task and add to the task group
Task newTask = new Task(newTaskName);
parent.addUndertaking(atIndex, newTask);
// Create undo/redo step and add to the undo manager
editSeq.addEdit(createNewTaskUndo(parent,
atIndex,
newTask,
lid,
presentationName));
return newTask;
}
protected Task addTask(TaskParent parent, int atIndex, String newTaskName)
{
return addTask(parent,
atIndex,
newTaskName,
ProjectLID.NewTask,
NEW_TASK,
undoMgr);
}
/**
* Utility to create an undo/redo step for adding a task
* to either a task group or at the top-level in the project, if the
* given parent is <code>null</code>.
*
* @param parent the task group to add the task to, or <code>null</code>
* if the task is to be added to the project
* @param newTask the new task to be added
* @param lid the ListenerIdentifier of the action needing undoable edit
* @param presentationName the undo/redo label
* @return the undo/redo support for this change suitable for inserting
* into a compound undo edit or the undo manager
*/
protected IUndoableEdit createNewTaskUndo(final TaskParent parent,
final int atIndex,
final AUndertaking newTask,
CogToolLID lid,
final String presentationName)
{
return new AUndoableEdit(lid)
{
protected Map<ITaskDesign, TaskApplication> associatedTAs = null;
protected boolean recoverMgrs = false;
@Override
public String getPresentationName()
{
return presentationName;
}
@Override
public void redo()
{
super.redo();
recoverMgrs = false;
parent.addUndertaking(atIndex, newTask);
if (associatedTAs != null) {
project.restoreRemovedTaskApplications(associatedTAs);
}
}
@Override
public void undo()
{
super.undo();
recoverMgrs = true;
associatedTAs =
project.taskApplicationsForRemovedTask(newTask);
parent.removeUndertaking(newTask);
}
@Override
public void die()
{
super.die();
if (recoverMgrs) {
recoverManagers(newTask, associatedTAs);
}
}
};
} // createNewTaskUndo
// Action for NewTaskGroup
protected IListenerAction createNewTaskGroupAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState selection =
(TaskSelectionState) prms;
// Figure out what the selection is
AUndertaking[] selectedTasks =
selection.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
TaskGroup newGroup = null;
if ((selectedTasks == null) || (selectedTasks.length == 0)) {
String newGroupName =
computeNewTaskName(project, DEFAULT_TASK_GROUP_PREFIX);
// No task selection -- add a new root task group
newGroup = addTaskGroup(project,
project.getUndertakings().size(),
newGroupName,
selectedTasks);
}
else {
// One selected task: create new group at selected position
// Multiple selected tasks:
// if all tasks have same parent,
// create new group after last selection
// if tasks do not have same parent,
// add new root group after last selected root
// but, if no selected root, new root at end
// Get parent
TaskGroup parent = selection.getSelectedTaskParent();
if (parent == null) {
String newGroupName =
computeNewTaskName(project,
DEFAULT_TASK_GROUP_PREFIX);
newGroup =
addTaskGroup(project,
findLastSelectedRoot(selectedTasks),
newGroupName,
selectedTasks);
}
else {
String newGroupName =
computeNewTaskName(parent,
DEFAULT_TASK_GROUP_PREFIX);
AUndertaking last =
selectedTasks[selectedTasks.length - 1];
newGroup =
addTaskGroup(parent,
parent.getUndertakings().indexOf(last) + 1,
newGroupName,
selectedTasks);
}
}
// Task is automatically selected when added -- rename
// Cannot put this into the ui because of undo/redo
ui.initiateTaskRename(newGroup);
return true;
}
};
} // createNewTaskGroupAction
/**
* Add a new task group inside an existing task group.
*
* @param parent the task parent where the task will be added
* @param prev the task immediately before the position
* of the new task group (or null for first position)
* @param selection tasks to be moved into new group as children
* @param lid the undo/redo command token
* @param presentationName the undo/redo command label
* @param editSeq the undo/redo sequence to hold the new edit
* @return created and added task group
*/
protected TaskGroup addTaskGroup(TaskParent parent,
int atIndex,
String newGroupName,
AUndertaking[] children,
CogToolLID lid,
String presentationName,
IUndoableEditSequence editSeq)
{
TaskGroup newGroup = new TaskGroup(newGroupName, GroupNature.SUM);
// Add to parent at index
parent.addUndertaking(atIndex, newGroup);
TaskParent[] oldParents = new TaskParent[children.length];
int[] indexes = new int[children.length];
// Move children & create undo
removeChildTasks(children, oldParents, indexes);
addToTaskGroup(children, newGroup);
// Create undo/redo step and add to undo manager
editSeq.addEdit(createNewTaskGroupUndo(parent, atIndex, newGroup,
oldParents, indexes, children,
lid, presentationName));
return newGroup;
}
protected TaskGroup addTaskGroup(TaskParent parent,
int atIndex,
String newGroupName,
AUndertaking[] children)
{
return addTaskGroup(parent,
atIndex,
newGroupName,
children,
ProjectLID.NewTaskGroup,
NEW_TASK_GROUP,
undoMgr);
}
/**
* Remove child tasks, recording their old parents and indexes
* of each child in their respective parent. To restore,
* add back to the old parents in reverse.
* <p>
* Fills in the oldParents and indexes arrays only if not <code>null</code>.
* <p>
* It is assumed that the oldParents and indexes arrays are the
* exact same size as the children array.
*
* @param children the tasks to be removed
* @param oldParents if not <code>null</code>, to hold the corresponding
* parent for each removed task
* @param indexes if not <code>null</code>, to hold the index of
* each removed task in its corresponding parent
* @author mlh
*/
protected void removeChildTasks(AUndertaking[] children,
TaskParent[] oldParents,
int[] indexes)
{
for (int i = 0; i < children.length; i++) {
TaskParent parent = project.getTaskParent(children[i]);
// Save old index for undo
if (indexes != null) {
indexes[i] = parent.getUndertakings().indexOf(children[i]);
}
// Remove from old parent
parent.removeUndertaking(children[i]);
if (oldParents != null) {
oldParents[i] = parent;
}
}
}
/**
* Re-parent each given child task to the given new task group.
*
* @param children the tasks to be re-parented
* @param newGroup the new parent for the given child tasks
*/
protected void addToTaskGroup(AUndertaking[] children, TaskGroup newGroup)
{
// Add to new parent
for (AUndertaking element : children) {
newGroup.addUndertaking(element);
}
}
/**
* Create the undo/redo step for the placement of a new task group and
* the re-parenting of the selected tasks into the new task group.
*
* @param parent the parent task group (or project if null) for the
* new task group
* @param index the location for inserting the new task group into
* the parent
* @param taskGroup the new task group itself
* @param oldParents the corresponding parent task parents for the given
* child tasks
* @param indexes the insertion index of each child in its old parent for
* use in undo
* @param children the tasks to be re-parented
* @param lid the undo/redo command token
* @param presentationName the undo/redo edit label
* @return the undo/redo step for the placement of the new task group and
* the re-parenting of the selected tasks into the new task group
*/
protected IUndoableEdit createNewTaskGroupUndo
(final TaskParent parent,
final int index,
final TaskGroup taskGroup,
final TaskParent[] oldParents,
final int[] indexes,
final AUndertaking[] children,
CogToolLID lid,
final String presentationName)
{
return new AUndoableEdit(lid)
{
@Override
public String getPresentationName()
{
return presentationName;
}
@Override
public void redo()
{
super.redo();
// Add new group
parent.addUndertaking(index, taskGroup);
// Move children
removeChildTasks(children, null, null);
addToTaskGroup(children, taskGroup);
}
@Override
public void undo()
{
super.undo();
// Un-move children; IMPORTANT: reverse order!
for (int i = children.length - 1; 0 <= i; i--) {
// Remove from new group
taskGroup.removeUndertaking(children[i]);
// Add to old parent at old index
oldParents[i].addUndertaking(indexes[i], children[i]);
}
// Remove new group
parent.removeUndertaking(taskGroup);
}
};
} // createNewTaskGroupUndo
/**
* Test whether the given new task name is unique given the selected task's
* parent's scope. If the name hasn't changed, it is assumed that it is
* still unique.
*
* @param newTaskName the new task name
* @param oldTaskName the renamed task's old name
* @param parent the name scope; if <code>null</code>, the project is
* the scope.
* @return true if and only if the new name is unique with the name scope
* @author mlh
*/
protected boolean isTaskNameUnique(String newTaskName,
String oldTaskName,
TaskParent parent)
{
// System.out.println("old: " + oldTaskName + " new: " + newTaskName);
if (newTaskName.equals(oldTaskName)) {
return true;
}
return (parent != null)
? (parent.getUndertaking(newTaskName) == null)
: (project.getUndertaking(newTaskName) == null);
}
/**
* The semantic application action to rename the given selected task from
* the "old" name to the given "new" name.
* Adds the appropriate undo/redo to the controller's undo manager.
*
* @param renamedTask the task to rename
* @param newTaskName the new task name
* @param oldTaskName the renamed task's old name
* @param parent the name scope; if <code>null</code>, the project is
* the scope.
* @author mlh
*/
protected boolean renameTask(final AUndertaking renamedTask,
final String oldTaskName,
final String newTaskName,
TaskGroup parent)
{
// Check if newTaskName is empty; retry if user desires
if (newTaskName.length() == 0) {
if (interaction.protestEmptyTaskName()) {
ui.initiateTaskRename(renamedTask);
return true;
}
return false;
}
// Check uniqueness of new name; if not, complain
if (isTaskNameUnique(newTaskName, oldTaskName, parent)) {
// If renaming a group, use modifyTaskGroup
if (renamedTask.isTaskGroup()) {
TaskGroup group = (TaskGroup) renamedTask;
// Just a rename; not changing nature
modifyTaskGroup(group,
oldTaskName,
newTaskName,
group.getNature(),
group.getNature());
}
else if (! newTaskName.equals(oldTaskName)) {
// Rename only if the name has changed
renamedTask.setName(newTaskName);
// Create undo/redo step and add to undo manager
undoMgr.addEdit(new AUndoableEdit(ProjectLID.RenameTask)
{
@Override
public String getPresentationName()
{
return RENAME_TASK;
}
@Override
public void redo()
{
super.redo();
renamedTask.setName(newTaskName);
}
@Override
public void undo()
{
super.undo();
renamedTask.setName(oldTaskName);
}
});
}
return true;
}
// Not unique; complain and retry if user desires
if (interaction.protestNotUniqueTaskName()) {
ui.initiateTaskRename(renamedTask);
return true;
}
return false;
} // renameTask
/**
* Utility to modify a task that is a group, modifying both its name
* and its nature.
*
* @param modifiedTaskGroup group to modify
* @param oldTaskName the old name
* @param newTaskName the new name
* @param oldNature the old computational nature of the group's subtasks
* @param newNature the new computational nature of the group's subtasks
*/
protected void modifyTaskGroup(final TaskGroup modifiedTaskGroup,
final String oldTaskName,
final String newTaskName,
final GroupNature oldNature,
final GroupNature newNature)
{
// Rename only if the name or nature has changed
if ((! newTaskName.equals(oldTaskName)) || (oldNature != newNature)) {
modifiedTaskGroup.setName(newTaskName);
modifiedTaskGroup.setNature(newNature);
// Create undo/redo step and add to undo manager
undoMgr.addEdit(new AUndoableEdit(ProjectLID.EditTask)
{
@Override
public String getPresentationName()
{
return RENAME_TASK_GROUP;
}
@Override
public void redo()
{
super.redo();
modifiedTaskGroup.setName(newTaskName);
modifiedTaskGroup.setNature(newNature);
}
@Override
public void undo()
{
super.undo();
modifiedTaskGroup.setName(oldTaskName);
modifiedTaskGroup.setNature(oldNature);
}
});
}
} // modifyTaskGroup
/**
* Utility to delete the specified tasks.
* If an object saver is specified (that is, not <code>null</code>),
* the deleted tasks are serialized as well.
*
* @param tasksToDelete the subtasks to delete
* @param saver if not null, the saver to use for serializing the
* deleted tasks (used saving to the system clipboard for the
* "cut" action)
* @param editSequence to hold the undoable edit
* @throws RcvrClipboardException if the saver is given and serialization
* failed for some reason; NOTE!!! Delete will have succeeded!
* @author mlh
*/
protected void deleteTasks(final AUndertaking[] tasksToDelete,
ObjectSaver saver,
IUndoableEditSequence editSequence)
{
@SuppressWarnings("unchecked")
final Map<ITaskDesign, TaskApplication>[] assocTAs =
new Map[tasksToDelete.length];
RcvrClipboardException firstException = null;
// Delete each task and serialize if desired
for (int i = 0; i < tasksToDelete.length; i++) {
assocTAs[i] =
project.taskApplicationsForRemovedTask(tasksToDelete[i]);
if (saver != null) {
try {
saver.saveObject(tasksToDelete[i]);
}
catch (IOException ex) {
if (firstException != null) {
firstException =
new RcvrClipboardException("Could not save object"
+ " to clipboard.",
ex);
}
}
}
}
final TaskParent[] oldParents = new TaskParent[tasksToDelete.length];
final int[] indexes = new int[tasksToDelete.length];
removeChildTasks(tasksToDelete, oldParents, indexes);
// Create undo/redo step and add to undo manager
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.DeleteTask)
{
protected Map<ITaskDesign, TaskApplication>[] associatedTAs = assocTAs;
protected boolean recoverMgrs = true;
@Override
public String getPresentationName()
{
return (tasksToDelete.length > 1) ? DELETE_TASKS
: DELETE_TASK;
}
@Override
public void redo()
{
super.redo();
recoverMgrs = true;
for (int i = 0; i < tasksToDelete.length; i++) {
associatedTAs[i] =
project.taskApplicationsForRemovedTask(tasksToDelete[i]);
}
removeChildTasks(tasksToDelete, null, null);
}
@Override
public void undo()
{
super.undo();
recoverMgrs = false;
// Un-delete children; IMPORTANT: reverse order!
for (int i = tasksToDelete.length - 1; 0 <= i; i--) {
// Add to old parent at old index
oldParents[i].addUndertaking(indexes[i],
tasksToDelete[i]);
project.restoreRemovedTaskApplications(associatedTAs[i]);
}
}
@Override
public void die()
{
super.die();
if (recoverMgrs) {
for (int i = 0; i < tasksToDelete.length; i++) {
recoverManagers(tasksToDelete[i],
associatedTAs[i]);
}
}
}
};
editSequence.addEdit(edit);
if (firstException != null) {
throw firstException;
}
} // deleteTasks
protected TaskApplication ensureTaskApplication(AUndertaking task,
Design design,
CognitiveModelGenerator gen)
{
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
return ensureTaskApplication(task, design, gen, demoMgr);
}
protected TaskApplication ensureTaskApplication(AUndertaking task,
Design design,
CognitiveModelGenerator gen,
DemoStateManager demoMgr)
{
return DemoStateManager.ensureTaskApplication(project,
task,
design,
gen,
demoMgr);
}
// Action for EditScript
protected IListenerAction createScriptEditorAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
if (prms != null) {
ProjectSelectionState seln =
(ProjectSelectionState) prms;
// Must have selected tasks and design
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
if ((design == null) ||
(tasks == null) ||
(tasks.length == 0))
{
return false;
}
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
// Editing a script only applies to tasks, not task groups
for (int i = 0; i < tasks.length; i++) {
if (! tasks[i].isTaskGroup()) {
CognitiveModelGenerator gen = MODELGEN_ALG;
TaskGroup group = tasks[i].getTaskGroup();
if (group != null) {
Object isSnifAct =
group.getAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR);
if (isSnifAct != null) {
gen = IdentityModelGenerator.ONLY;
}
}
// If no script set exists for this cell, create
TaskApplication ta =
ensureTaskApplication(tasks[i],
design,
gen,
demoMgr);
Demonstration demo = ta.getDemonstration();
if (CogToolPref.HCIPA.getBoolean()) {
HCIPACmd.checkStartFrame(project,
ta,
gen);
}
// Determine which window to open/create
if ((demo.getStartFrame() == null) ||
! demo.isStartFrameChosen())
{
// No start frame; present ui to choose one
SEFrameChooserController.
openController(ta,
gen,
project);
}
else {
// Start frame chosen; go straight to demo ui
try {
SEDemoController.
openController(ta,
gen,
project);
}
catch (GraphicsUtil.ImageException ex) {
interaction.protestInvalidImageFile();
}
}
}
// Else do nothing when a TaskGroup cell is "edited"
}
return true;
}
interaction.protestNoSelection();
return false;
}
};
}
// Action for ShowSum, ShowMean, ShowMin, and ShowMax
protected IListenerAction createShowNatureAction(final GroupNature nature,
final CogToolLID lid)
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
if (prms != null) {
final List<TaskGroup> groups = new ArrayList<TaskGroup>();
final List<GroupNature> oldNatures =
new ArrayList<GroupNature>();
TaskSelectionState seln =
(TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.FAST_SELECTION);
// Change applies only to task group instances
for (AUndertaking task : tasks) {
if (task.isTaskGroup()) {
TaskGroup group = (TaskGroup) task;
GroupNature oldNature = group.getNature();
// If a change for this group, modify and
// record old value for undo support
if (oldNature != nature) {
oldNatures.add(oldNature);
groups.add(group);
group.setNature(nature);
}
}
}
// If any groups were actually modified, create
// undo/redo step and add to undo manager
if (groups.size() > 0) {
undoMgr.addEdit(new AUndoableEdit(lid) {
@Override
public String getPresentationName()
{
return CHANGE_GROUP_TYPE;
}
@Override
public void redo()
{
super.redo();
for (int i = 0; i < groups.size(); i++) {
TaskGroup group = groups.get(i);
group.setNature(nature);
}
}
@Override
public void undo()
{
super.undo();
for (int i = 0; i < groups.size(); i++) {
TaskGroup group = groups.get(i);
GroupNature oldNat = oldNatures.get(i);
group.setNature(oldNat);
}
}
});
}
}
return true;
}
};
}
protected IListenerAction createRegenerateScriptAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
return regenerateScripts((ProjectSelectionState) prms);
}
};
}
// Action for RecomputeScript
protected IListenerAction createRecomputeScriptAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
return recomputeScripts((ProjectSelectionState) prms);
}
};
}
public boolean createVisualization(Design design,
AUndertaking task,
int strategy)
{
TaskApplication ta = getVisualizationTA(design, task);
if (ta != null) {
IPredictionAlgo activeAlgo = ta.determineActiveAlgorithm(project);
CognitiveModelGenerator gen = ta.getFirstModelGenerator();
if (ta.getResult(gen, activeAlgo) != null) {
PERTChartController c =
PERTChartController.openController(ta,
gen,
activeAlgo,
project,
strategy,
interaction);
return (c != null);
}
}
return false;
}
protected TaskApplication getVisualizationTA(Design design,
AUndertaking task)
{
if (task.isTaskGroup()) {
Iterator<AUndertaking> it =
((TaskGroup) task).getUndertakings().iterator();
while (it.hasNext()) {
TaskApplication result = getVisualizationTA(design, it.next());
if (result != null) {
return result;
}
}
return null;
}
return project.getTaskApplication(task, design);
}
// Action for ImportHumanCSVFile
protected IListenerAction createImportHumanCSVFileAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
// Must have selected tasks and design
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
if ((design == null) || (tasks == null) || (tasks.length == 0))
{
return false;
}
List<String> outputLines = new LinkedList<String>();
List<String> errorLines = new LinkedList<String>();
// Get csv file
File dataFile = interaction.selectCSVFile();
if (dataFile == null) {
interaction.setStatusMessage(IMPORT_FAIL_NOFILE_MSG);
return false;
}
// Read lines out of file
FileReader reader = null;
try {
reader = new FileReader(dataFile);
FileUtil.readLines(reader, outputLines);
}
catch (FileNotFoundException e) {
interaction.setStatusMessage(IMPORT_FAIL_NOFILE_MSG);
throw new RcvrIOTempException
("Error in parsing csv", e);
}
catch (IOException e) {
interaction.setStatusMessage(IMPORT_FAIL_NOREAD_MSG);
throw new RcvrParsingException
("Error in parsing csv", e);
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
// ignore
}
reader = null;
}
}
// parse ResultSteps out of trace lines
TraceParser<ResultStep> parser = new HumanCSVParser();
List<ResultStep> steps;
try {
steps = parser.parseTrace(outputLines);
}
catch (TraceParser.ParseException e) {
interaction.setStatusMessage(IMPORT_FAIL_PARSE_IMPL_MSG);
throw new RcvrParsingException
("Error in parsing implementation", e);
}
System.out.println(steps);
if (steps.size() < 1) {
interaction.setStatusMessage(IMPORT_FAIL_PARSE_MSG);
return false;
}
double taskTime = -1.0;
Iterator<ResultStep> stepIt = steps.iterator();
// Iterate to find min start time and max duration
while (stepIt.hasNext()) {
ResultStep step = stepIt.next();
taskTime =
Math.max(taskTime, step.startTime + step.duration);
}
// Scale time to seconds.
taskTime /= 1000.0;
// -------------- Done parsing
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
final TaskApplication[] taskApps =
new TaskApplication[tasks.length];
final APredictionResult[] oldResults =
new APredictionResult[tasks.length];
final APredictionResult[] results =
new APredictionResult[tasks.length];
final IPredictionAlgo[] oldActiveAlgos =
new IPredictionAlgo[tasks.length];
for (int i = 0; i < tasks.length; i++) {
taskApps[i] = ensureTaskApplication(tasks[i],
design,
MODELGEN_ALG,
demoMgr);
// If for some reason there are no result steps,
// create a TimePredictionResult that
// reflects COMPUTATION_FAILED.
// Otherwise, create a normal one.
Script script = taskApps[i].getScript(MODELGEN_ALG);
if (taskTime < 0.0) {
results[i] =
new TimePredictionResult(dataFile.getName(),
script,
HumanDataAlgo.ONLY,
outputLines,
errorLines,
steps);
}
else {
results[i] =
new TimePredictionResult(dataFile.getName(),
script,
HumanDataAlgo.ONLY,
outputLines,
errorLines,
steps,
taskTime);
}
oldResults[i] = taskApps[i].getResult(MODELGEN_ALG,
HumanDataAlgo.ONLY);
taskApps[i].setResult(MODELGEN_ALG,
HumanDataAlgo.ONLY,
results[i]);
oldActiveAlgos[i] = taskApps[i].getActiveAlgorithm();
taskApps[i].setActiveAlgorithm(HumanDataAlgo.ONLY);
}
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.RecomputeScript)
{
@Override
public String getPresentationName()
{
return IMPORT_HUMAN_CSV;
}
@Override
public void redo()
{
super.redo();
for (int i = 0; i < taskApps.length; i++) {
taskApps[i].setResult(MODELGEN_ALG,
HumanDataAlgo.ONLY,
results[i]);
taskApps[i].setActiveAlgorithm(HumanDataAlgo.ONLY);
}
}
@Override
public void undo()
{
super.undo();
for (int i = 0; i < taskApps.length; i++) {
taskApps[i].setResult(MODELGEN_ALG,
HumanDataAlgo.ONLY,
oldResults[i]);
taskApps[i].setActiveAlgorithm(oldActiveAlgos[i]);
}
}
};
undoMgr.addEdit(edit);
interaction.setStatusMessage(IMPORT_SUCCESS_MSG);
return true;
} // performAction
};
} // createImportHumanCSVFileAction
protected IListenerAction createGenerateACTRModelAction()
{
return new IListenerAction()
{
public Class<?> getParameterClass() {
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
// Must have selected tasks and design
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
for (AUndertaking task : tasks) {
TaskApplication ta = project.getTaskApplication(task,
design);
Script s =
DemoStateManager.ensureScript(ta,
KLMCognitiveGenerator.ONLY);
// TODO There's too much algorithm specific code
// in here; but for now it seems the expedient
// thing to do -- all this needs to be thought
// through for all back ends, and restructured
String path = s.getAssociatedPath();
String filename = null;
if (path == null) {
filename = design.getName() + "-" + task.getName();
}
else {
filename = (new File(path)).getName();
if ((filename != null) &&
filename.endsWith(CogToolFileTypes.LISP_FILE_EXT))
{
filename =
filename.substring(0,
filename.length()
- CogToolFileTypes.LISP_FILE_EXT.length());
}
}
File file =
interaction.selectExportLocation(filename,
CogToolFileTypes.LISP_FILE_EXT);
if (file == null) {
return false;
}
s.setAssociatedPath(file.getAbsolutePath());
// selectExportLocation actually creates the file,
// so we have to delete it.
if (file.length() == 0) {
file.delete();
}
try {
IPredictionAlgo taAlg =
ta.determineActiveAlgorithm(project);
if (! (taAlg instanceof ACTRPredictionAlgo)) {
throw new RcvrIllegalStateException(
"Can't generate ACT-R Model from a non ACT-R task.");
}
ACTRPredictionAlgo algo =
(ACTRPredictionAlgo) taAlg;
algo.outputModel(design,
task,
s.getDemonstration().getStartFrame(),
s,
file,
null);
}
catch (UnsupportedOperationException ex) {
throw new RcvrUnimplementedFnException(ex);
}
catch (IOException ex) {
throw new RcvrIOException(
("IOException generating model file for task " +
task.getName() + " in design " +
design.getName()),
ex);
}
}
return false;
}
};
}
// Action for ShowVisualization
protected IListenerAction createShowModelVisualizationAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
ProjectSelectionState seln = (ProjectSelectionState) prms;
// Must have selected tasks and design
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
if ((design == null) ||
(tasks == null) ||
(tasks.length == 0))
{
return false;
}
boolean visCreated = false;
for (AUndertaking task : tasks) {
if (createVisualization(design, task, -1)) {
visCreated = true;
break;
}
}
if (! visCreated) {
interaction.reportProblem(visualizationNotCreated,
noResultsToVisualize);
}
return visCreated;
}
};
}
protected boolean regenerateScripts(AUndertaking task,
Design design,
DemoStateManager demoStateMgr,
IUndoableEditSequence editSequence)
{
if (task.isTaskGroup()) {
Iterator<AUndertaking> allTasks =
((TaskGroup) task).getUndertakings().iterator();
CompoundUndoableEdit groupEditSeq =
new CompoundUndoableEdit(REGENERATE_SCRIPTS,
ProjectLID.RegenerateScript);
while (allTasks.hasNext()) {
if (! regenerateScripts(allTasks.next(),
design,
demoStateMgr,
groupEditSeq))
{
return false;
}
}
if (groupEditSeq.isSignificant()) {
groupEditSeq.end();
editSequence.addEdit(groupEditSeq);
}
return true;
}
TaskApplication ta = project.getTaskApplication(task, design);
if (ta != null) {
Demonstration demo = ta.getDemonstration();
return DemoScriptCmd.regenerateScripts(project,
demo,
demoStateMgr,
interaction,
editSequence);
}
return true;
}
protected boolean regenerateScripts(ProjectSelectionState seln)
{
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
String editLabel = ui.hasMultipleScripts(seln) ? REGENERATE_SCRIPTS
: REGENERATE_SCRIPT;
CompoundUndoableEdit editSequence =
new CompoundUndoableEdit(editLabel, ProjectLID.RegenerateScript);
editSequence.setManager(undoMgr);
if (design != null) {
DemoStateManager demoStateMgr =
DemoStateManager.getStateManager(project, design);
if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
if (! regenerateScripts(tasks[i],
design,
demoStateMgr,
editSequence))
{
return false;
}
}
}
else {
Iterator<AUndertaking> allTasks =
project.getUndertakings().iterator();
while (allTasks.hasNext()) {
if (! regenerateScripts(allTasks.next(),
design,
demoStateMgr,
editSequence))
{
return false;
}
}
}
}
else if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
Iterator<Design> allDesigns =
project.getDesigns().iterator();
while (allDesigns.hasNext()) {
design = allDesigns.next();
DemoStateManager demoStateMgr =
DemoStateManager.getStateManager(project, design);
if (! regenerateScripts(tasks[i],
design,
demoStateMgr,
editSequence))
{
return false;
}
}
}
}
if (editSequence.isSignificant()) {
editSequence.end();
undoMgr.addEdit(editSequence);
}
return true;
}
protected class ComputeMessages
{
protected static final int NO_OBSOLETE_YET = 0;
protected static final int REGENERATE_IF_NEEDED = 1;
protected static final int WARN_ON_OBSOLETE = 2;
protected List<String> invalidDemos = null;
protected List<String> obsoleteDemos = null;
protected int state = NO_OBSOLETE_YET;
protected void addDemoIdentification(Demonstration demo,
List<String> toList)
{
TaskApplication ta = demo.getTaskApplication();
toList.add(" " + TASK_LABEL + " "
+ ta.getTask().getFullName() + " "
+ DESIGN_LABEL + " "
+ ta.getDesign().getName());
}
// Returns true if recompute should go forward, false if we
// should go on to the next cell. If regeneration is required,
// the undoable edit will be added to the given edit sequence.
public boolean canComputeScript(TaskApplication ta,
DemoStateManager demoStateMgr,
IUndoableEditSequence editSequence)
{
APredictionResult result =
ta.getResult(ta.getFirstModelGenerator(),
ta.determineActiveAlgorithm(project));
if ((result != null) && (! result.canBeRecomputed())) {
return false;
}
Demonstration demo = ta.getDemonstration();
if (demo.isInvalid()) {
if (invalidDemos == null) {
invalidDemos = new ArrayList<String>();
invalidDemos.add(uncomputedInvalidDemosMsg);
}
addDemoIdentification(demo, invalidDemos);
return false;
}
if (demo.isObsolete()) {
if (state == NO_OBSOLETE_YET) {
state = interaction.reportRegenerationRequired()
? REGENERATE_IF_NEEDED
: WARN_ON_OBSOLETE;
}
if (state == REGENERATE_IF_NEEDED) {
return DemoScriptCmd.regenerateScripts(project,
demo,
demoStateMgr,
interaction,
editSequence);
}
if (obsoleteDemos == null) {
obsoleteDemos = new ArrayList<String>();
obsoleteDemos.add(uncomputedObsoleteScriptsMsg);
}
addDemoIdentification(demo, obsoleteDemos);
return false;
}
return true;
}
public void presentMessages()
{
if (obsoleteDemos != null) {
interaction.reportWarnings(RECOMPUTE_SCRIPTS,
obsoleteDemos);
}
if (invalidDemos != null) {
interaction.reportWarnings(RECOMPUTE_SCRIPTS,
invalidDemos);
}
}
}
protected boolean recomputeScripts(ProjectSelectionState seln)
{
Design design = seln.getSelectedDesign();
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
ComputeMessages computeMsgs = new ComputeMessages();
String editLabel = ui.hasMultipleScripts(seln)
? RECOMPUTE_SCRIPTS
: RECOMPUTE_SCRIPT;
CompoundUndoableEdit editSequence =
new CompoundUndoableEdit(editLabel, ProjectLID.RecomputeScript);
editSequence.setManager(undoMgr);
if (design != null) {
DemoStateManager demoStateMgr =
DemoStateManager.getStateManager(project, design);
if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
if (! recomputeScripts(tasks[i],
design,
demoStateMgr,
computeMsgs,
editSequence))
{
return false;
}
}
}
else {
Iterator<AUndertaking> allTasks =
project.getUndertakings().iterator();
while (allTasks.hasNext()) {
if (! recomputeScripts(allTasks.next(),
design,
demoStateMgr,
computeMsgs,
editSequence))
{
return false;
}
}
}
}
else if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
Iterator<Design> allDesigns =
project.getDesigns().iterator();
while (allDesigns.hasNext()) {
design = allDesigns.next();
DemoStateManager demoStateMgr =
DemoStateManager.getStateManager(project, design);
if (! recomputeScripts(tasks[i],
design,
demoStateMgr,
computeMsgs,
editSequence))
{
return false;
}
}
}
}
if (editSequence.isSignificant()) {
editSequence.end();
undoMgr.addEdit(editSequence);
}
computeMsgs.presentMessages();
return true;
}
protected boolean recomputeScripts(AUndertaking task,
Design design,
DemoStateManager demoStateMgr,
ComputeMessages computeMsgs,
IUndoableEditSequence editSequence)
{
if (CogToolPref.isTracingOverride == null && !CogToolPref.IS_TRACING.getBoolean()) {
Boolean answer = getInteraction().confirmNoTracing();
if (answer == null) {
// canceled
return false;
} else if (answer.booleanValue()) {
CogToolPref.IS_TRACING.setBoolean(true);
}
}
if (task.isTaskGroup()) {
if (! NullSafe.equals(WidgetAttributes.NO_CONTEXT,
task.getAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR)))
{
return computeSnifAct(design, task, editSequence, null);
}
Iterator<AUndertaking> allTasks =
((TaskGroup) task).getUndertakings().iterator();
CompoundUndoableEdit groupEditSeq =
new CompoundUndoableEdit(RECOMPUTE_SCRIPTS,
ProjectLID.RecomputeScript);
while (allTasks.hasNext()) {
if (! recomputeScripts(allTasks.next(),
design,
demoStateMgr,
computeMsgs,
groupEditSeq))
{
return false;
}
}
if (groupEditSeq.isSignificant()) {
groupEditSeq.end();
editSequence.addEdit(groupEditSeq);
}
return true;
}
TaskApplication ta = project.getTaskApplication(task, design);
if (ta != null) {
IPredictionAlgo activeAlg =
ta.determineActiveAlgorithm(project);
if (activeAlg == SNIFACTPredictionAlgo.ONLY) {
return computeSnifAct(design, task, editSequence, null);
}
if (computeMsgs.canComputeScript(ta,
demoStateMgr,
editSequence))
{
if (! activeAlg.allowsComputation()) {
interaction.setStatusMessage(algDisallowsComputation);
interaction.reportProblem(RECOMPUTE_SCRIPTS,
algDisallowsComputation);
return false;
}
else if (! ta.getDemonstration().isStartFrameChosen()) {
// nothing to compute
interaction.setStatusMessage(noStartFrameChosen);
return false;
}
IUndoableEdit edit =
ComputePredictionCmd.computeAllPredictions(project,
ta,
activeAlg,
ta.determineComputeInBackground(project),
interaction);
if (edit != null) {
ta.setActiveAlgorithm(activeAlg);
editSequence.addEdit(edit);
}
else {
interaction.setStatusMessage(computeHadNoResult);
}
}
else {
interaction.setStatusMessage(cannotRecomputeInvalid);
}
}
else {
if (project.getDefaultAlgo() == SNIFACTPredictionAlgo.ONLY) {
return computeSnifAct(design, task, editSequence, null);
}
interaction.setStatusMessage(cannotRecomputeNoDemo);
}
return true;
} // recomputeScripts
protected IListenerAction createExportResultsToCSVAction()
{
return new AListenerAction() {
public boolean performAction(Object actionParms)
{
return exportResultsToCSV();
}
};
}
public String exportFile = null;
public boolean exportResultsToCSV() {
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd_HHmmss");
Date now = new Date();
String fileName = project.getName() + '_' + fmt.format(now);
File dest = null;
if (interaction != null && exportFile == null) {
dest = interaction.selectCSVFileDest(fileName);
} else if (exportFile != null) {
dest = new File(exportFile);
}
exportFile = null;
if (dest == null) {
return false;
}
StringBuilder buffer = exportResults(CSV_SEPARATOR, now);
FileWriter fw = null;
BufferedWriter writer = null;
try {
fw = new FileWriter(dest);
writer = new BufferedWriter(fw);
writer.write(buffer.toString());
}
catch (IOException e) {
if (interaction != null) {
interaction.reportProblem("File I/O Error", e.getMessage());
} else {
e.printStackTrace();
}
return false;
}
finally {
try {
if (writer != null) {
writer.close();
}
if (fw != null) {
fw.close();
}
}
catch (IOException e) {
if (interaction != null) {
interaction.reportProblem("File I/O Error on Close",
e.getMessage());
} else {
e.printStackTrace();
}
return false;
}
}
if (interaction != null) {
interaction.setStatusMessage(L10N.get("DSO.ExportCompletedPre",
"Export completed to ")
+ dest
+ L10N.get("DSO.ExportCompletePost",
"."));
}
return true;
}
protected IListenerAction createExportDesignToHTMLAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState selection =
(ProjectSelectionState) actionParms;
Design d = selection.getSelectedDesign();
if (d == null) {
interaction.protestNoSelection();
return false;
}
return ExportToHTMLWorkThread.exportDesignToHTML(d, interaction);
}
};
}
protected IListenerAction createCaptureAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
//return BehaviorRecorderCmd.captureBehavior(getModel());
return false;
}
};
}
protected void importDesign(TaskParent parent,
DesignSelectionState prms,
Design newDesign,
Collection<Demonstration> demonstrations,
Set<AUndertaking> newUndertakings,
IUndoableEditSequence editSeq)
{
makeDesignNameUnique(newDesign);
ProjectCmd.addNewDesign(project,
newDesign,
prms.getSelectedDesign(),
importXMLPresentation,
editSeq);
// Add taskapplications/tasks as well for demonstrations
if ((demonstrations != null) && (demonstrations.size() > 0)) {
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, newDesign);
Iterator<Demonstration> demoIt = demonstrations.iterator();
while (demoIt.hasNext()) {
Demonstration demo = demoIt.next();
TaskApplication taskApp = demo.getTaskApplication();
AUndertaking demoTask = taskApp.getTask();
if (demoTask.getTaskGroup() == null &&
!newUndertakings.contains(demoTask)) {
// If the taskApp's task is not already part of the
// project, add it. Regardless, any project root task
// with the same name should be the same at this point!
AUndertaking rootTask =
parent.getUndertaking(demoTask.getName());
if (rootTask == null) {
parent.addUndertaking(demoTask);
editSeq.addEdit(createNewTaskUndo(parent,
Project.AT_END,
demoTask,
ProjectLID.ImportXML,
importXMLPresentation));
}
else if (rootTask != demoTask) {
throw new RcvrIllegalStateException("Unexpected root task difference");
}
}
project.setTaskApplication(taskApp);
demoMgr.trackEdits(demo);
}
}
}
public File importFile = null;
public boolean importFileComputes = false;
protected IListenerAction createImportAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object prms)
{
boolean computeScripts = CogToolPref.COMPSCR.getBoolean();
if (importFile == null) {
importFile = interaction.selectXMLFile(true, null);
} else {
computeScripts = importFileComputes;
}
if (importFile == null) {
return false;
}
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(importXMLPresentation,
ProjectLID.ImportXML);
Map<Design, Collection<Demonstration>> parsedDesigns = null;
Set<AUndertaking> newUndertakings = null;
TaskParent parent = project;
try {
if (CogToolPref.HCIPA.getBoolean()) {
TaskGroup importGroup =
new TaskGroup(importFile.getName(),
GroupNature.SUM);
parent = importGroup;
project.addUndertaking(importGroup);
editSeq.addEdit(createNewTaskUndo(project,
Project.AT_END,
importGroup,
ProjectLID.ImportXML,
importXMLPresentation));
}
ImportCogToolXML importer = new ImportCogToolXML();
if (! importer.importXML(importFile,
parent,
MODELGEN_ALG) ||
(importer.getDesigns().size() == 0))
{
List<String> errors = importer.getObjectFailures();
if ((errors != null) && (errors.size() > 0)) {
interaction.reportProblems(importXMLPresentation,
errors);
}
else {
interaction.reportProblem(importXMLPresentation,
xmlParseFailed);
}
return false;
}
List<String> warnings = importer.getGenerationWarnings();
if (warnings.size() > 0) {
interaction.reportWarnings(importXMLPresentation,
warnings);
}
parsedDesigns = importer.getDesigns();
newUndertakings = importer.getNewUndertakings();
}
catch (ImportCogToolXML.ImportFailedException ex) {
throw new RcvrXMLParsingException("Missing XML component",
ex);
}
catch (GraphicsUtil.ImageException ex) {
throw new RcvrImageException("Image error during loading XML",
ex);
}
catch (IOException ex) {
throw new RcvrXMLParsingException("IO error loading XML",
ex);
}
catch (SAXException ex) {
throw new RcvrXMLParsingException("Error parsing XML", ex);
}
catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
importFile = null;
importFileComputes = false;
}
for (AUndertaking u : newUndertakings) {
parent.addUndertaking(u);
final AUndertaking uu = u;
final TaskParent pp = parent;
editSeq.addEdit(new AUndoableEdit(ProjectLID.ImportXML) {
@Override
public void redo()
{
super.redo();
pp.addUndertaking(uu);
}
@Override
public void undo()
{
super.undo();
pp.removeUndertaking(uu);
}
});
}
Iterator<Map.Entry<Design, Collection<Demonstration>>> designDemos =
parsedDesigns.entrySet().iterator();
while (designDemos.hasNext()) {
Map.Entry<Design, Collection<Demonstration>> entry =
designDemos.next();
importDesign(parent,
(DesignSelectionState) prms,
entry.getKey(),
entry.getValue(),
newUndertakings,
editSeq);
}
editSeq.end();
undoMgr.addEdit(editSeq);
if(computeScripts){
//compute predictions for imported project
ProjectContextSelectionState seln = new ProjectContextSelectionState(project);
seln.addSelectedDesigns(project.getDesigns());
ui.selectAllTasks();
recomputeScripts(seln);
ui.deselectAllTasks();
}
return true;
}
};
}
protected IListenerAction createImportWebCrawlAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState selection = (DesignSelectionState) prms;
ProjectInteraction.IWebCrawlImport importParms =
interaction.requestWebCrawlParms(project,
WebCrawler.DEFAULT_MAX_TO_CRAWL);
if (importParms != null) {
String designName = importParms.getDesignName();
Design design;
if (designName == null) {
ProjectInteraction.DesignRequestData requestData =
requestNewDesignParms(false);
if (requestData == null) {
return false; // canceled!
}
design = new Design(requestData.designName,
requestData.deviceTypes);
}
else {
design = project.getDesign(designName);
}
int defaultDepth = importParms.getDefaultDepth();
List<URLCrawlEntry> urls = importParms.getURLsToCrawl();
if ((urls == null) || (urls.size() == 0)) {
interaction.reportProblem(ImportWebCrawlThread.IMPORT_WEB_CRAWL,
noURLsToCrawlError);
return false;
}
// If new, indicate that the work thread should add the
// new design to the project when it completes;
// -1 indicates that the design is *not* new.
int beforeIndex = ImportWebCrawlThread.EXISTING_DESIGN;
if (designName == null) {
Design selectedDesign = selection.getSelectedDesign();
beforeIndex =
(selectedDesign != null)
? (project.getDesigns().indexOf(selectedDesign) + 1)
: project.getDesigns().size();
}
ImportWebCrawlThread workThread =
new ImportWebCrawlThread(interaction,
undoMgr,
project,
design,
beforeIndex,
importParms.getMaxPages(),
defaultDepth,
urls,
importParms.pruneSameURLs(),
importParms.getBrowserWidth(),
importParms.getBrowserHeight(),
importParms.captureImages());
ThreadManager.startNewThread(workThread);
return true;
}
return false;
}
};
}
protected void duplicateTaskApplications(Design designCopy,
Map<ITaskDesign, TaskApplication> associatedTAs)
{
// The undo edit for adding the Design will remove and restore
// the task-applications; all we need to do here is duplicate
// the task applications.
Iterator<TaskApplication> taskApps = associatedTAs.values().iterator();
while (taskApps.hasNext()) {
TaskApplication ta = taskApps.next();
AUndertaking task = ta.getTask();
project.setTaskApplication(ta.duplicate(task, designCopy));
}
}
protected void duplicateTaskApplications(AUndertaking originalTask,
AUndertaking taskCopy)
{
// The undo edit for adding the Task will remove and restore
// the task-applications; all we need to do here is duplicate
// the task applications.
Iterator<Design> allDesigns = project.getDesigns().iterator();
while (allDesigns.hasNext()) {
Design design = allDesigns.next();
TaskApplication originalTA =
project.getTaskApplication(originalTask, design);
if (originalTA != null) {
TaskApplication dupTA =
originalTA.duplicate(taskCopy, design);
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
project.setTaskApplication(dupTA);
demoMgr.trackEdits(dupTA.getDemonstration());
}
}
}
protected void duplicateTaskApplications(TaskGroup originalGroup,
TaskGroup groupCopy)
{
Iterator<AUndertaking> originalChildren =
originalGroup.getUndertakings().iterator();
Iterator<AUndertaking> copyChildren =
groupCopy.getUndertakings().iterator();
// Iterate in parallel
while (originalChildren.hasNext() && copyChildren.hasNext()) {
AUndertaking originalTask = originalChildren.next();
AUndertaking taskCopy = copyChildren.next();
if (originalTask instanceof TaskGroup) {
duplicateTaskApplications((TaskGroup) originalTask,
(TaskGroup) taskCopy);
}
else {
duplicateTaskApplications(originalTask, taskCopy);
}
}
}
protected IListenerAction createDuplicateDesignAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return DesignSelectionState.class;
}
public boolean performAction(Object prms)
{
DesignSelectionState seln = (DesignSelectionState) prms;
Design design = seln.getSelectedDesign();
// Can only duplicate if a design is currently selected.
if (design == null) {
interaction.protestNoSelection();
return false;
}
// Determine new name
String copyName =
NamedObjectUtil.makeNameUnique(design.getName(),
project.getDesigns());
Design designCopy = design.duplicate(copyName);
ISimilarityDictionary dict =
(ISimilarityDictionary) design.getAttribute(WidgetAttributes.DICTIONARY_ATTR);
if (! NullSafe.equals(dict, WidgetAttributes.NO_DICTIONARY)) {
designCopy.setAttribute(WidgetAttributes.DICTIONARY_ATTR,
dict.duplicate());
}
ProjectCmd.addNewDesign(project,
designCopy,
seln.getSelectedDesign(),
DUPLICATE_DESIGN,
undoMgr);
Map<ITaskDesign, TaskApplication> associatedTAs =
project.taskApplicationsForDesign(design);
duplicateTaskApplications(designCopy, associatedTAs);
return true;
}
};
}
protected AUndertaking duplicateTask(AUndertaking task,
int atIndex,
TaskParent parent,
List<AUndertaking> siblings,
CogToolLID lid,
String presentationName,
IUndoableEditSequence editSeq)
{
String newTaskName =
NamedObjectUtil.makeNameUnique(task.getName(), siblings);
IUndoableEdit edit;
AUndertaking duplicateTask = task.duplicate(newTaskName);
// Create undo/redo step
if (task.isTaskGroup()) {
SNIFACTExecContext context =
(SNIFACTExecContext) task.getAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR);
// Attribute values are referenced, not duplicated during a
// duplicate operation; the SMIFACT_CONTEXT_ATTR value must be
// duplicated as well.
if (! NullSafe.equals(context, WidgetAttributes.NO_CONTEXT)) {
duplicateTask.setAttribute(WidgetAttributes.SNIFACT_CONTEXT_ATTR,
context.duplicate());
}
edit =
createNewTaskGroupUndo(parent,
atIndex,
(TaskGroup) duplicateTask,
null,
null,
new AUndertaking[0],
lid,
presentationName);
}
else {
edit = createNewTaskUndo(parent,
atIndex,
duplicateTask,
lid,
presentationName);
}
editSeq.addEdit(edit);
parent.addUndertaking(atIndex, duplicateTask);
if (task.isTaskGroup()) {
duplicateTaskApplications((TaskGroup) task,
(TaskGroup) duplicateTask);
}
else {
duplicateTaskApplications(task, duplicateTask);
}
return duplicateTask;
}
protected IListenerAction createDuplicateTasksAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState seln = (TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.ORDER_SELECTION);
// Can only duplicate if one or more tasks are selected
if ((tasks != null) && (tasks.length > 0)) {
String presentationName = (tasks.length > 1)
? DUPLICATE_TASKS
: DUPLICATE_TASK;
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(presentationName,
ProjectLID.DuplicateTask);
AUndertaking lastDuplicate = null;
for (AUndertaking task : tasks) {
TaskParent parent = project.getTaskParent(task);
List<AUndertaking> parentUndertakings =
parent.getUndertakings();
int atIndex = parentUndertakings.indexOf(task) + 1;
lastDuplicate = duplicateTask(task,
atIndex,
parent,
parentUndertakings,
ProjectLID.DuplicateTask,
presentationName,
editSeq);
}
// Done with undo/redo steps; add the compound change
// to the undo manager.
editSeq.end();
undoMgr.addEdit(editSeq);
if (tasks.length == 1) {
ui.initiateTaskRename(lastDuplicate);
}
}
else {
interaction.protestNoSelection();
}
return true;
}
};
}
protected IListenerAction createReorderDesignsAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return Design[].class;
}
public boolean performAction(Object prms)
{
final Design[] newDesignOrder = (Design[]) prms;
final Design[] oldDesignOrder =
new Design[newDesignOrder.length];
project.reorderDesigns(newDesignOrder, oldDesignOrder);
undoMgr.addEdit(new AUndoableEdit(ProjectLID.ReorderDesigns)
{
@Override
public String getPresentationName()
{
return REORDER_DESIGNS;
}
@Override
public void redo()
{
super.redo();
project.reorderDesigns(newDesignOrder, null);
}
@Override
public void undo()
{
super.undo();
project.reorderDesigns(oldDesignOrder, null);
}
});
return true;
}
};
}
protected IListenerAction createSetProjDefaultAlg(final ProjectLID lid,
final String label,
final IPredictionAlgo alg)
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
final IPredictionAlgo oldDefaultAlg = project.getDefaultAlgo();
project.setDefaultAlgo(alg);
undoMgr.addEdit(new AUndoableEdit(lid)
{
@Override
public String getPresentationName()
{
return label;
}
@Override
public void redo()
{
super.redo();
project.setDefaultAlgo(alg);
}
@Override
public void undo()
{
super.undo();
project.setDefaultAlgo(oldDefaultAlg);
}
});
return true;
}
};
}
protected boolean setProjectDefaultExecution(ProjectLID lid,
final String label,
final boolean inBackground)
{
final boolean wasInBkg = project.getDefaultRunInBackground();
if (wasInBkg != inBackground) {
project.setDefaultRunInBackground(inBackground);
undoMgr.addEdit(new AUndoableEdit(lid)
{
@Override
public String getPresentationName()
{
return label;
}
@Override
public void redo()
{
super.redo();
project.setDefaultRunInBackground(inBackground);
}
@Override
public void undo()
{
super.undo();
project.setDefaultRunInBackground(wasInBkg);
}
});
}
return true;
}
protected IListenerAction createSetProjDefaultExecBkg(final ProjectLID lid,
final String label,
final boolean inBkg)
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
return setProjectDefaultExecution(lid, label, inBkg);
}
};
}
protected IListenerAction createSetAlgorithmHumanAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState parms =
(ProjectSelectionState) actionParms;
final TaskApplication ta =
project.getTaskApplication(parms.getSelectedTask(),
parms.getSelectedDesign());
final IPredictionAlgo oldAlgo =
ta.determineActiveAlgorithm(project);
ta.setActiveAlgorithm(HumanDataAlgo.ONLY);
undoMgr.addEdit(new AUndoableEdit(ProjectLID.SetAlgorithmHuman)
{
@Override
public String getPresentationName()
{
return L10N.get("UNDO.PM.SetHumanAlgorithm",
"Set Algorithm to Human Data");
}
@Override
public void redo()
{
super.redo();
ta.setActiveAlgorithm(HumanDataAlgo.ONLY);
}
@Override
public void undo()
{
super.undo();
ta.setActiveAlgorithm(oldAlgo);
}
});
return true;
}
};
}
protected IListenerAction createSetAlgorithmAction(final IPredictionAlgo alg,
final CogToolLID lid,
final String actionString)
{
return new IListenerAction()
{
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState selState =
(ProjectSelectionState) actionParms;
Design design = selState.getSelectedDesign();
AUndertaking[] tasks =
selState.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
// iterate through tasks and get set of TaskApplications
final TaskApplication[] taskApps =
new TaskApplication[tasks.length];
final IPredictionAlgo[] oldAlgos =
new IPredictionAlgo[tasks.length];
for (int i = 0; i < tasks.length; i++) {
// Make sure that the task application exists, and create it
// if it does not. No need to ensure a script.
TaskApplication ta = ensureTaskApplication(tasks[i],
design,
null,
demoMgr);
taskApps[i] = ta;
oldAlgos[i] = ta.getActiveAlgorithm();
// now set the new algorithm
ta.setActiveAlgorithm(alg);
}
undoMgr.addEdit(new AUndoableEdit(lid)
{
@Override
public String getPresentationName()
{
return actionString;
}
@Override
public void redo()
{
super.redo();
for (TaskApplication taskApp : taskApps) {
taskApp.setActiveAlgorithm(alg);
}
}
@Override
public void undo()
{
super.undo();
for (int i = 0; i < taskApps.length; i++) {
taskApps[i].setActiveAlgorithm(oldAlgos[i]);
}
}
});
return true;
}
};
}
protected IListenerAction createSetBackgroundComputeAction(final Boolean bkg,
final ProjectLID lid,
final String actionName)
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState selState =
(ProjectSelectionState) actionParms;
Design design = selState.getSelectedDesign();
AUndertaking[] tasks =
selState.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
// iterate through tasks and get set of TaskApplications
final TaskApplication[] taskApps =
new TaskApplication[tasks.length];
final Boolean[] oldBkgSettings = new Boolean[tasks.length];
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, design);
for (int i = 0; i < tasks.length; i++) {
// Make sure that the task application exists, and create it
// if it does not. No need to ensure a script.
TaskApplication ta = ensureTaskApplication(tasks[i],
design,
null,
demoMgr);
taskApps[i] = ta;
oldBkgSettings[i] = ta.getComputeInBackground();
// now set the compute in background flag
ta.setComputeInBackground(bkg);
}
undoMgr.addEdit(new AUndoableEdit(lid)
{
@Override
public String getPresentationName()
{
return actionName;
}
@Override
public void redo()
{
super.redo();
for (TaskApplication taskApp : taskApps) {
taskApp.setComputeInBackground(bkg);
}
}
@Override
public void undo()
{
super.undo();
for (int i = 0; i < taskApps.length; i++) {
taskApps[i].setComputeInBackground(oldBkgSettings[i]);
}
}
});
return true;
}
};
}
// TODO it is a crock that we're cloning this stuff; when we have time
// we should design a shared mechanism to be used by all back ends
protected IListenerAction createEditACTRModelAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState selState =
(ProjectSelectionState) actionParms;
Design design = selState.getSelectedDesign();
AUndertaking[] tasks =
selState.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
for (AUndertaking task : tasks) {
TaskApplication ta = project.getTaskApplication(task,
design);
if (ta == null) {
return false;
}
// find the script
Script script = ta.getScript(KLMCognitiveGenerator.ONLY);
if (script == null) {
return false;
}
// get the resourcePath
String resourcePath = script.getAssociatedPath();
if (resourcePath == null) {
return false;
}
try {
FileUtil.editFile(new File(resourcePath));
}
catch (UnsupportedOperationException ex) {
throw new RcvrUnimplementedFnException("Editing a file is not implemented",
ex);
}
catch (IOException ex) {
throw new RcvrIOException("Problem when trying to edit a file.",
ex);
}
}
return true;
}
};
}
/**
* Fetch the implementation of the view for this window.
*
* @return the implementation of the view for this window
*/
@Override
public UI getUI()
{
return ui;
}
public ProjectInteraction getInteraction()
{
return interaction;
}
/**
* editSeq will be null if no regeneration occurred; otherwise,
* the edit sequence will contain the undoable edit for the regeneration.
*/
public static boolean openProjectOnCompute(Project project,
final Script script,
final APredictionResult newResult,
CompoundUndoableEdit editSeq)
{
boolean notModified;
try {
notModified = UndoManager.isAtSavePoint(project);
}
catch (IllegalStateException ex) {
System.err.println("Ignoring that isAtSavePoint failed.");
notModified = false;
}
ProjectController c =
ProjectController.openController(project,
false,
notModified);
final CognitiveModelGenerator modelGen = script.getModelGenerator();
final IPredictionAlgo computeAlg = newResult.getPredictionAlgorithm();
final TaskApplication taskApp =
script.getDemonstration().getTaskApplication();
final APredictionResult oldResult =
taskApp.getResult(modelGen, computeAlg);
taskApp.setResult(modelGen,
computeAlg,
PredictionResultProxy.getLatestResult(newResult));
UndoManager scriptUndoMgr =
UndoManager.getUndoManager(script, project);
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.RecomputeScript)
{
protected APredictionResult redoResult = newResult;
protected APredictionResult undoResult = oldResult;
@Override
public String getPresentationName()
{
return COMPUTE_SCRIPT;
}
@Override
public void redo()
{
super.redo();
redoResult =
PredictionResultProxy.getLatestResult(redoResult);
taskApp.setResult(modelGen, computeAlg, redoResult);
}
@Override
public void undo()
{
super.undo();
undoResult =
PredictionResultProxy.getLatestResult(undoResult);
taskApp.setResult(modelGen, computeAlg, undoResult);
}
};
if (editSeq != null) {
editSeq.addEdit(edit);
editSeq.end();
edit = editSeq;
}
// Add to script's undo mgr first to set owner properly
scriptUndoMgr.addEdit(edit);
c.undoMgr.addEdit(edit);
c.takeFocus();
return true;
}
// Action for ExportScriptToCSV
protected IListenerAction createExportScriptToCSVAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
ProjectSelectionState seln =
(ProjectSelectionState) actionParms;
Design design = seln.getSelectedDesign();
if (design == null) {
interaction.protestNoSelection();
return false;
}
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION);
if (tasks.length == 0) {
interaction.protestNoSelection();
return false;
}
// TODO: Only perform this action when one cell is selected
// (i.e. one task is selected)
// Also, since CogTool doesn't support multiple algorithms
// yet, just use the first prediction algorithm in the map
// to get the script I want; this may need to be changed.
AUndertaking task = tasks[0];
TaskApplication taskApp =
project.getTaskApplication(task, design);
if (taskApp == null) {
interaction.protestNoSelection();
return false;
}
Script script = taskApp.getScript(MODELGEN_ALG);
if (script == null) {
script = taskApp.getScript(IdentityModelGenerator.ONLY);
if (script == null) {
interaction.protestNoSelection();
return false;
}
}
return DemoScriptCmd.exportScriptToCSV(script,
project,
interaction,
undoMgr);
}
};
}
public void exportCSVKludge() {
for (Design d : project.getDesigns()) {
if (d == null) {
continue;
}
for (TaskApplication ta : project.taskApplicationsForDesign(d).values()) {
if (ta == null) {
continue;
}
Script s = ta.getScript(MODELGEN_ALG);
if (s == null) {
continue;
}
DemoScriptCmd.exportScriptToCSV(s, project, null, undoMgr);
}
}
exportResultsToCSV();
exportDesignToXML(null);
}
protected IListenerAction createExportDesignToXML()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectSelectionState.class;
}
public boolean performAction(Object actionParms)
{
return exportDesignToXML(
((ProjectSelectionState) actionParms).getSelectedDesign());
}
};
}
private boolean exportDesignToXML(Design design) {
String defaultFilename =
((design != null) ? design.getName() : project.getName())
+ ".xml";
File exportFile = null;
if (interaction != null && CogTool.exportCSVKludgeDir == null) {
exportFile = interaction.selectXMLFile(false, defaultFilename);
} else {
exportFile = new File(CogTool.exportCSVKludgeDir, defaultFilename);
}
if (exportFile == null) {
return false;
}
OutputStream oStream = null;
String completionMsg;
try {
try {
oStream = new FileOutputStream(exportFile);
Writer xmlWriter =
new BufferedWriter(new OutputStreamWriter(oStream,
"UTF-8"));
if (design == null) {
ExportCogToolXML.exportXML(project,
xmlWriter,
"UTF-8");
completionMsg = allDesignsExportedToXml;
}
else {
Map<ITaskDesign, TaskApplication> designTAs =
project.taskApplicationsForDesign(design);
ExportCogToolXML.exportXML(design,
designTAs,
xmlWriter,
"UTF-8");
completionMsg = designExportedToXml;
}
xmlWriter.flush();
}
finally {
if (oStream != null) {
oStream.close();
}
}
}
catch (IllegalArgumentException e) {
throw new RcvrIllegalStateException("Invalid argument exporting to XML", e);
}
catch (IllegalStateException e) {
throw new RcvrIllegalStateException("Exporting to XML", e);
}
catch (IOException e) {
throw new RcvrIOSaveException("Exporting to XML", e);
}
catch (Exception e) {
throw new RecoverableException("Exporting to XML", e);
}
if (interaction != null) {
interaction.setStatusMessage(completionMsg
+ " "
+ exportFile.getAbsolutePath());
}
return true;
}
protected IListenerAction createChangeTaskPositionAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.ChangeTaskPositionParms.class;
}
public boolean performAction(Object actionParms)
{
ProjectUI.ChangeTaskPositionParms prms =
(ProjectUI.ChangeTaskPositionParms) actionParms;
if ((prms.placeBeforeTask != null) &&
prms.tasks.isInSelectedHierarchy(prms.placeBeforeTask))
{
// Nothing to do
return false;
}
if ((prms.tasks == null) ||
(prms.tasks.getSelectedTaskCount() == 0))
{
interaction.protestNoSelection();
return false;
}
final AUndertaking[] selectedTasks =
prms.tasks.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
final TaskParent[] oldParents =
new TaskParent[selectedTasks.length];
final int[] indexes = new int[selectedTasks.length];
final String[] oldNames = new String[selectedTasks.length];
final TaskParent placeBeforeTaskParent =
(prms.placeBeforeTask != null)
? project.getTaskParent(prms.placeBeforeTask)
: project;
final List<AUndertaking> siblings =
placeBeforeTaskParent.getUndertakings();
// If the place-before-task is selected, find the next
// sibling that is not selected.
AUndertaking placeBefore = prms.placeBeforeTask;
if (prms.tasks.isTaskSelected(placeBefore)) {
int siblingIndex = siblings.indexOf(placeBefore);
int siblingCount = siblings.size();
while (++siblingIndex < siblingCount) {
placeBefore = siblings.get(siblingIndex);
if (! prms.tasks.isTaskSelected(placeBefore)) {
break;
}
}
if (siblingIndex >= siblingCount) {
placeBefore = null;
}
}
// Remove first so that the atIndex computation works!
removeChildTasks(selectedTasks, oldParents, indexes);
final int atIndex =
(placeBefore != null) ? siblings.indexOf(placeBefore)
: siblings.size();
// Add each selected task as siblings before the given task
for (int i = 0; i < selectedTasks.length; i++) {
oldNames[i] = selectedTasks[i].getName();
String newName =
NamedObjectUtil.makeNameUnique(oldNames[i], siblings);
if (! newName.equals(oldNames[i])) {
selectedTasks[i].setName(newName);
}
placeBeforeTaskParent.addUndertaking(atIndex + i,
selectedTasks[i]);
}
// Create undo/redo step and add to undo manager
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.ChangeTaskPosition)
{
@Override
public String getPresentationName()
{
return (selectedTasks.length > 1) ? MOVE_TASKS
: MOVE_TASK;
}
@Override
public void redo()
{
super.redo();
removeChildTasks(selectedTasks, null, null);
// Add each selected task as siblings
// before the given task
for (int i = 0; i < selectedTasks.length; i++) {
String newName =
NamedObjectUtil.makeNameUnique(oldNames[i],
siblings);
if (! newName.equals(oldNames[i])) {
selectedTasks[i].setName(newName);
}
placeBeforeTaskParent.addUndertaking(atIndex + i,
selectedTasks[i]);
}
}
@Override
public void undo()
{
super.undo();
removeChildTasks(selectedTasks, null, null);
// Un-delete children; IMPORTANT: reverse order!
for (int i = selectedTasks.length - 1; 0 <= i; i--)
{
if (! oldNames[i].equals(selectedTasks[i].getName())) {
selectedTasks[i].setName(oldNames[i]);
}
// Add to old parent at old index
oldParents[i].addUndertaking(indexes[i],
selectedTasks[i]);
}
}
};
undoMgr.addEdit(edit);
return true;
}
};
}
protected IListenerAction createDuplicateTaskFullAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.ChangeTaskPositionParms.class;
}
public boolean performAction(Object actionParms)
{
ProjectUI.ChangeTaskPositionParms prms =
(ProjectUI.ChangeTaskPositionParms) actionParms;
if ((prms.tasks == null) ||
(prms.tasks.getSelectedTaskCount() == 0))
{
interaction.protestNoSelection();
return false;
}
AUndertaking[] selectedTasks =
prms.tasks.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
TaskParent placeBeforeTaskParent =
(prms.placeBeforeTask != null)
? project.getTaskParent(prms.placeBeforeTask)
: project;
List<AUndertaking> siblings = placeBeforeTaskParent.getUndertakings();
int atIndex = (prms.placeBeforeTask != null)
? siblings.indexOf(prms.placeBeforeTask)
: siblings.size();
String presentationName = (selectedTasks.length > 1)
? DUPLICATE_TASKS
: DUPLICATE_TASK;
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(presentationName,
ProjectLID.DuplicateTaskFull);
AUndertaking lastDuplicate = null;
for (int i = 0; i < selectedTasks.length; i++) {
lastDuplicate = duplicateTask(selectedTasks[i],
atIndex + i,
placeBeforeTaskParent,
siblings,
ProjectLID.DuplicateTaskFull,
presentationName,
editSeq);
}
// Done with undo/redo steps; add the compound change
// to the undo manager.
editSeq.end();
undoMgr.addEdit(editSeq);
if (selectedTasks.length == 1) {
ui.initiateTaskRename(lastDuplicate);
}
return true;
}
};
}
protected String promoteTask(final AUndertaking task,
CogToolLID lid,
IUndoableEditSequence editSeq)
{
final TaskGroup parent = task.getTaskGroup();
if (parent == null) {
return cannotPromoteTaskError + ": " + task.getFullName();
}
List<AUndertaking> siblings = parent.getUndertakings();
final int indexInParent = siblings.indexOf(task);
final TaskParent grandparent = project.getTaskParent(parent);
List<AUndertaking> uncles = grandparent.getUndertakings();
final int newTaskIndex = uncles.indexOf(parent) + 1;
final String oldTaskName = task.getName();
final int adoptedSiblingCount = siblings.size() - indexInParent - 1;
final AUndertaking asUndertaking =
((task instanceof TaskGroup) || (adoptedSiblingCount == 0))
? task
: new TaskGroup(task.getName(), GroupNature.SUM);
final TaskGroup asTaskGroup =
asUndertaking.isTaskGroup() ? (TaskGroup) asUndertaking : null;
// Must treat associated task-applications as deleted if the
// promotion changed the undertaking from a task to a task group.
final Map<ITaskDesign, TaskApplication> assocTAs =
(asUndertaking != task)
? project.taskApplicationsForRemovedTask(task)
: null;
final AUndertaking[] adoptedSiblings =
(adoptedSiblingCount > 0) ? new AUndertaking[adoptedSiblingCount]
: null;
final String[] oldSiblingNames =
(adoptedSiblingCount > 0) ? new String[adoptedSiblingCount] : null;
// Delete task and later siblings from parent
parent.removeUndertaking(task);
for (int i = 0; i < adoptedSiblingCount; i++) {
adoptedSiblings[i] = siblings.get(indexInParent);
if (oldSiblingNames != null) {
oldSiblingNames[i] = adoptedSiblings[i].getName();
}
parent.removeUndertaking(adoptedSiblings[i]);
// Insert later siblings as children of asTaskGroup
makeTaskNameUnique(asTaskGroup, adoptedSiblings[i]);
asTaskGroup.addUndertaking(adoptedSiblings[i]);
}
// Insert task at newTaskIndex into grandparent
makeTaskNameUnique(grandparent, asUndertaking);
grandparent.addUndertaking(newTaskIndex, asUndertaking);
// Create undoable edit
IUndoableEdit edit =
new AUndoableEdit(lid)
{
protected Map<ITaskDesign, TaskApplication> associatedTAs = assocTAs;
protected boolean recoverMgrs = true;
@Override
public String getPresentationName()
{
return PROMOTE_TASK;
}
@Override
public void redo()
{
super.redo();
recoverMgrs = true;
associatedTAs =
(asUndertaking != task)
? project.taskApplicationsForRemovedTask(task)
: null;
for (int i = 0; i < adoptedSiblingCount; i++) {
parent.removeUndertaking(adoptedSiblings[i]);
makeTaskNameUnique(asTaskGroup, adoptedSiblings[i]);
asTaskGroup.addUndertaking(adoptedSiblings[i]);
}
parent.removeUndertaking(task);
makeTaskNameUnique(grandparent, asUndertaking);
grandparent.addUndertaking(newTaskIndex, asUndertaking);
}
@Override
public void undo()
{
super.undo();
recoverMgrs = false;
grandparent.removeUndertaking(asUndertaking);
task.setName(oldTaskName);
parent.addUndertaking(indexInParent, task);
if (asUndertaking != task) {
project.restoreRemovedTaskApplications(associatedTAs);
}
for (int i = 0; i < adoptedSiblingCount; i++) {
asTaskGroup.removeUndertaking(adoptedSiblings[i]);
if (oldSiblingNames != null) {
adoptedSiblings[i].setName(oldSiblingNames[i]);
}
parent.addUndertaking(indexInParent + i + 1,
adoptedSiblings[i]);
}
}
@Override
public void die()
{
super.die();
if (recoverMgrs && (asUndertaking != task)) {
recoverManagers(task, associatedTAs);
}
}
};
editSeq.addEdit(edit);
return null;
}
protected IListenerAction createUngroupAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState seln = (TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION |
TaskSelectionState.TASK_GROUPS_ONLY);
if ((tasks == null) || (tasks.length == 0)) {
interaction.protestNoSelection();
return false;
}
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(L10N.get("PC.Ungroup", "Ungroup"),
ProjectLID.Ungroup);
for (AUndertaking task : tasks) {
if (task.isTaskGroup()) {
TaskGroup group = (TaskGroup) task;
List<AUndertaking> childTasks = group.getUndertakings();
int numChildTasks = childTasks.size();
if (numChildTasks > 0) {
AUndertaking[] promoteTasks =
new AUndertaking[numChildTasks];
childTasks.toArray(promoteTasks);
for (int j = numChildTasks - 1; j >= 0; j--) {
promoteTask(promoteTasks[j],
ProjectLID.Ungroup,
editSeq);
}
}
}
}
deleteTasks(tasks, null, editSeq);
if (editSeq.isSignificant()) {
editSeq.end();
undoMgr.addEdit(editSeq);
}
return true;
}
};
}
protected IListenerAction createPromoteTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState seln = (TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
if ((tasks == null) || (tasks.length == 0)) {
interaction.protestNoSelection();
return false;
}
List<String> errors = new ArrayList<String>();
String editLabel =
(tasks.length > 1) ? PROMOTE_TASKS : PROMOTE_TASK;
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(editLabel,
ProjectLID.PromoteTask);
for (AUndertaking task : tasks) {
String promoteError =
promoteTask(task, ProjectLID.PromoteTask, editSeq);
if (promoteError != null) {
errors.add(promoteError);
}
}
if (errors.size() > 0) {
interaction.reportProblems(editLabel, errors);
}
if (editSeq.isSignificant()) {
editSeq.end();
undoMgr.addEdit(editSeq);
}
return true;
}
};
}
protected String demoteTask(final AUndertaking task,
IUndoableEditSequence editSeq)
{
final TaskParent parent = project.getTaskParent(task);
List<AUndertaking> siblings = parent.getUndertakings();
final int indexInParent = siblings.indexOf(task);
if (indexInParent == 0) {
return cannotDemoteTaskError + ": " + task.getFullName();
}
final String oldTaskName = task.getName();
final AUndertaking prevSibling = siblings.get(indexInParent - 1);
final TaskGroup siblingAsTaskGroup =
(prevSibling instanceof TaskGroup)
? (TaskGroup) prevSibling
: new TaskGroup(prevSibling.getName(),
GroupNature.SUM);
if (siblingAsTaskGroup.getUndertakings().size() > 0) {
AUndertaking firstTask =
siblingAsTaskGroup.getUndertakings().get(0);
if (firstTask.isSpawned()) {
return cannotDemoteIntoGroupError;
}
}
// Must treat sibling's task-applications as deleted if the
// demotion changed it from a task to a task group
final Map<ITaskDesign, TaskApplication> siblingAssocTAs =
(siblingAsTaskGroup != prevSibling)
? project.taskApplicationsForRemovedTask(prevSibling)
: null;
// Remove task from parent and replace previousSibling with
// new task group if not already one.
parent.removeUndertaking(task);
if (siblingAsTaskGroup != prevSibling) {
parent.removeUndertaking(prevSibling);
parent.addUndertaking(indexInParent - 1, siblingAsTaskGroup);
}
// Insert task as the last child of siblingAsTaskGroup
makeTaskNameUnique(siblingAsTaskGroup, task);
siblingAsTaskGroup.addUndertaking(task);
// Create undoable edit
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.DemoteTask)
{
protected Map<ITaskDesign, TaskApplication> siblingTAs =
siblingAssocTAs;
protected boolean recoverMgrs = true;
@Override
public String getPresentationName()
{
return DEMOTE_TASK;
}
@Override
public void redo()
{
super.redo();
recoverMgrs = true;
siblingTAs =
(siblingAsTaskGroup != prevSibling)
? project.taskApplicationsForRemovedTask(prevSibling)
: null;
// Remove task from parent and replace previousSibling with
// new task group if not already one.
parent.removeUndertaking(task);
if (siblingAsTaskGroup != prevSibling) {
parent.removeUndertaking(prevSibling);
parent.addUndertaking(indexInParent - 1,
siblingAsTaskGroup);
}
// Insert task as the last child of siblingAsTaskGroup
makeTaskNameUnique(siblingAsTaskGroup, task);
siblingAsTaskGroup.addUndertaking(task);
}
@Override
public void undo()
{
super.undo();
recoverMgrs = false;
// Remove task from sibling group; rename back
siblingAsTaskGroup.removeUndertaking(task);
task.setName(oldTaskName);
// Restore sibling as a task if necessary
if (siblingAsTaskGroup != prevSibling) {
parent.removeUndertaking(siblingAsTaskGroup);
parent.addUndertaking(indexInParent - 1, prevSibling);
project.restoreRemovedTaskApplications(siblingTAs);
}
// Add task back to parent
parent.addUndertaking(indexInParent, task);
}
@Override
public void die()
{
super.die();
if (recoverMgrs && (siblingAsTaskGroup != prevSibling))
{
recoverManagers(task, siblingTAs);
}
}
};
editSeq.addEdit(edit);
return null;
}
protected IListenerAction createDemoteTaskAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
TaskSelectionState seln = (TaskSelectionState) prms;
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
if ((tasks == null) || (tasks.length == 0)) {
interaction.protestNoSelection();
return false;
}
List<String> errors = new ArrayList<String>();
String editLabel =
(tasks.length > 1) ? DEMOTE_TASKS : DEMOTE_TASK;
CompoundUndoableEdit editSeq =
new CompoundUndoableEdit(editLabel,
ProjectLID.DemoteTask);
for (AUndertaking task : tasks) {
String demoteError = demoteTask(task, editSeq);
if (demoteError != null) {
errors.add(demoteError);
}
}
if (errors.size() > 0) {
interaction.reportProblems(editLabel, errors);
}
if (editSeq.isSignificant()) {
editSeq.end();
undoMgr.addEdit(editSeq);
}
return true;
}
};
}
protected boolean moveTaskAction(TaskSelectionState seln,
boolean moveEarlier)
{
AUndertaking[] tasks =
seln.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
if ((tasks == null) || (tasks.length == 0)) {
interaction.protestNoSelection();
return false;
}
if (tasks.length > 1) {
interaction.protestTooManySelectedTasks();
return false;
}
final AUndertaking task = tasks[0];
final TaskParent parent = project.getTaskParent(task);
List<AUndertaking> siblings = parent.getUndertakings();
int siblingCount = siblings.size();
if (siblingCount == 1) {
interaction.setStatusMessage(taskIsOnlyChild);
}
else {
final int oldTaskIndex = siblings.indexOf(task);
IUndoableEdit edit;
if (moveEarlier) {
if (oldTaskIndex == 0) {
interaction.protestCannotMoveEarlier();
return false;
}
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex - 1, task);
edit = new AUndoableEdit(ProjectLID.MoveTaskEarlier)
{
@Override
public String getPresentationName()
{
return MOVE_TASK_EARLIER;
}
@Override
public void redo()
{
super.redo();
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex - 1, task);
}
@Override
public void undo()
{
super.undo();
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex, task);
}
};
}
else {
if (oldTaskIndex == siblingCount - 1) {
interaction.protestCannotMoveLater();
return false;
}
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex + 1, task);
edit = new AUndoableEdit(ProjectLID.MoveTaskEarlier)
{
@Override
public String getPresentationName()
{
return MOVE_TASK_LATER;
}
@Override
public void redo()
{
super.redo();
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex + 1, task);
}
@Override
public void undo()
{
super.undo();
parent.removeUndertaking(task);
parent.addUndertaking(oldTaskIndex, task);
}
};
}
undoMgr.addEdit(edit);
}
return true;
}
protected IListenerAction createMoveTaskEarlierAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
return moveTaskAction((TaskSelectionState) prms, true);
}
};
}
protected IListenerAction createMoveTaskLaterAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return TaskSelectionState.class;
}
public boolean performAction(Object prms)
{
return moveTaskAction((TaskSelectionState) prms, false);
}
};
}
protected boolean exportToHCIPA(Design design, TaskGroup task)
{
String initialName =
project.getName() + "_" + design.getName()
+ "_" + task.getName();
File scriptFile =
interaction.selectExportLocation(initialName,
CogToolFileTypes.PHP_FILE_EXT);
if (scriptFile != null) {
return HCIPACmd.exportToHCIPA(project,
design,
task,
scriptFile);
}
return false;
}
protected IListenerAction createExportToHCIPAAction()
{
return new AListenerAction() {
public boolean performAction(Object prms)
{
ProjectSelectionState sel =
(ProjectSelectionState) prms;
Design design = sel.getSelectedDesign();
AUndertaking[] tasks =
sel.getSelectedTasks(TaskSelectionState.PRUNE_SELECTION |
TaskSelectionState.ORDER_SELECTION);
if (design != null) {
if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
if (tasks[i].isTaskGroup() &&
(tasks[i].getTaskGroup() == null))
{
if (! exportToHCIPA(design,
(TaskGroup) tasks[i]))
{
return false;
}
}
}
}
else {
Iterator<AUndertaking> allTasks =
project.getUndertakings().iterator();
while (allTasks.hasNext()) {
AUndertaking topLevelTask = allTasks.next();
if (topLevelTask.isTaskGroup()) {
if (! exportToHCIPA(design,
(TaskGroup) topLevelTask))
{
return false;
}
}
}
}
}
else if ((tasks != null) && (tasks.length > 0)) {
for (int i = 0; i < tasks.length; i++) {
if (tasks[i].isTaskGroup() &&
(tasks[i].getTaskGroup() == null))
{
Iterator<Design> allDesigns =
project.getDesigns().iterator();
while (allDesigns.hasNext()) {
if (! exportToHCIPA(allDesigns.next(),
(TaskGroup) tasks[i]))
{
return false;
}
}
}
}
}
else {
interaction.protestNoSelection();
return false;
}
return true;
}
};
}
protected IListenerAction createMoveTaskAppAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.MoveCopyTaskApplicationParms.class;
}
public boolean performAction(Object p)
{
if (p != null) {
ProjectUI.MoveCopyTaskApplicationParms parms =
(ProjectUI.MoveCopyTaskApplicationParms) p;
// Must have selected tasks and design
if ((parms.design == null) ||
(parms.fromTask == null) ||
(parms.toTask == null))
{
interaction.protestNoSelection();
return false;
}
final AUndertaking fromTask = parms.fromTask;
final AUndertaking toTask = parms.toTask;
final TaskApplication taskApp =
project.removeTaskApplication(parms.fromTask,
parms.design);
if (taskApp == null) {
interaction.protestNoTaskApplication();
return false;
}
final TaskApplication oldTaskApp =
project.removeTaskApplication(parms.toTask,
parms.design);
taskApp.setTask(toTask);
project.setTaskApplication(taskApp);
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.MoveTaskApplication)
{
@Override
public String getPresentationName()
{
return MOVE_TASKAPP;
}
@Override
public void redo()
{
super.redo();
project.removeTaskApplication(taskApp);
if (oldTaskApp != null) {
project.removeTaskApplication(oldTaskApp);
}
taskApp.setTask(toTask);
project.setTaskApplication(taskApp);
}
@Override
public void undo()
{
super.undo();
project.removeTaskApplication(taskApp);
taskApp.setTask(fromTask);
if (oldTaskApp != null) {
project.setTaskApplication(oldTaskApp);
}
project.setTaskApplication(taskApp);
}
};
undoMgr.addEdit(edit);
}
return true;
}
};
}
protected IListenerAction createDuplicateTaskAppAction()
{
return new IListenerAction() {
public Class<?> getParameterClass()
{
return ProjectUI.MoveCopyTaskApplicationParms.class;
}
public boolean performAction(Object p)
{
if (p != null) {
ProjectUI.MoveCopyTaskApplicationParms parms =
(ProjectUI.MoveCopyTaskApplicationParms) p;
// Must have selected tasks and design
if ((parms.design == null) ||
(parms.fromTask == null) ||
(parms.toTask == null))
{
interaction.protestNoSelection();
return false;
}
final AUndertaking fromTask = parms.fromTask;
final AUndertaking toTask = parms.toTask;
TaskApplication taskApp =
project.getTaskApplication(fromTask, parms.design);
if (taskApp == null) {
interaction.protestNoTaskApplication();
return false;
}
final TaskApplication oldTaskApp =
project.removeTaskApplication(parms.toTask,
parms.design);
final TaskApplication newTaskApp =
taskApp.duplicate(toTask, parms.design);
DemoStateManager demoMgr =
DemoStateManager.getStateManager(project, parms.design);
project.setTaskApplication(newTaskApp);
demoMgr.trackEdits(newTaskApp.getDemonstration());
IUndoableEdit edit =
new AUndoableEdit(ProjectLID.DuplicateTaskApplication)
{
protected boolean recoverMgrs = false;
@Override
public String getPresentationName()
{
return DUPLICATE_TASKAPP;
}
@Override
public void redo()
{
super.redo();
if (oldTaskApp != null) {
project.removeTaskApplication(oldTaskApp);
}
project.setTaskApplication(newTaskApp);
recoverMgrs = false;
}
@Override
public void undo()
{
super.undo();
project.removeTaskApplication(newTaskApp);
if (oldTaskApp != null) {
project.setTaskApplication(oldTaskApp);
}
recoverMgrs = true;
}
@Override
public void die()
{
if (recoverMgrs) {
recoverManagers(newTaskApp);
}
}
};
undoMgr.addEdit(edit);
}
return true;
}
};
}
/**
* Creates a new ProjectController instance for editing a new
* Project instance.
*
* @return the Controller instance for editing a new Project instance
* @author mlh
*/
public static ProjectController newProjectController()
{
ProjectController controller = new ProjectController();
ControllerRegistry.ONLY.addOpenController(controller);
return controller;
}
/**
* Creates a new ProjectController instance for editing an existing
* Project instance.
*
* @param project the Project instance to edit.
* @param unregistered true if and only if the given project has yet
* to be saved
* @param unmodified true if and only if the given project has yet
* to be modified
* @return the Controller instance for editing the given Project instance
* @author mlh
*/
public static ProjectController openController(Project project,
boolean unregistered,
boolean unmodified)
{
// Check whether this project is already open
ProjectController controller =
(ProjectController)
ControllerRegistry.ONLY.findOpenController(project);
// If already open, just bring it to front
if (controller != null) {
controller.takeFocus();
}
else {
// if this project isn't open, create a new controller
controller =
new ProjectController(project, unregistered, unmodified);
ControllerRegistry.ONLY.addOpenController(controller);
}
return controller;
}
}