/*******************************************************************************
* 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.model;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.ecf.core.util.Base64;
import edu.cmu.cs.hcii.cogtool.model.Project.ITaskDesign;
import edu.cmu.cs.hcii.cogtool.util.IAttributed;
import edu.cmu.cs.hcii.cogtool.util.NamedObject;
import edu.cmu.cs.hcii.cogtool.util.XMLOutput;
public class ExportCogToolXML
{
protected static abstract class ExportAttribute<T>
{
protected String attrName;
protected abstract String getXMLAttribute();
protected abstract T castValue(Object value);
protected abstract String toStringValue(T attrValue);
protected ExportAttribute(String attributeName)
{
this.attrName = attributeName;
}
public String getAttributeName()
{
return this.attrName;
}
public void toXML(IAttributed attributed, XMLOutput xmlWriter)
throws IOException
{
T attrValue = castValue(attributed.getAttribute(this.attrName));
xmlWriter.addAttribute(getXMLAttribute(), toStringValue(attrValue));
}
}
protected static abstract class BooleanExportAttribute
extends ExportAttribute<Boolean>
{
protected BooleanExportAttribute(String attributeName)
{
super(attributeName);
}
@Override
protected Boolean castValue(Object value)
{
return (Boolean) value;
}
}
protected static abstract class StringExportAttribute
extends ExportAttribute<String>
{
protected StringExportAttribute(String attributeName)
{
super(attributeName);
}
@Override
protected String castValue(Object value)
{
return (String) value;
}
}
protected static abstract class IntegerExportAttribute
extends ExportAttribute<Integer>
{
protected IntegerExportAttribute(String attributeName)
{
super(attributeName);
}
@Override
protected Integer castValue(Object value)
{
return (Integer) value;
}
}
protected static abstract class DoubleExportAttribute
extends ExportAttribute<Double>
{
protected DoubleExportAttribute(String attributeName)
{
super(attributeName);
}
@Override
protected Double castValue(Object value)
{
return (Double) value;
}
}
protected static final Map<String, ExportAttribute<?>> ATTRIBUTE_REGISTRY =
new HashMap<String, ExportAttribute<?>>();
protected static void registerAttr(ExportAttribute<?> attr)
{
ATTRIBUTE_REGISTRY.put(attr.getAttributeName(), attr);
}
protected static void registerAttributes()
{
registerAttr(new BooleanExportAttribute(WidgetAttributes.IS_SELECTED_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.IS_SELECTED_ATTR;
}
@Override
protected String toStringValue(Boolean attrValue)
{
if (WidgetAttributes.IS_SELECTED.equals(attrValue)) {
return ImportCogToolXML.IS_SELECTED_VALUE;
}
if (WidgetAttributes.NOT_SELECTED.equals(attrValue)) {
return ImportCogToolXML.NOT_SELECTED_VALUE;
}
return ImportCogToolXML.TOGGLE_VALUE;
}
});
registerAttr(new BooleanExportAttribute(WidgetAttributes.IS_TOGGLEABLE_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.IS_TOGGLEABLE_ATTR;
}
@Override
protected String toStringValue(Boolean attrValue)
{
if (WidgetAttributes.IS_TOGGLEABLE.equals(attrValue)) {
return ImportCogToolXML.TRUE_VALUE;
}
return ImportCogToolXML.FALSE_VALUE;
}
});
registerAttr(new BooleanExportAttribute(WidgetAttributes.IS_STANDARD_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.IS_STANDARD_ATTR;
}
@Override
protected String toStringValue(Boolean attrValue)
{
if (WidgetAttributes.IS_STANDARD.equals(attrValue)) {
return ImportCogToolXML.TRUE_VALUE;
}
return ImportCogToolXML.FALSE_VALUE;
}
});
registerAttr(new ExportAttribute<NamedObject>(WidgetAttributes.SELECTION_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.SELECTION_ATTR;
}
@Override
protected NamedObject castValue(Object value)
{
return (NamedObject) value;
}
@Override
protected String toStringValue(NamedObject attrValue)
{
if (attrValue != null) {
return attrValue.getName();
}
return "";
}
});
registerAttr(new BooleanExportAttribute(WidgetAttributes.IS_RENDERED_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.IS_RENDERED_ATTR;
}
@Override
protected String toStringValue(Boolean attrValue)
{
if (Boolean.TRUE.equals(attrValue)) {
return ImportCogToolXML.TRUE_VALUE;
}
return ImportCogToolXML.FALSE_VALUE;
}
});
registerAttr(new BooleanExportAttribute(WidgetAttributes.IS_SEPARATOR_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.IS_SEPARATOR_ATTR;
}
@Override
protected String toStringValue(Boolean attrValue)
{
if (WidgetAttributes.IS_SEPARATOR.equals(attrValue)) {
return ImportCogToolXML.TRUE_VALUE;
}
return ImportCogToolXML.FALSE_VALUE;
}
});
registerAttr(new StringExportAttribute(WidgetAttributes.APPENDED_TEXT_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.APPENDED_TEXT_ATTR;
}
@Override
protected String toStringValue(String attrValue)
{
return (attrValue != null) ? attrValue : "";
}
});
registerAttr(new IntegerExportAttribute(WidgetAttributes.SUBMENU_ACTION_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.SUBMENU_ACTION_ATTR;
}
@Override
protected String toStringValue(Integer attrValue)
{
if (WidgetAttributes.TAP_SUBMENU_ACTION.equals(attrValue)) {
return ImportCogToolXML.TAP_VALUE;
}
if (WidgetAttributes.CLICK_SUBMENU_ACTION.equals(attrValue)) {
return ImportCogToolXML.CLICK_VALUE;
}
return ImportCogToolXML.HOVER_VALUE;
}
});
registerAttr(new DoubleExportAttribute(WidgetAttributes.SUBMENU_DELAY_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.SUBMENU_DELAY_ATTR;
}
@Override
protected String toStringValue(Double attrValue)
{
if (WidgetAttributes.PC_SUBMENU_DELAY.equals(attrValue)) {
return ImportCogToolXML.PC_DELAY_VALUE;
}
return ImportCogToolXML.NO_DELAY_VALUE;
}
});
registerAttr(new IntegerExportAttribute(WidgetAttributes.CONTEXT_MENU_ACTION_ATTR)
{
@Override
protected String getXMLAttribute()
{
return ImportCogToolXML.CONTEXT_MENU_ACTION_ATTR;
}
@Override
protected String toStringValue(Integer attrValue)
{
if (WidgetAttributes.CTRL_LEFT_CLICK.equals(attrValue)) {
return ImportCogToolXML.CTRL_LEFT_VALUE;
}
if (WidgetAttributes.TAP_HOLD.equals(attrValue)) {
return ImportCogToolXML.TAP_HOLD_VALUE;
}
if (WidgetAttributes.MENU_KEY_PRESS.equals(attrValue)) {
return ImportCogToolXML.MENU_KEY_VALUE;
}
return ImportCogToolXML.RIGHT_CLICK_VALUE;
}
});
}
// Don't allow the same attribute to be "published" more than once
// for a given IAttributed instance
protected static IAttributed currentAttributed = null;
protected static Set<String> writtenAttributes = new HashSet<String>();
protected static void addAttributeToXML(IAttributed attributed,
String attrName,
XMLOutput xmlWriter)
throws IOException
{
if (currentAttributed != attributed) {
writtenAttributes.clear();
currentAttributed = attributed;
}
if (! writtenAttributes.contains(attrName)) {
ExportAttribute<?> attrXML = ATTRIBUTE_REGISTRY.get(attrName);
if (attrXML != null) {
attrXML.toXML(attributed, xmlWriter);
writtenAttributes.add(attrName);
}
}
}
protected static void addAttributesToXML(IAttributed attributed,
XMLOutput xmlWriter)
throws IOException
{
if (attributed != null) {
if (notInitialized) {
registerAttributes();
}
Iterator<IAttributed.AttributeDefinition<?>> localAttrs =
attributed.getLocalAttributeNames();
while (localAttrs.hasNext()) {
IAttributed.AttributeDefinition<?> attrDefn = localAttrs.next();
addAttributeToXML(attributed, attrDefn.attrName, xmlWriter);
}
}
}
protected static boolean notInitialized = true;
private static final Map<TaskGroup, Integer> taskGroupIDs =
new HashMap<TaskGroup, Integer>();
private static int nextTaskGroupID = 0;
private static Integer taskGroupID(TaskGroup tg) {
Integer result = taskGroupIDs.get(tg);
if (result == null) {
result = nextTaskGroupID++;
taskGroupIDs.put(tg, result);
}
return result;
}
private ExportCogToolXML() { }
protected static String getBoolean(boolean flag)
{
return flag ? "true" : "false";
}
protected static void outputPoint(String eltName,
DoublePoint pt,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(eltName,
ImportCogToolXML.X_ATTR,
Double.toString(pt.x));
xmlWriter.addAttribute(ImportCogToolXML.Y_ATTR,
Double.toString(pt.y));
xmlWriter.noMoreAttributes(XMLOutput.NO_NESTED_DATA);
}
protected static void outputBounds(String eltName,
DoubleRectangle bds,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(eltName,
ImportCogToolXML.X_ATTR,
Double.toString(bds.x));
xmlWriter.addAttribute(ImportCogToolXML.Y_ATTR,
Double.toString(bds.y));
xmlWriter.addAttribute(ImportCogToolXML.WIDTH_ATTR,
Double.toString(bds.width));
xmlWriter.addAttribute(ImportCogToolXML.HEIGHT_ATTR,
Double.toString(bds.height));
xmlWriter.noMoreAttributes(XMLOutput.NO_NESTED_DATA);
}
protected static void outputBackgroundImage(byte[] imgData,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(ImportCogToolXML.BKG_IMAGE_DATA_ELT);
xmlWriter.outputText(Base64.encode(imgData));
xmlWriter.endElement();
}
protected static void outputActionStep(AAction action,
TransitionSource stepFocus,
TransitionDelay td,
XMLOutput xmlWriter)
throws IOException
{
if (stepFocus instanceof InputDevice) {
InputDevice device = (InputDevice) stepFocus;
if (device.getDeviceType() == DeviceType.Keyboard) {
outputKeyPressAction(ImportCogToolXML.KEYBOARD_STEP_ELT,
(KeyAction) action,
td,
xmlWriter);
}
else if (device.getDeviceType() == DeviceType.Voice) {
outputVoiceAction(ImportCogToolXML.VOICE_STEP_ELT,
(VoiceAction) action,
td,
xmlWriter);
}
else {
throw new IllegalStateException("Unsupported device");
}
}
else if (stepFocus == null) {
xmlWriter.startElementNoAttrs(ImportCogToolXML.ACTION_STEP_ELT);
outputAction(action, xmlWriter);
xmlWriter.endElement();
}
else if (stepFocus instanceof IWidget) {
xmlWriter.startElement(ImportCogToolXML.ACTION_STEP_ELT,
ImportCogToolXML.TARGET_WIDGET_NAME_ATTR,
stepFocus.getName());
outputTransitionDelayAttrs(td, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
outputAction(action, xmlWriter);
xmlWriter.endElement();
}
}
protected static void outputDemonstrationStep(AScriptStep demoStep,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.DEMO_STEP_ELT);
addAttributesToXML(demoStep, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
if (demoStep instanceof ActionScriptStep) {
ActionScriptStep actionStep = (ActionScriptStep) demoStep;
outputActionStep(actionStep.getAction(),
actionStep.getStepFocus(),
actionStep,
xmlWriter);
}
else if (demoStep instanceof TransitionScriptStep) {
TransitionScriptStep transitionStep =
(TransitionScriptStep) demoStep;
outputActionStep(transitionStep.getTransition().getAction(),
transitionStep.getStepFocus(),
null,
xmlWriter);
}
else if (demoStep instanceof ThinkScriptStep) {
ThinkScriptStep thinkStep = (ThinkScriptStep) demoStep;
xmlWriter.startElement(ImportCogToolXML.THINK_STEP_ELT,
ImportCogToolXML.DURATION_ATTR,
Double.toString(thinkStep.getThinkDuration()));
xmlWriter.noMoreAttributes(XMLOutput.NO_NESTED_DATA);
}
else if (demoStep instanceof DelayScriptStep) {
DelayScriptStep delayStep = (DelayScriptStep) demoStep;
xmlWriter.startElement(ImportCogToolXML.SYS_DELAY_STEP_ELT,
ImportCogToolXML.DURATION_ATTR,
Double.toString(delayStep.getDelayDuration()));
xmlWriter.noMoreAttributes(XMLOutput.NO_NESTED_DATA);
}
else if (demoStep instanceof LookAtScriptStep) {
LookAtScriptStep lookAtStep = (LookAtScriptStep) demoStep;
IWidget lookAtTarget = lookAtStep.getLookAtTarget();
xmlWriter.startElement(ImportCogToolXML.LOOK_AT_STEP_ELT,
ImportCogToolXML.LOOKAT_WIDGET_NAME_ATTR,
lookAtTarget.getName());
xmlWriter.noMoreAttributes(XMLOutput.NO_NESTED_DATA);
}
xmlWriter.endElement();
}
protected static void outputStartingHandPosition(String eltName,
HandLocation location,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(eltName);
if (location == HandLocation.OnKeyboard) {
xmlWriter.outputText(ImportCogToolXML.KEYBOARD_DEVICE);
}
else if (location == HandLocation.OnMouse) {
xmlWriter.outputText(ImportCogToolXML.MOUSE_DEVICE);
}
else if (location == HandLocation.OnScreen) {
xmlWriter.outputText(ImportCogToolXML.TOUCHSCREEN_DEVICE);
}
xmlWriter.endElement();
}
protected static void outputDemonstration(AUndertaking task,
Demonstration demo,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.DEMONSTRATION_ELT,
ImportCogToolXML.TASK_NAME_ATTR,
task.getName());
TaskGroup parent = task.getTaskGroup();
if (parent != null) {
xmlWriter.addAttribute(ImportCogToolXML.TASK_GROUP_ID_ATTR,
taskGroupID(parent));
}
Frame startFrame = demo.getStartFrame();
xmlWriter.addAttribute(ImportCogToolXML.START_FRAME_NAME_ATTR,
(startFrame != null) ? startFrame.getName()
: "");
boolean handedness = demo.getMouseHand();
xmlWriter.addAttribute(ImportCogToolXML.HANDEDNESS_ATTR,
(handedness == HandLocation.RIGHT_HAND)
? ImportCogToolXML.RIGHT_HAND
: ImportCogToolXML.LEFT_HAND);
addAttributesToXML(demo, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
DefaultModelGeneratorState initialState = demo.getInitialState();
if (handedness == HandLocation.RIGHT_HAND) {
outputStartingHandPosition(ImportCogToolXML.START_RIGHT_POS_ELT,
initialState.getHandLocation(HandLocation.RIGHT_HAND),
xmlWriter);
}
else {
outputStartingHandPosition(ImportCogToolXML.START_LEFT_POS_ELT,
initialState.getHandLocation(HandLocation.LEFT_HAND),
xmlWriter);
}
Iterator<AScriptStep> demoSteps = demo.getSteps().iterator();
while (demoSteps.hasNext()) {
AScriptStep demoStep = demoSteps.next();
outputDemonstrationStep(demoStep, xmlWriter);
}
xmlWriter.endElement();
}
protected static void outputKeyboardState(String modifier,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(ImportCogToolXML.KBD_MODIFIER_ELT);
xmlWriter.outputText(modifier);
xmlWriter.endElement();
}
protected static void outputKeyboardModifiers(int modifiers,
XMLOutput xmlWriter)
throws IOException
{
if ((modifiers & AAction.SHIFT) != 0) {
outputKeyboardState(ImportCogToolXML.SHIFT_MODIFIER, xmlWriter);
}
if ((modifiers & AAction.CTRL) != 0) {
outputKeyboardState(ImportCogToolXML.CTRL_MODIFIER, xmlWriter);
}
if ((modifiers & AAction.ALT) != 0) {
outputKeyboardState(ImportCogToolXML.ALT_MODIFIER, xmlWriter);
}
if ((modifiers & AAction.COMMAND) != 0) {
outputKeyboardState(ImportCogToolXML.COMMAND_MODIFIER, xmlWriter);
}
if ((modifiers & AAction.FUNCTION) != 0) {
outputKeyboardState(ImportCogToolXML.FUNCTION_MODIFIER, xmlWriter);
}
}
protected static String getButtonValue(MouseButtonState buttonState)
{
if (buttonState == MouseButtonState.Left) {
return ImportCogToolXML.LEFT_BUTTON;
}
if (buttonState == MouseButtonState.Right) {
return ImportCogToolXML.RIGHT_BUTTON;
}
if (buttonState == MouseButtonState.Middle) {
return ImportCogToolXML.MIDDLE_BUTTON;
}
throw new IllegalArgumentException("Unknown button");
}
protected static String getClickType(MousePressType clickType)
{
if (clickType == MousePressType.Click) {
return ImportCogToolXML.DOWNUP_ACTION;
}
if (clickType == MousePressType.Down) {
return ImportCogToolXML.DOWN_ACTION;
}
if (clickType == MousePressType.Up) {
return ImportCogToolXML.UP_ACTION;
}
if (clickType == MousePressType.Double) {
return ImportCogToolXML.DOUBLE_ACTION;
}
if (clickType == MousePressType.Triple) {
return ImportCogToolXML.TRIPLE_ACTION;
}
if (clickType == MousePressType.Hover) {
return ImportCogToolXML.HOVER_ACTION;
}
throw new IllegalArgumentException("Unknown mouse press type");
}
protected static String getTapType(TapPressType tapType)
{
if (tapType == TapPressType.Tap) {
return ImportCogToolXML.DOWNUP_ACTION;
}
if (tapType == TapPressType.Down) {
return ImportCogToolXML.DOWN_ACTION;
}
if (tapType == TapPressType.Up) {
return ImportCogToolXML.UP_ACTION;
}
if (tapType == TapPressType.DoubleTap) {
return ImportCogToolXML.DOUBLE_ACTION;
}
if (tapType == TapPressType.TripleTap) {
return ImportCogToolXML.TRIPLE_ACTION;
}
if (tapType == TapPressType.Hover) {
return ImportCogToolXML.HOVER_ACTION;
}
throw new IllegalArgumentException("Unknown tap press type");
}
protected static String getKeyPressValue(KeyPressType pressType)
{
if (pressType == KeyPressType.Stroke) {
return ImportCogToolXML.PRESS_ACTION;
}
if (pressType == KeyPressType.Down) {
return ImportCogToolXML.DOWN_ACTION;
}
if (pressType == KeyPressType.Up) {
return ImportCogToolXML.UP_ACTION;
}
throw new IllegalArgumentException("Unknown key press type");
}
protected static void outputKeyPressAction(String eltName,
KeyAction keyAction,
TransitionDelay td,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(eltName,
ImportCogToolXML.IS_CMD_ATTR,
getBoolean(keyAction.isCommand()));
xmlWriter.addAttribute(ImportCogToolXML.TYPE_ATTR,
getKeyPressValue(keyAction.getPressType()));
outputTransitionDelayAttrs(td, xmlWriter);
addAttributesToXML(keyAction, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
xmlWriter.startElementNoAttrs(ImportCogToolXML.TEXT_ELT);
xmlWriter.outputText(keyAction.getText(), true);
xmlWriter.endElement();
xmlWriter.endElement();
}
protected static void outputVoiceAction(String eltName,
VoiceAction voiceAction,
TransitionDelay td,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(eltName,
ImportCogToolXML.IS_CMD_ATTR,
getBoolean(voiceAction.isCommand()));
outputTransitionDelayAttrs(td, xmlWriter);
addAttributesToXML(voiceAction, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
xmlWriter.startElementNoAttrs(ImportCogToolXML.TEXT_ELT);
xmlWriter.outputText(voiceAction.getText(), true);
xmlWriter.endElement();
xmlWriter.endElement();
}
protected static void outputAction(AAction action, XMLOutput xmlWriter)
throws IOException
{
if (action instanceof ButtonAction) {
ButtonAction mouseAction = (ButtonAction) action;
MouseButtonState whichButton = mouseAction.getButton();
xmlWriter.startElement(ImportCogToolXML.MOUSE_ACTION_ELT,
ImportCogToolXML.ACTION_ATTR,
getClickType(mouseAction.getPressType()));
if (whichButton != null) {
xmlWriter.addAttribute(ImportCogToolXML.BUTTON_ATTR,
getButtonValue(whichButton));
}
addAttributesToXML(mouseAction, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
outputKeyboardModifiers(mouseAction.getModifiers(), xmlWriter);
xmlWriter.endElement();
}
else if (action instanceof TapAction) {
TapAction tapAction = (TapAction) action;
xmlWriter.startElement(ImportCogToolXML.TOUCHSCREEN_ACTION_ELT,
ImportCogToolXML.ACTION_ATTR,
getTapType(tapAction.getTapPressType()));
addAttributesToXML(tapAction, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
//TODO: outputKeyboardModifiers(tapAction.getModifiers(), xmlWriter);
xmlWriter.endElement();
}
else if (action instanceof GraffitiAction) {
GraffitiAction graffitiAction = (GraffitiAction) action;
xmlWriter.startElement(ImportCogToolXML.GRAFFITI_ACTION_ELT,
ImportCogToolXML.IS_CMD_ATTR,
getBoolean(graffitiAction.isCommand()));
addAttributesToXML(graffitiAction, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
xmlWriter.startElementNoAttrs(ImportCogToolXML.GESTURES_ELT);
xmlWriter.outputText(graffitiAction.getText(), true);
xmlWriter.endElement();
xmlWriter.endElement();
}
else if (action instanceof KeyAction) {
KeyAction keyAction = (KeyAction) action;
outputKeyPressAction(ImportCogToolXML.KEYBOARD_ACTION_ELT,
keyAction,
null,
xmlWriter);
}
else if (action instanceof VoiceAction) {
VoiceAction voiceAction = (VoiceAction) action;
outputVoiceAction(ImportCogToolXML.VOICE_ACTION_ELT,
voiceAction,
null,
xmlWriter);
}
} // outputAction
protected static void outputTransitionDelayAttrs(TransitionDelay td,
XMLOutput xmlWriter)
throws IOException
{
if (td != null) {
double transitionDelay = td.getDelayInSecs();
xmlWriter.addAttribute(ImportCogToolXML.DURATION_ATTR,
Double.toString(transitionDelay));
String delayLabel = td.getDelayLabel();
if (! TransitionDelay.DEFAULT_DELAY_LABEL.equals(delayLabel)) {
xmlWriter.addAttribute(ImportCogToolXML.DELAY_LABEL_ATTR,
delayLabel);
}
}
}
protected static void outputTransition(Transition transition,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.TRANSITION_ELT,
ImportCogToolXML.DEST_FRAME_NAME_ATTR,
transition.getDestination().getName());
outputTransitionDelayAttrs(transition, xmlWriter);
addAttributesToXML(transition, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
xmlWriter.startElementNoAttrs(ImportCogToolXML.ACTION_ELT);
outputAction(transition.getAction(), xmlWriter);
xmlWriter.endElement();
xmlWriter.endElement();
}
protected static void outputTransitions(Iterator<Transition> transitions,
XMLOutput xmlWriter)
throws IOException
{
while (transitions.hasNext()) {
Transition transition = transitions.next();
outputTransition(transition, xmlWriter);
}
}
protected static void outputTransitionSet(String eltName,
Iterator<Transition> transitions,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(eltName);
outputTransitions(transitions, xmlWriter);
xmlWriter.endElement();
}
protected static String getShapeTypeValue(ShapeType shapeType)
{
if (shapeType == ShapeType.Rectangle) {
return ImportCogToolXML.RECTANGLE_SHAPE;
}
if (shapeType == ShapeType.Ellipse) {
return ImportCogToolXML.ELLIPSE_SHAPE;
}
if (shapeType == ShapeType.RoundedRectangle) {
return ImportCogToolXML.ROUND_RECT_SHAPE;
}
throw new IllegalStateException("Unknown shape type");
}
protected static String getWidgetTypeValue(WidgetType wType)
{
switch (wType.getEnumValue()) {
case WidgetType.BUTTON_PERSISTENCE: {
return ImportCogToolXML.BUTTON_WIDGETTYPE;
}
case WidgetType.LINK_PERSISTENCE: {
return ImportCogToolXML.LINK_WIDGETTYPE;
}
case WidgetType.CHECK_PERSISTENCE: {
return ImportCogToolXML.CHECKBOX_WIDGETTYPE;
}
case WidgetType.RADIO_PERSISTENCE: {
return ImportCogToolXML.RADIO_WIDGETTYPE;
}
case WidgetType.TEXTBOX_PERSISTENCE: {
return ImportCogToolXML.TEXTBOX_WIDGETTYPE;
}
case WidgetType.TEXT_PERSISTENCE: {
return ImportCogToolXML.TEXT_WIDGETTYPE;
}
case WidgetType.PULLDOWNLIST_PERSISTENCE: {
return ImportCogToolXML.PULLDOWNLIST_WIDGETTYPE;
}
case WidgetType.PULLDOWNITEM_PERSISTENCE: {
return ImportCogToolXML.PULLDOWNITEM_WIDGETTYPE;
}
case WidgetType.LISTBOXITEM_PERSISTENCE: {
return ImportCogToolXML.LISTBOXITEM_WIDGETTYPE;
}
case WidgetType.CONTEXT_MENU_PERSISTENCE: {
return ImportCogToolXML.CONTEXTMENU_WIDGETTYPE;
}
case WidgetType.MENU_PERSISTENCE: {
return ImportCogToolXML.MENUHEADER_WIDGETTYPE;
}
case WidgetType.SUBMENU_PERSISTENCE: {
return ImportCogToolXML.SUBMENU_WIDGETTYPE;
}
case WidgetType.MENUITEM_PERSISTENCE: {
return ImportCogToolXML.MENUITEM_WIDGETTYPE;
}
case WidgetType.GRAFFITI_PERSISTENCE: {
return ImportCogToolXML.GRAFFITI_WIDGETTYPE;
}
case WidgetType.NONINTERACTIVE_PERSISTENCE: {
return ImportCogToolXML.NONINTERACTIVE_WIDGETTYPE;
}
}
throw new IllegalStateException("Unknown widget type");
}
protected static void addRemoteLabelAttribute(FrameElement elt,
XMLOutput xmlWriter)
throws IOException
{
FrameElement remoteLabelOwner = elt.getRemoteLabelOwner();
if (remoteLabelOwner != null) {
IWidget remoteLabel =
(IWidget) remoteLabelOwner.getAttribute(WidgetAttributes.REMOTE_LABEL_ATTR);
if (remoteLabel != null) {
xmlWriter.addAttribute(ImportCogToolXML.REMOTE_LABEL_ATTR,
remoteLabel.getName());
}
}
}
protected static void outputWidget(IWidget widget, XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.WIDGET_ELT,
ImportCogToolXML.NAME_ATTR,
widget.getName());
xmlWriter.addAttribute(ImportCogToolXML.TYPE_ATTR,
getWidgetTypeValue(widget.getWidgetType()));
if (widget instanceof ChildWidget) {
ChildWidget asChild = (ChildWidget) widget;
IWidget parent = asChild.getParent();
if (parent != null) {
xmlWriter.addAttribute(ImportCogToolXML.PARENT_ATTR,
parent.getName());
}
}
else if ((widget instanceof MenuHeader) ||
(widget instanceof ListItem))
{
addGroupNameAttribute(widget.getParentGroup(), xmlWriter);
}
else if (widget instanceof GridButton) {
GridButton gridWidget = (GridButton) widget;
GridButtonGroup group =
(GridButtonGroup) gridWidget.getParentGroup();
xmlWriter.addAttribute(ImportCogToolXML.X_ATTR,
gridWidget.getHorizSpace());
xmlWriter.addAttribute(ImportCogToolXML.Y_ATTR,
gridWidget.getVertSpace());
addGroupNameAttribute(group, xmlWriter);
}
AShape widgetShape = widget.getShape();
xmlWriter.addAttribute(ImportCogToolXML.SHAPE_ATTR,
getShapeTypeValue(widgetShape.getShapeType()));
addAttributesToXML(widget, xmlWriter);
// Handle needed attributes that may not be set on the widget itself
if (widget.isStandard()) {
if (widget.getDefiner(WidgetAttributes.IS_STANDARD_ATTR) == null) {
xmlWriter.addAttribute(ImportCogToolXML.IS_STANDARD_ATTR,
ImportCogToolXML.TRUE_VALUE);
}
}
if (widget.isRendered()) { // default is not rendered
addAttributeToXML(widget,
WidgetAttributes.IS_RENDERED_ATTR,
xmlWriter);
}
if (! widget.isAttributeDefault(WidgetAttributes.SUBMENU_ACTION_ATTR)) {
addAttributeToXML(widget,
WidgetAttributes.SUBMENU_ACTION_ATTR,
xmlWriter);
}
if (! widget.isAttributeDefault(WidgetAttributes.SUBMENU_DELAY_ATTR)) {
addAttributeToXML(widget,
WidgetAttributes.SUBMENU_DELAY_ATTR,
xmlWriter);
}
addRemoteLabelAttribute(widget, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
String title = widget.getTitle();
if ((title != null) && (! title.equals(""))) {
xmlWriter.startElementNoAttrs(ImportCogToolXML.DISPLAY_LABEL_ELT);
xmlWriter.outputText(title, true);
xmlWriter.endElement();
}
String aux = widget.getAuxiliaryText();
if ((aux != null) && (! aux.equals(""))) {
xmlWriter.startElementNoAttrs(ImportCogToolXML.AUX_TEXT_ELT);
xmlWriter.outputText(aux, true);
xmlWriter.endElement();
}
outputBounds(ImportCogToolXML.EXTENT_ELT,
widgetShape.getBounds(),
xmlWriter);
byte[] bkgImage = widget.getImage();
if (bkgImage != null) {
outputBackgroundImage(bkgImage, xmlWriter);
}
outputTransitions(widget.getTransitions().values().iterator(),
xmlWriter);
xmlWriter.endElement();
} // outputWidget
protected static void outputEltGroup(FrameElementGroup eltGroup,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.ELTGROUP_ELT,
ImportCogToolXML.NAME_ATTR,
eltGroup.getName());
addRemoteLabelAttribute(eltGroup, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
String aux = eltGroup.getAuxiliaryText();
if ((aux != null) && (! aux.equals(""))) {
xmlWriter.startElementNoAttrs(ImportCogToolXML.AUX_TEXT_ELT);
xmlWriter.outputText(aux, true);
xmlWriter.endElement();
}
for (FrameElement elt : eltGroup) {
String eltName = null;
if (elt instanceof IWidget) {
eltName = ((IWidget) elt).getName();
}
else if (elt instanceof FrameElementGroup) {
eltName = ((FrameElementGroup) elt).getName();
}
else if (elt instanceof SimpleWidgetGroup) {
eltName = determineGroupName((SimpleWidgetGroup) elt);
}
if (eltName != null) {
xmlWriter.startElementNoAttrs(ImportCogToolXML.ELTNAME_ELT);
xmlWriter.outputText(eltName);
xmlWriter.endElement();
}
}
xmlWriter.endElement();
}
protected static void outputSpeakerText(String speakerText,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(ImportCogToolXML.SPEAKER_TEXT_ELT);
xmlWriter.outputText(speakerText, true);
xmlWriter.endElement();
}
protected static void outputListenTime(double listenTimeInSecs,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(ImportCogToolXML.LISTEN_TIME_SECS_ELT);
xmlWriter.outputText(Double.toString(listenTimeInSecs), true);
xmlWriter.endElement();
}
protected static void outputFrame(Frame frame, XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.FRAME_ELT,
ImportCogToolXML.NAME_ATTR,
frame.getName());
addAttributesToXML(frame, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
byte[] bkgImage = frame.getBackgroundImage();
if (bkgImage != null) {
outputBackgroundImage(bkgImage, xmlWriter);
}
DoublePoint frameOrigin = frame.getFrameOrigin();
if (frameOrigin != null) {
outputPoint(ImportCogToolXML.ORIGIN_ELT, frameOrigin, xmlWriter);
}
String speakerText = frame.getSpeakerText();
if ((speakerText != null) && ! speakerText.equals("")) {
outputSpeakerText(speakerText, xmlWriter);
}
double listenTimeInSecs = frame.getListenTimeInSecs();
if (listenTimeInSecs > 0.0) {
outputListenTime(listenTimeInSecs, xmlWriter);
}
Iterator<IWidget> widgets = frame.getWidgets().iterator();
while (widgets.hasNext()) {
IWidget widget = widgets.next();
outputWidget(widget, xmlWriter);
}
Iterator<FrameElementGroup> groups = frame.getEltGroups().iterator();
while (groups.hasNext()) {
FrameElementGroup group = groups.next();
outputEltGroup(group, xmlWriter);
}
InputDevice device = frame.getInputDevice(DeviceType.Keyboard);
if (device != null) {
Collection<Transition> transitions = device.getTransitions().values();
if (transitions.size() > 0) {
outputTransitionSet(ImportCogToolXML.KEYBOARD_TRANSITIONS_ELT,
transitions.iterator(),
xmlWriter);
}
}
device = frame.getInputDevice(DeviceType.Voice);
if (device != null) {
Collection<Transition> transitions = device.getTransitions().values();
if (transitions.size() > 0) {
outputTransitionSet(ImportCogToolXML.VOICE_TRANSITIONS_ELT,
transitions.iterator(),
xmlWriter);
}
}
xmlWriter.endElement();
}
protected static void outputDeviceType(DeviceType deviceType,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElementNoAttrs(ImportCogToolXML.DEVICE_ELT);
switch (deviceType.getEnumValue()) {
case DeviceType.KEYBOARD_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.KEYBOARD_DEVICE);
break;
}
case DeviceType.MOUSE_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.MOUSE_DEVICE);
break;
}
case DeviceType.TOUCHSCREEN_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.TOUCHSCREEN_DEVICE);
break;
}
case DeviceType.VOICE_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.MICROPHONE_DEVICE);
break;
}
case DeviceType.DISPLAY_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.DISPLAY_DEVICE);
break;
}
case DeviceType.SPEAKER_PERSISTENCE: {
xmlWriter.outputText(ImportCogToolXML.SPEAKER_DEVICE);
break;
}
default: {
throw new IllegalStateException("Unknown device type");
}
}
xmlWriter.endElement();
}
protected static void outputDesign(Design design,
Map<ITaskDesign, TaskApplication> designTAs,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.DESIGN_ELT,
ImportCogToolXML.NAME_ATTR,
design.getName());
addAttributesToXML(design, xmlWriter);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
Iterator<DeviceType> deviceTypes = design.getDeviceTypes().iterator();
while (deviceTypes.hasNext()) {
DeviceType deviceType = deviceTypes.next();
outputDeviceType(deviceType, xmlWriter);
}
Iterator<Frame> frames = design.getFrames().iterator();
while (frames.hasNext()) {
Frame frame = frames.next();
outputFrame(frame, xmlWriter);
}
Iterator<Map.Entry<ITaskDesign, TaskApplication>> taskApps =
designTAs.entrySet().iterator();
while (taskApps.hasNext()) {
Map.Entry<ITaskDesign, TaskApplication> entry = taskApps.next();
AUndertaking task = entry.getKey().getTask();
TaskApplication taskApp = entry.getValue();
outputDemonstration(task, taskApp.getDemonstration(), xmlWriter);
}
xmlWriter.endElement();
}
private static void outputTask(Task task, XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.TASK_ELT);
xmlWriter.addAttribute(ImportCogToolXML.NAME_ATTR, task.getName());
xmlWriter.noMoreAttributes(true);
}
private static void outputTaskGroup(TaskGroup taskGroup,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.startElement(ImportCogToolXML.TASK_GROUP_ELT);
xmlWriter.addAttribute(ImportCogToolXML.NAME_ATTR,
taskGroup.getName());
xmlWriter.addAttribute(ImportCogToolXML.TASK_GROUP_ID_ATTR,
taskGroupID(taskGroup));
xmlWriter.addAttribute(ImportCogToolXML.GROUP_NATURE_ATTR,
taskGroup.getNature().getName());
xmlWriter.noMoreAttributes(false);
for (AUndertaking task : taskGroup.getUndertakings()) {
outputUndertaking(task, xmlWriter);
}
xmlWriter.endElement();
}
private static void outputUndertaking(AUndertaking task,
XMLOutput xmlWriter)
throws IOException
{
if (task.isTaskGroup()) {
outputTaskGroup((TaskGroup)task, xmlWriter);
} else {
outputTask((Task)task, xmlWriter);
}
}
protected static void outputProject(Project project, XMLOutput xmlWriter)
throws IOException
{
for (Design design : project.getDesigns()) {
outputDesign(design,
project.taskApplicationsForDesign(design),
xmlWriter);
}
for (AUndertaking task : project.getUndertakings()) {
outputUndertaking(task, xmlWriter);
}
}
// At the moment, this class is all static; although it is not
// strictly necessary, resetting this registry after use
// reduces memory "footprint"
protected static final Map<SimpleWidgetGroup, String> GROUP_REGISTRY =
new HashMap<SimpleWidgetGroup, String>();
protected static String determineGroupName(SimpleWidgetGroup widgetGroup)
{
String grpName = GROUP_REGISTRY.get(widgetGroup);
if (grpName == null) {
grpName = widgetGroup.getName();
if ((grpName == null) || "".equals(grpName)) {
grpName =
"__anonymous-group-" + Integer.toString(GROUP_REGISTRY.size() + 1);
}
GROUP_REGISTRY.put(widgetGroup, grpName);
}
return grpName;
}
protected static void addGroupNameAttribute(SimpleWidgetGroup widgetGroup,
XMLOutput xmlWriter)
throws IOException
{
xmlWriter.addAttribute(ImportCogToolXML.GROUP_ATTR,
determineGroupName(widgetGroup));
}
public static void exportXML(Design design,
Map<ITaskDesign, TaskApplication> designTAs,
Writer sink,
String characterEncoding)
throws IOException
{
try {
XMLOutput xmlWriter = new XMLOutput(sink, characterEncoding);
xmlWriter.outputXMLHeader();
xmlWriter.startElement(ImportCogToolXML.COGTOOL_IMPORT_ELT,
ImportCogToolXML.VERSION_ATTR,
ImportCogToolXML.CURRENT_VERSION);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
outputDesign(design, designTAs, xmlWriter);
xmlWriter.endElement();
}
finally {
// clear the registries
GROUP_REGISTRY.clear();
writtenAttributes.clear();
currentAttributed = null;
taskGroupIDs.clear();
}
}
public static void exportXML(Project project,
Writer sink,
String characterEncoding)
throws IOException
{
try {
XMLOutput xmlWriter = new XMLOutput(sink, characterEncoding);
xmlWriter.outputXMLHeader();
xmlWriter.startElement(ImportCogToolXML.COGTOOL_IMPORT_ELT,
ImportCogToolXML.VERSION_ATTR,
ImportCogToolXML.CURRENT_VERSION);
xmlWriter.noMoreAttributes(XMLOutput.HAS_NESTED_DATA);
outputProject(project, xmlWriter);
xmlWriter.endElement();
}
finally {
// clear the registries
GROUP_REGISTRY.clear();
writtenAttributes.clear();
currentAttributed = null;
taskGroupIDs.clear();
}
}
}