/*******************************************************************************
* CogTool Copyright Notice and Distribution Terms
* CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* CogTool is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* CogTool is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CogTool; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* CogTool makes use of several third-party components, with the
* following notices:
*
* Eclipse SWT version 3.448
* Eclipse GEF Draw2D version 3.2.1
*
* Unless otherwise indicated, all Content made available by the Eclipse
* Foundation is provided to you under the terms and conditions of the Eclipse
* Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this
* Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
*
* CLISP version 2.38
*
* Copyright (c) Sam Steingold, Bruno Haible 2001-2006
* This software is distributed under the terms of the FSF Gnu Public License.
* See COPYRIGHT file in clisp installation folder for more information.
*
* ACT-R 6.0
*
* Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere &
* John R Anderson.
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* Apache Jakarta Commons-Lang 2.1
*
* This product contains software developed by the Apache Software Foundation
* (http://www.apache.org/)
*
* jopt-simple version 1.0
*
* Copyright (c) 2004-2013 Paul R. Holser, Jr.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Mozilla XULRunner 1.9.0.5
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/.
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The J2SE(TM) Java Runtime Environment version 5.0
*
* Copyright 2009 Sun Microsystems, Inc., 4150
* Network Circle, Santa Clara, California 95054, U.S.A. All
* rights reserved. U.S.
* See the LICENSE file in the jre folder for more information.
******************************************************************************/
package edu.cmu.cs.hcii.cogtool.ui;
import java.util.Collection;
import java.util.EventObject;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Label;
import edu.cmu.cs.hcii.cogtool.CogToolLID;
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.DoubleSize;
import edu.cmu.cs.hcii.cogtool.model.Frame;
import edu.cmu.cs.hcii.cogtool.model.Script;
import edu.cmu.cs.hcii.cogtool.model.AScriptStep;
import edu.cmu.cs.hcii.cogtool.model.TaskApplication;
import edu.cmu.cs.hcii.cogtool.model.TaskGroup;
import edu.cmu.cs.hcii.cogtool.model.AUndertaking;
import edu.cmu.cs.hcii.cogtool.model.ListChange;
import edu.cmu.cs.hcii.cogtool.model.Project;
import edu.cmu.cs.hcii.cogtool.uimodel.DefaultSEUIModel;
import edu.cmu.cs.hcii.cogtool.util.AlertHandler;
import edu.cmu.cs.hcii.cogtool.util.L10N;
import edu.cmu.cs.hcii.cogtool.util.ListenerIdentifierMap;
import edu.cmu.cs.hcii.cogtool.util.MenuUtil;
import edu.cmu.cs.hcii.cogtool.util.NameChangeAlert;
import edu.cmu.cs.hcii.cogtool.util.OSUtils;
import edu.cmu.cs.hcii.cogtool.util.PrecisionUtilities;
import edu.cmu.cs.hcii.cogtool.util.SWTStringUtil;
import edu.cmu.cs.hcii.cogtool.util.StringUtil;
import edu.cmu.cs.hcii.cogtool.util.UndoManager;
import edu.cmu.cs.hcii.cogtool.view.DefaultSEView;
import edu.cmu.cs.hcii.cogtool.view.StandardDrawingEditor;
public abstract class SEDefaultUI extends ZoomableUI
{
protected AUndertaking task; // cached from uiModel!
protected Design design; // cached from uiModel!
protected DefaultSEView view = null;
protected DefaultSEUIModel uiModel = null;
protected MouseListener frameLabelListener =
new MouseAdapter()
{
@Override
public void mouseDoubleClick(MouseEvent evt)
{
Label frameNameLabel = (Label) evt.getSource();
Frame f = design.getFrame(frameNameLabel.getText());
if (f != null) {
performAction(DesignEditorLID.EditFrame, f);
}
}
};
protected DefaultSEUIModel getDefaultUIModel()
{
// Overridden by SEDemoUI and ScriptViewerUI
return null;
}
protected AlertHandler frameNameChangeHandler =
new AlertHandler() {
public void handleAlert(EventObject alert) {
// This should be just a name change, so rebuild the list.
updateView();
}
};
// Used by SEDemoUI and ScriptViewerUI to handle new input devices
protected AlertHandler inputDeviceChangeHandler =
new AlertHandler()
{
public void handleAlert(EventObject alert)
{
Frame.InputDeviceChange deviceChange =
(Frame.InputDeviceChange) alert;
view.addInputDevice(deviceChange.newDevice);
uiModel.updateDeviceDisplay();
}
};
protected static final String SCRIPT_PREFIX =
L10N.get("WT.ScriptPrefix", "Script");
protected static String buildWindowMenuLabel(Design design,
AUndertaking task)
{
String designName = SWTStringUtil.insertEllipsis(design.getName(),
StringUtil.EQUAL,
SWTStringUtil.DEFAULT_FONT);
String taskName = SWTStringUtil.insertEllipsis(task.getName(),
StringUtil.EQUAL,
SWTStringUtil.DEFAULT_FONT);
return SCRIPT_PREFIX + ": " + designName + " > " + taskName;
}
public SEDefaultUI(AUndertaking t,
Design d,
Project scriptProject,
UndoManager undoMgr,
boolean supportSpeaker)
{
super(scriptProject,
buildWindowMenuLabel(d, t),
buildLeadItems(scriptProject, d),
undoMgr);
task = t;
design = d;
task.addHandler(this, NameChangeAlert.class, renameHandler);
design.addHandler(this,
NameChangeAlert.class,
renameHandler);
if (supportSpeaker) {
design.addHandler(this,
Design.DeviceTypeChange.class,
new AlertHandler() {
public void handleAlert(EventObject alert)
{
Set<DeviceType> dts =
design.getDeviceTypes();
int deviceTypes =
DeviceType.buildDeviceSet(dts);
view.addSpeakerDevice(deviceTypes);
}
});
}
Iterator<Frame> iter = design.getFrames().iterator();
while (iter.hasNext()) {
Frame frame = iter.next();
frame.addHandler(this,
NameChangeAlert.class,
frameNameChangeHandler);
}
project.addHandler(this,
Project.DesignChange.class,
new AlertHandler()
{
public void handleAlert(EventObject alert)
{
Project.DesignChange chg =
(Project.DesignChange) alert;
if ((! chg.isAdd) &&
(chg.element == design))
{
closeOpenController();
}
}
});
project.addHandler(this,
Project.TaskChange.class,
new AlertHandler()
{
public void handleAlert(EventObject alert)
{
Project.TaskChange chg =
(Project.TaskChange) alert;
if ((! chg.isAdd) &&
(chg.element == task))
{
closeOpenController();
}
}
});
design.addHandler(this,
TaskApplication.TaskApplicationResultChange.class,
new AlertHandler()
{
public void handleAlert(EventObject alert)
{
TaskApplication.TaskApplicationResultChange chg =
(TaskApplication.TaskApplicationResultChange) alert;
TaskApplication taskApp =
project.getTaskApplication(chg.task,
design);
// If not in the project, must be removed!
if (taskApp == null) {
closeOpenController();
}
}
});
AlertHandler closeIfContextRemovedHandler =
new AlertHandler()
{
public void handleAlert(EventObject alert)
{
ListChange chg = (ListChange) alert;
if ((! chg.isAdd) &&
((chg.element == design) || (chg.element == task)))
{
closeOpenController();
}
}
};
project.addHandler(this,
Project.DesignChange.class,
closeIfContextRemovedHandler);
project.addHandler(this,
Project.TaskChange.class,
closeIfContextRemovedHandler);
addCloseIfTaskRemoved(project.getUndertakings().iterator(),
closeIfContextRemovedHandler);
}
protected AlertHandler handleWidgetShapeChange =
new AlertHandler() {
public void handleAlert(EventObject alert)
{
resetVisibleArea();
}
};
public void resetVisibleArea()
{
StandardDrawingEditor e = view.getEditor();
e.getLWS().getUpdateManager().performUpdate();
DoubleSize extent = uiModel.getCurrentFrame().getPreferredSize();
e.setMinVisibleArea(PrecisionUtilities.round(extent.width),
PrecisionUtilities.round(extent.height),
false);
}
protected void setViewUIModel(DefaultSEView v, DefaultSEUIModel uim)
{
view = v;
uiModel = uim;
}
protected abstract void updateView();
protected void addRemoveFrameNameChgHandler(Frame frame, boolean add)
{
if (add) {
// Add a handler for name change events.
frame.addHandler(this,
NameChangeAlert.class,
frameNameChangeHandler);
}
else {
// Remove the handler for name change events.
frame.removeHandler(NameChangeAlert.class,
frameNameChangeHandler);
}
}
protected boolean determineNextSelection(Script script,
Collection<AScriptStep> scriptSteps,
int action,
int stepIndex,
DelayedSelection seln)
{
Demonstration demo = script.getDemonstration();
int numDemoSteps = demo.getStepCount();
boolean computableChange;
// This works for Demonstration.ScriptStepChange.REMOVE_STEP
// since the removed object's index should be the next item
// to select.
if (action == Demonstration.ScriptStepChange.ADD_STEP) {
// Select the next item after those that were added
if (scriptSteps != null) {
int numStepsAdded = scriptSteps.size();
stepIndex += numStepsAdded;
computableChange = (numDemoSteps == numStepsAdded);
}
else {
stepIndex++;
computableChange = (numDemoSteps == 1);
}
}
else {
computableChange = (numDemoSteps == 0);
}
AScriptStep stepToSelect = demo.getStepAt(stepIndex);
seln.addToSelection(stepToSelect);
return computableChange;
}
protected void addCloseIfTaskRemoved(Iterator<AUndertaking> undertakings,
AlertHandler closeIfTaskRemovedHandler)
{
while (undertakings.hasNext()) {
AUndertaking undertaking = undertakings.next();
if (undertaking.isTaskGroup()) {
TaskGroup taskGroup = (TaskGroup) undertaking;
taskGroup.addHandler(this,
TaskGroup.TaskChange.class,
closeIfTaskRemovedHandler);
Iterator<AUndertaking> childUndertakings =
taskGroup.getUndertakings().iterator();
addCloseIfTaskRemoved(childUndertakings,
closeIfTaskRemovedHandler);
}
}
}
@Override
protected void updateTitle()
{
String taskName = SWTStringUtil.insertEllipsis(task.getName(),
StringUtil.EQUAL,
SWTStringUtil.DEFAULT_FONT);
getView().setWindowTitle(modificationFlag
+ SCRIPT_PREFIX
+ ": "
+ project.getName()
+ " > "
+ design.getName()
+ " > "
+ taskName
+ (OSUtils.MACOSX ? "" : UI.WINDOW_TITLE));
}
@Override
protected String buildWindowMenuLabel()
{
return buildWindowMenuLabel(design, task);
}
/**
* Sets the "always-enabled" widgets;
* call this at the end of the subclass constructor!
*/
@Override
protected void setInitiallyEnabled(boolean forConstruction)
{
super.setInitiallyEnabled(forConstruction);
setEnabled(CogToolLID.ZoomIn,
ListenerIdentifierMap.ALL,
MenuUtil.ENABLED);
setEnabled(CogToolLID.ZoomOut,
ListenerIdentifierMap.ALL,
MenuUtil.ENABLED);
setEnabled(CogToolLID.ZoomNormal,
ListenerIdentifierMap.ALL,
MenuUtil.ENABLED);
setEnabled(CogToolLID.ZoomToFit,
ListenerIdentifierMap.ALL,
MenuUtil.ENABLED);
// Turn off paste
setEnabled(CogToolLID.Paste,
ListenerIdentifierMap.ALL,
MenuUtil.DISABLED);
}
protected void removeTaskGroupHandlers(Iterator<AUndertaking> undertakings)
{
while (undertakings.hasNext()) {
AUndertaking undertaking = undertakings.next();
if (undertaking.isTaskGroup()) {
((TaskGroup) undertaking).removeAllHandlers(this);
}
}
}
@Override
public void dispose()
{
removeTaskGroupHandlers(project.getUndertakings().iterator());
task.removeAllHandlers(this);
design.removeAllHandlers(this);
Iterator<Frame> iter = design.getFrames().iterator();
while (iter.hasNext()) {
Frame frame = iter.next();
frame.removeAllHandlers(this);
}
super.dispose();
}
}