// Copyright 2012 Georg-August-Universität Göttingen, Germany
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package de.ugoe.cs.autoquest.plugin.jfc.commands;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import de.ugoe.cs.autoquest.CommandHelpers;
import de.ugoe.cs.autoquest.SequenceInstanceOf;
import de.ugoe.cs.util.console.Command;
import de.ugoe.cs.autoquest.eventcore.Event;
import de.ugoe.cs.autoquest.eventcore.gui.*;
import de.ugoe.cs.autoquest.plugin.jfc.guimodel.JFCGUIElement;
import de.ugoe.cs.util.console.Console;
import de.ugoe.cs.util.console.GlobalDataContainer;
/**
*
* Command to create a Jacareto xml replay file from stored sessions.
*
*
* @author Daniel May
* @version 1.0
*/
public class CMDgenerateJacaretoReplay implements Command {
private int nextRef;
private JFCGUIElement currentFocus;
/*
* (non-Javadoc)
*
* @see de.ugoe.cs.util.console.Command#help()
*/
@Override
public String help() {
return "generateJacaretoReplay ";
}
/*
* (non-Javadoc)
*
* @see de.ugoe.cs.util.console.Command#run(java.util.List)
*/
@SuppressWarnings("unchecked")
@Override
public void run(List parameters) {
String filename;
String sequencesName;
try {
filename = (String) parameters.get(0);
sequencesName = (String) parameters.get(1);
}
catch (Exception e) {
throw new IllegalArgumentException();
}
Collection> sequences = null;
Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName);
if (dataObject == null) {
CommandHelpers.objectNotFoundMessage(sequencesName);
return;
}
if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
CommandHelpers.objectNotType(sequencesName, "Collection>>");
return;
}
sequences = (Collection>) dataObject;
writeJacaretoXML(sequences, filename);
}
private void writeLine(BufferedWriter writer, String line) throws IOException {
writer.write(line);
writer.newLine();
}
private void writeJacaretoHead(BufferedWriter writer) throws IOException {
writeLine(writer, "");
writeLine(writer, "");
writeLine(writer, "");
// TODO: This header content is basically copy+paste from a
// specific jacareto replay file right now.
// Some things such as screen resolution and especially the
// application starter details need to be changed for general cases.
writeLine(writer,
" ");
writeLine(writer,
" ");
writeLine(writer,
" ");
writeLine(writer, " ");
writeLine(writer,
" ");
}
private ArrayList writeJacaretoEvents(BufferedWriter writer,
Collection> sequences)
throws IOException
{
ArrayList structure = new ArrayList();
structure.add("");
// reference the elements that we included in the header
structure.add(" "); // Calendar
structure.add(" "); // SystemInfo
structure.add(" "); // KeyboardState
structure.add(" "); // ComponentMode
structure.add(" "); // ApplicationStarter
nextRef = 5;
for (List sequence : sequences) {
for (Iterator eventIter = sequence.iterator(); eventIter.hasNext();) {
Event event = eventIter.next();
if (event.getType() instanceof MouseButtonDown) {
structure.add("");
writeMouseClickEvent(writer, structure, event, 501);
}
else if (event.getType() instanceof MouseButtonUp) {
writeMouseClickEvent(writer, structure, event, 502);
}
else if (event.getType() instanceof MouseClick) {
writeMouseClickEvent(writer, structure, event, 500);
structure.add(" ");
// FIXME: don't always write an item action
writeItemActionEvent(writer, structure, event);
}
/*
else if (event.getType() instanceof KeyboardFocusChange) {
writeFocusChangeEvent(writer, structure, event);
}
*/
}
}
return structure;
}
private void writeJacaretoTail(BufferedWriter writer, ArrayList structure)
throws IOException
{
writeLine(writer, "
");
// write the recording's structure
writeLine(writer, "");
for (String element : structure) {
writeLine(writer, element);
}
// close root element
writeLine(writer, "");
writeLine(writer, " ");
}
private void writeJacaretoXML(Collection> sequences, String filename) {
BufferedWriter writer = new BufferedWriter(openReplayFile(filename + ".xml"));
try {
writeJacaretoHead(writer);
ArrayList structure = writeJacaretoEvents(writer, sequences);
writeJacaretoTail(writer, structure);
writeLine(writer, "
");
writer.flush();
writer.close();
}
catch (IOException e) {
Console.printerrln("Unable to write Jacareto replay file " + filename);
}
}
/**
*
* Helper function that opens the replay file for writing.
*
*
* @param filename
* name and path of the replay file
* @param encoding
* file encoding, empty string for platform default
* @return {@link OutputStreamWriter} that writes to the replay file
*/
private OutputStreamWriter openReplayFile(String filename) {
File file = new File(filename);
boolean fileCreated;
try {
fileCreated = file.createNewFile();
if (!fileCreated) {
Console.traceln(Level.INFO, "Created logfile " + filename);
}
else {
Console.traceln(Level.INFO, "Overwrote existing logfile " + filename);
}
}
catch (IOException e) {
Console.printerrln("Unable to create file " + filename);
Console.logException(e);
}
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(file));
}
catch (IOException e) {
Console.printerrln("Unable to open file for writing (read-only file):" + filename);
Console.logException(e);
}
return writer;
}
private void writeItemActionEvent(BufferedWriter writer,
ArrayList structure,
Event event) throws IOException
{
JFCGUIElement target = (JFCGUIElement) event.getTarget();
MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
//@formatter:off
writeLine(writer,
" "
);
writeLine(writer,
" "
);
//@formatter:on
structure.add("");
structure.add(" ");
structure.add(" ");
structure.add(" ");
}
private void writeFocusChangeEvent(BufferedWriter writer,
ArrayList structure,
Event event) throws IOException
{
KeyboardFocusChange info = (KeyboardFocusChange) event.getType();
JFCGUIElement target = (JFCGUIElement) event.getTarget();
if (currentFocus != null) {
// focus lost on old target
writeFocusEvent(writer, structure, info, currentFocus, 1005);
// focus gained on new target
writeFocusEvent(writer, structure, info, target, 1004);
}
else {
// TODO: it seems like Jacareto wants a window activation before
// the first focus event but that is not the case in autoquest,
// skip for now
}
currentFocus = target;
}
private void writeFocusEvent(BufferedWriter writer,
ArrayList structure,
KeyboardFocusChange info,
JFCGUIElement target,
int jacId) throws IOException
{
//@formatter:off
writeLine(writer,
" "
);
//@formatter:on
}
private void writeMouseClickEvent(BufferedWriter writer,
ArrayList structure,
Event event,
int jacId) throws IOException
{
MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
JFCGUIElement target = (JFCGUIElement) event.getTarget();
int clickCount = event.getType() instanceof MouseDoubleClick ? 2 : 1;
// TODO: change procTime and duration to adequate values
//@formatter:off
writeLine(writer,
""
);
writeLine(writer,
" "
);
writeLine(writer, " ");
//@formatter:on
structure.add(" ");
}
private int getButtonModifier(MouseButtonInteraction info) {
switch (info.getButton())
{
case LEFT:
return 16;
case MIDDLE:
return 8;
case RIGHT:
return 4;
default:
// TODO: handle unknown mouse button
return -1;
}
}
}