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

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

begin implementing focus events

  • Property svn:mime-type set to text/plain
File size: 14.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    private JFCGUIElement currentFocus;
50
51    /*
52     * (non-Javadoc)
53     *
54     * @see de.ugoe.cs.util.console.Command#help()
55     */
56    @Override
57    public String help() {
58        return "generateJacaretoReplay <filename> <sequences>";
59    }
60
61    /*
62     * (non-Javadoc)
63     *
64     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
65     */
66    @SuppressWarnings("unchecked")
67    @Override
68    public void run(List<Object> parameters) {
69        String filename;
70        String sequencesName;
71        try {
72            filename = (String) parameters.get(0);
73            sequencesName = (String) parameters.get(1);
74        }
75        catch (Exception e) {
76            throw new IllegalArgumentException();
77        }
78
79        Collection<List<Event>> sequences = null;
80        Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName);
81        if (dataObject == null) {
82            CommandHelpers.objectNotFoundMessage(sequencesName);
83            return;
84        }
85        if (!SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
86            CommandHelpers.objectNotType(sequencesName, "Collection<List<Event<?>>>");
87            return;
88        }
89
90        sequences = (Collection<List<Event>>) dataObject;
91
92        writeJacaretoXML(sequences, filename);
93    }
94
95    private void writeLine(BufferedWriter writer, String line) throws IOException {
96        writer.write(line);
97        writer.newLine();
98    }
99
100    private void writeJacaretoHead(BufferedWriter writer) throws IOException {
101        writeLine(writer, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
102        writeLine(writer, "<JacaretoStructure>");
103        writeLine(writer, "<Record>");
104
105        // TODO: This header content is basically copy+paste from a
106        // specific jacareto replay file right now.
107        // Some things such as screen resolution and especially the
108        // application starter details need to be changed for general cases.
109        writeLine(writer,
110                  "<Calendar procTime=\"0\" duration=\"0\" year=\"2014\" month=\"8\" date=\"11\" hour=\"14\" min=\"43\" sec=\"41\" uuid=\"06831ba1-f28a-4e05-b46e-ce9d8f9ffa0f\" />");
111        writeLine(writer,
112                  "<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\" />");
113        writeLine(writer,
114                  "<KeyboardState procTime=\"0\" duration=\"0\" isNumLockOn=\"false\" isScrollLockOn=\"false\" isCapsLockOn=\"false\" applyIsNumLockOn=\"true\" applyIsScrollLockOn=\"true\" applyIsCapsLockOn=\"true\" uuid=\"28146f79-9fc7-49f9-b4a8-5866a7625683\" />");
115        writeLine(writer, "<ComponentMode numberPopupMenues=\"true\" />");
116        writeLine(writer,
117                  "<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\" />");
118    }
119
120    private ArrayList<String> writeJacaretoEvents(BufferedWriter writer,
121                                                  Collection<List<Event>> sequences)
122        throws IOException
123    {
124        ArrayList<String> structure = new ArrayList<String>();
125        structure.add("<StructureElement class=\"jacareto.struct.RootElement\">");
126        // reference the elements that we included in the header
127        structure.add("<Recordable ref=\"0\" />"); // Calendar
128        structure.add("<Recordable ref=\"1\" />"); // SystemInfo
129        structure.add("<Recordable ref=\"2\" />"); // KeyboardState
130        structure.add("<Recordable ref=\"3\" />"); // ComponentMode
131        structure.add("<Recordable ref=\"4\" />"); // ApplicationStarter
132        nextRef = 5;
133
134        for (List<Event> sequence : sequences) {
135            for (Iterator<Event> eventIter = sequence.iterator(); eventIter.hasNext();) {
136                Event event = eventIter.next();
137
138                if (event.getType() instanceof MouseButtonDown) {
139                    structure.add("<StructureElement class=\"jacareto.struct.MouseClick\">");
140                    writeMouseClickEvent(writer, structure, event, 501);
141                }
142                else if (event.getType() instanceof MouseButtonUp) {
143                    writeMouseClickEvent(writer, structure, event, 502);
144                }
145                else if (event.getType() instanceof MouseClick) {
146                    writeMouseClickEvent(writer, structure, event, 500);
147                    structure.add("</StructureElement>");
148                    // FIXME: don't always write an item action
149                    writeItemActionEvent(writer, structure, event);
150                }
151                /*
152                else if (event.getType() instanceof KeyboardFocusChange) {
153                    writeFocusChangeEvent(writer, structure, event);
154                }
155                */
156            }
157        }
158
159        return structure;
160    }
161
162    private void writeJacaretoTail(BufferedWriter writer, ArrayList<String> structure)
163        throws IOException
164    {
165        writeLine(writer, "</Record>");
166
167        // write the recording's structure
168        writeLine(writer, "<Structure>");
169        for (String element : structure) {
170            writeLine(writer, element);
171        }
172        // close root element
173        writeLine(writer, "</StructureElement>");
174        writeLine(writer, "</Structure>");
175    }
176
177    private void writeJacaretoXML(Collection<List<Event>> sequences, String filename) {
178        BufferedWriter writer = new BufferedWriter(openReplayFile(filename + ".xml"));
179
180        try {
181            writeJacaretoHead(writer);
182            ArrayList<String> structure = writeJacaretoEvents(writer, sequences);
183            writeJacaretoTail(writer, structure);
184            writeLine(writer, "</JacaretoStructure>");
185
186            writer.flush();
187            writer.close();
188        }
189        catch (IOException e) {
190            Console.printerrln("Unable to write Jacareto replay file " + filename);
191        }
192    }
193
194    /**
195     * <p>
196     * Helper function that opens the replay file for writing.
197     * </p>
198     *
199     * @param filename
200     *            name and path of the replay file
201     * @param encoding
202     *            file encoding, empty string for platform default
203     * @return {@link OutputStreamWriter} that writes to the replay file
204     */
205    private OutputStreamWriter openReplayFile(String filename) {
206        File file = new File(filename);
207        boolean fileCreated;
208        try {
209            fileCreated = file.createNewFile();
210            if (!fileCreated) {
211                Console.traceln(Level.INFO, "Created logfile " + filename);
212            }
213            else {
214                Console.traceln(Level.INFO, "Overwrote existing logfile " + filename);
215            }
216        }
217        catch (IOException e) {
218            Console.printerrln("Unable to create file " + filename);
219            Console.logException(e);
220        }
221        OutputStreamWriter writer = null;
222        try {
223            writer = new OutputStreamWriter(new FileOutputStream(file));
224        }
225        catch (IOException e) {
226            Console.printerrln("Unable to open file for writing (read-only file):" + filename);
227            Console.logException(e);
228        }
229        return writer;
230    }
231
232    private void writeItemActionEvent(BufferedWriter writer,
233                                      ArrayList<String> structure,
234                                      Event event) throws IOException
235    {
236        JFCGUIElement target = (JFCGUIElement) event.getTarget();
237        MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
238
239        //@formatter:off
240        writeLine(writer,
241            "<ItemEvent "
242            + "procTime=\"0\" "
243            + "duration=\"0\" "
244            + "source=\"" + target.getJacaretoHierarchy() + "\" "
245            + "class=\"" + target.getSpecification().getType() + "\" "
246            + "uuid=\"" + UUID.randomUUID() + "\" "
247            + "ID=\"701\" "
248            + "item=\"\" "
249            + "stateChange=\"1\" />"
250        );
251        writeLine(writer,
252            "<ActionEvent "
253            + "procTime=\"0\" "
254            + "duration=\"0\" "
255            + "source=\"" + target.getJacaretoHierarchy() + "\" "
256            + "class=\"" + target.getSpecification().getType() + "\" "
257            + "uuid=\"" + UUID.randomUUID() + "\" "
258            + "ID=\"1001\" "
259            + "command=" + target.getName() + " "
260            + "modifiers=\"" + getButtonModifier(info) + "\" />"
261        );
262        //@formatter:on
263        structure.add("<StructureElement class=\"jacareto.struct.ItemStateChange\">");
264        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
265        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
266        structure.add("</StructureElement>");
267    }
268
269    private void writeFocusChangeEvent(BufferedWriter writer,
270                                       ArrayList<String> structure,
271                                       Event event) throws IOException
272    {
273        KeyboardFocusChange info = (KeyboardFocusChange) event.getType();
274        JFCGUIElement target = (JFCGUIElement) event.getTarget();
275
276        if (currentFocus != null) {
277            // focus lost on old target
278            writeFocusEvent(writer, structure, info, currentFocus, 1005);
279            // focus gained on new target
280            writeFocusEvent(writer, structure, info, target, 1004);
281        }
282        else {
283            // TODO: it seems like Jacareto wants a window activation before
284            // the first focus event but that is not the case in autoquest,
285            // skip for now
286        }
287
288        currentFocus = target;
289    }
290
291    private void writeFocusEvent(BufferedWriter writer,
292                                 ArrayList<String> structure,
293                                 KeyboardFocusChange info,
294                                 JFCGUIElement target,
295                                 int jacId) throws IOException
296    {
297        //@formatter:off
298        writeLine(writer,
299            "<FocusEvent "
300            + "procTime=\"0\" "
301            + "duration=\"0\" "
302            + "source=\"" + target.getJacaretoHierarchy() + "\" "
303            + "class=\"" + target.getSpecification().getType() + "\" "
304            + "uuid=\"" + UUID.randomUUID() + "\" "
305            + "ID=\"" + jacId + "\" "
306            + "component=\"null\" "
307            + "root=\"" + target.getJacaretoRoot() + "\" "
308            + "xPos=\"0\" "
309            + "yPos=\"0\" "
310            + "width=\"0\" "
311            + "height=\"0\" "
312            + "isTemporary=\"false\" />"
313        );
314        //@formatter:on
315    }
316
317    private void writeMouseClickEvent(BufferedWriter writer,
318                                      ArrayList<String> structure,
319                                      Event event,
320                                      int jacId) throws IOException
321    {
322        MouseButtonInteraction info = (MouseButtonInteraction) event.getType();
323        JFCGUIElement target = (JFCGUIElement) event.getTarget();
324        int clickCount = event.getType() instanceof MouseDoubleClick ? 2 : 1;
325
326        // TODO: change procTime and duration to adequate values
327        //@formatter:off
328        writeLine(writer,
329            "<MouseEvent "
330            + "procTime=\"0\" "
331            + "duration=\"150\" "
332            + "source=\"" + target.getJacaretoHierarchy() + "\" "
333            + "class=\"" + target.getSpecification().getType() + "\" "
334            + "uuid=\"" + UUID.randomUUID() + "\" "
335            + "ID=\"" + jacId + "\" "
336            + "component=\"null\" "
337            + "root=\"" + target.getJacaretoRoot() + "\" "
338            + "xPos=\"0\" "
339            + "yPos=\"0\" "
340            + "width=\"0\" "
341            + "height=\"0\" "
342            + "when=\"" + event.getTimestamp() + "\" "
343            + "isConsumed=\"false\">"
344        );
345        writeLine(writer,
346            "<MouseInfo "
347            + "xPosition=\"" + info.getX() + "\" "
348            + "yPosition=\"" + info.getY() + "\" "
349            + "rootX=\"0\" "
350            + "rootY=\"0\" "
351            + "clickCount=\"" + clickCount + "\" "
352            + "modifiers=\"" + getButtonModifier(info) + "\" "
353            + "isPopupTrigger=\"false\" />"
354        );
355        writeLine(writer, "</MouseEvent>");
356        //@formatter:on
357
358        structure.add("<Recordable ref=\"" + (nextRef++) + "\" />");
359    }
360
361    private int getButtonModifier(MouseButtonInteraction info) {
362        switch (info.getButton())
363        {
364            case LEFT:
365                return 16;
366            case MIDDLE:
367                return 8;
368            case RIGHT:
369                return 4;
370            default:
371                // TODO: handle unknown mouse button
372                return -1;
373        }
374    }
375}
Note: See TracBrowser for help on using the repository browser.