source: trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/commands/CMDgenerateJacaretoReplay.java @ 1685

Last change on this file since 1685 was 1685, checked in by dmay, 10 years ago

implement middle clicks, right clicks and double clicks - still a bit untested though

  • Property svn:mime-type set to text/plain
File size: 12.3 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.plugin.jfc.commands;
16
17import java.io.BufferedWriter;
18import java.io.File;
19import java.io.FileOutputStream;
20import java.io.IOException;
21import java.io.OutputStreamWriter;
22import java.util.ArrayList;
23import java.util.Collection;
24import java.util.Iterator;
25import java.util.List;
26import java.util.UUID;
27import java.util.logging.Level;
28
29import de.ugoe.cs.autoquest.CommandHelpers;
30import de.ugoe.cs.autoquest.SequenceInstanceOf;
31import de.ugoe.cs.util.console.Command;
32import de.ugoe.cs.autoquest.eventcore.Event;
33import de.ugoe.cs.autoquest.eventcore.gui.*;
34import de.ugoe.cs.autoquest.plugin.jfc.guimodel.JFCGUIElement;
35import de.ugoe.cs.util.console.Console;
36import de.ugoe.cs.util.console.GlobalDataContainer;
37
38/**
39 * <p>
40 * Command to create a Jacareto xml replay file from stored sessions.
41 * </p>
42 *
43 * @author Daniel May
44 * @version 1.0
45 */
46public class CMDgenerateJacaretoReplay implements Command {
47
48    private int nextRef;
49
50    /*
51     * (non-Javadoc)
52     *
53     * @see de.ugoe.cs.util.console.Command#help()
54     */
55    @Override
56    public String help() {
57        return "generateJacaretoReplay <filename> <sequences>";
58    }
59
60    /*
61     * (non-Javadoc)
62     *
63     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
64     */
65    @SuppressWarnings("unchecked")
66    @Override
67    public void run(List<Object> parameters) {
68        String filename;
69        String sequencesName;
70        try {
71            filename = (String) parameters.get(0);
72            sequencesName = (String) parameters.get(1);
73        }
74        catch (Exception e) {
75            throw new IllegalArgumentException();
76        }
77
78        Collection<List<Event>> sequences = null;
79        Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName);
80        if (dataObject == null) {
81            CommandHelpers.objectNotFoundMessage(sequencesName);
82            return;
83        }
84        if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
85            CommandHelpers.objectNotType(sequencesName, "Collection<List<Event<?>>>");
86            return;
87        }
88
89        sequences = (Collection<List<Event>>) dataObject;
90
91        writeJacaretoXML(sequences, filename);
92    }
93
94    private void writeLine(BufferedWriter writer, String line) throws IOException {
95        writer.write(line);
96        writer.newLine();
97    }
98
99    private void writeJacaretoHead(BufferedWriter writer) throws IOException {
100        writeLine(writer, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
101        writeLine(writer, "<JacaretoStructure>");
102        writeLine(writer, "<Record>");
103
104        // TODO: This header content is basically copy+paste from a
105        // specific jacareto replay file right now.
106        // Some things such as screen resolution and especially the
107        // application starter details need to be changed for general cases.
108        writeLine(writer,
109                  "<Calendar procTime=\"0\" duration=\"0\" year=\"2014\" month=\"8\" date=\"11\" hour=\"14\" min=\"43\" sec=\"41\" uuid=\"06831ba1-f28a-4e05-b46e-ce9d8f9ffa0f\" />");
110        writeLine(writer,
111                  "<SystemInfo procTime=\"0\" duration=\"0\" screenWidth=\"2646\" screenHeight=\"1024\" javaVersion=\"1.7.0_65\" lookAndFeel=\"javax.swing.plaf.metal.MetalLookAndFeel\" uuid=\"720f430f-52cf-4d8b-9fbe-58434f766efe\" />");
112        writeLine(writer,
113                  "<KeyboardState procTime=\"0\" duration=\"0\" isNumLockOn=\"false\" isScrollLockOn=\"false\" isCapsLockOn=\"false\" applyIsNumLockOn=\"true\" applyIsScrollLockOn=\"true\" applyIsCapsLockOn=\"true\" uuid=\"28146f79-9fc7-49f9-b4a8-5866a7625683\" />");
114        writeLine(writer, "<ComponentMode numberPopupMenues=\"true\" />");
115        writeLine(writer,
116                  "<ApplicationStarter procTime=\"0\" duration=\"0\" name=\"HelloWorldSwing\" class=\"HelloWorldSwing\" initclass=\"\" basepath=\"/home/daniel/project/autoquest-jfcmonitor\" classpathext=\"${basepath}/helloswing.jar;${basepath}/.;\" detectDuration=\"false\" captureparams=\"\" replayparams=\"\" uuid=\"a7b7d7b9-caa9-4d6d-b052-cf74d353275e\" />");
117    }
118
119    private ArrayList<String> writeJacaretoEvents(BufferedWriter writer,
120                                                  Collection<List<Event>> sequences)
121        throws IOException
122    {
123        ArrayList<String> structure = new ArrayList<String>();
124        structure.add("<StructureElement class=\"jacareto.struct.RootElement\">");
125        // reference the elements that we included in the header
126        structure.add("<Recordable ref=\"0\" />"); // Calendar
127        structure.add("<Recordable ref=\"1\" />"); // SystemInfo
128        structure.add("<Recordable ref=\"2\" />"); // KeyboardState
129        structure.add("<Recordable ref=\"3\" />"); // ComponentMode
130        structure.add("<Recordable ref=\"4\" />"); // ApplicationStarter
131        nextRef = 5;
132
133        for (List<Event> sequence : sequences) {
134            for (Iterator<Event> eventIter = sequence.iterator(); eventIter.hasNext();) {
135                Event event = eventIter.next();
136
137                if (event.getType() instanceof MouseButtonDown) {
138                    structure.add("<StructureElement class=\"jacareto.struct.MouseClick\">");
139                    writeMouseClickEvent(writer, structure, event, 501);
140                }
141                else if (event.getType() instanceof MouseButtonUp) {
142                    writeMouseClickEvent(writer, structure, event, 502);
143                }
144                else if (event.getType() instanceof MouseClick) {
145                    writeMouseClickEvent(writer, structure, event, 500);
146                    structure.add("</StructureElement>");
147                    // FIXME: don't always write an item action
148                    writeItemActionEvent(writer, structure, event);
149                }
150            }
151        }
152
153        return structure;
154    }
155
156    private void writeJacaretoTail(BufferedWriter writer, ArrayList<String> structure)
157        throws IOException
158    {
159        writeLine(writer, "</Record>");
160
161        // write the recording's structure
162        writeLine(writer, "<Structure>");
163        for (String element : structure) {
164            writeLine(writer, element);
165        }
166        // close root element
167        writeLine(writer, "</StructureElement>");
168        writeLine(writer, "</Structure>");
169    }
170
171    private void writeJacaretoXML(Collection<List<Event>> sequences, String filename) {
172        BufferedWriter writer = new BufferedWriter(openReplayFile(filename + ".xml"));
173
174        try {
175            writeJacaretoHead(writer);
176            ArrayList<String> structure = writeJacaretoEvents(writer, sequences);
177            writeJacaretoTail(writer, structure);
178            writeLine(writer, "</JacaretoStructure>");
179
180            writer.flush();
181            writer.close();
182        }
183        catch (IOException e) {
184            Console.printerrln("Unable to write Jacareto replay file " + filename);
185        }
186    }
187
188    /**
189     * <p>
190     * Helper function that opens the replay file for writing.
191     * </p>
192     *
193     * @param filename
194     *            name and path of the replay file
195     * @param encoding
196     *            file encoding, empty string for platform default
197     * @return {@link OutputStreamWriter} that writes to the replay file
198     */
199    private OutputStreamWriter openReplayFile(String filename) {
200        File file = new File(filename);
201        boolean fileCreated;
202        try {
203            fileCreated = file.createNewFile();
204            if (!fileCreated) {
205                Console.traceln(Level.INFO, "Created logfile " + filename);
206            }
207            else {
208                Console.traceln(Level.INFO, "Overwrote existing logfile " + filename);
209            }
210        }
211        catch (IOException e) {
212            Console.printerrln("Unable to create file " + filename);
213            Console.logException(e);
214        }
215        OutputStreamWriter writer = null;
216        try {
217            writer = new OutputStreamWriter(new FileOutputStream(file));
218        }
219        catch (IOException e) {
220            Console.printerrln("Unable to open file for writing (read-only file):" + filename);
221            Console.logException(e);
222        }
223        return writer;
224    }
225
226    private void writeItemActionEvent(BufferedWriter writer,
227                                      ArrayList<String> structure,
228                                      Event event) throws IOException
229    {
230        JFCGUIElement target = (JFCGUIElement) event.getTarget();
231        MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
232
233        //@formatter:off
234        writeLine(writer,
235            "<ItemEvent "
236            + "procTime=\"0\" "
237            + "duration=\"0\" "
238            + "source=\"" + target.getJacaretoHierarchy() + "\" "
239            + "class=\"" + target.getSpecification().getType() + "\" "
240            + "uuid=\"" + UUID.randomUUID() + "\" "
241            + "ID=\"701\" "
242            + "item=\"\" "
243            + "stateChange=\"1\" />"
244        );
245        writeLine(writer,
246            "<ActionEvent "
247            + "procTime=\"0\" "
248            + "duration=\"0\" "
249            + "source=\"" + target.getJacaretoHierarchy() + "\" "
250            + "class=\"" + target.getSpecification().getType() + "\" "
251            + "uuid=\"" + UUID.randomUUID() + "\" "
252            + "ID=\"1001\" "
253            + "command=" + target.getName() + " "
254            + "modifiers=\"" + getButtonModifier(info) + "\" />"
255        );
256        //@formatter:on
257        structure.add("<StructureElement class=\"jacareto.struct.ItemStateChange\">");
258        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
259        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
260        structure.add("</StructureElement>");
261    }
262
263    private void writeMouseClickEvent(BufferedWriter writer,
264                                      ArrayList<String> structure,
265                                      Event event,
266                                      int jacId) throws IOException
267    {
268        MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
269        JFCGUIElement target = (JFCGUIElement) event.getTarget();
270        int clickCount = event.getType() instanceof MouseDoubleClick ? 2 : 1;
271
272        // TODO: change procTime and duration to adequate values
273        //@formatter:off
274        writeLine(writer,
275            "<MouseEvent "
276            + "procTime=\"0\" "
277            + "duration=\"150\" "
278            + "source=\"" + target.getJacaretoHierarchy() + "\" "
279            + "class=\"" + target.getSpecification().getType() + "\" "
280            + "uuid=\"" + UUID.randomUUID() + "\" "
281            + "ID=\"" + jacId + "\" "
282            + "component=\"null\" "
283            + "root=\"" + target.getJacaretoRoot() + "\" "
284            + "xPos=\"0\" "
285            + "yPos=\"0\" "
286            + "width=\"0\" "
287            + "height=\"0\" "
288            + "when=\"" + event.getTimestamp() + "\" "
289            + "isConsumed=\"false\">"
290        );
291        writeLine(writer,
292            "<MouseInfo "
293            + "xPosition=\"" + info.getX()+ "\" "
294            + "yPosition=\"" + info.getY()+ "\" "
295            + "rootX=\"0\" "
296            + "rootY=\"0\" "
297            + "clickCount=\"" + clickCount + "\" "
298            + "modifiers=\"" + getButtonModifier(info) + "\" "
299            + "isPopupTrigger=\"false\" />"
300        );
301        writeLine(writer, "</MouseEvent>");
302        //@formatter:on
303
304        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
305    }
306
307    private int getButtonModifier(MouseButtonInteraction info) {
308        switch (info.getButton())
309        {
310            case LEFT:
311                return 16;
312            case MIDDLE:
313                return 8;
314            case RIGHT:
315                return 4;
316            default:
317                // TODO: handle unknown mouse button
318                return -1;
319        }
320    }
321}
Note: See TracBrowser for help on using the repository browser.