source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/taskequality/GUIEventTaskComparisonRule.java @ 1154

Last change on this file since 1154 was 1154, checked in by pharms, 11 years ago
  • improved java doc
File size: 22.1 KB
RevLine 
[1113]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
[1146]15package de.ugoe.cs.autoquest.tasktrees.taskequality;
[807]16
[1061]17import de.ugoe.cs.autoquest.eventcore.IEventTarget;
[922]18import de.ugoe.cs.autoquest.eventcore.gui.IInteraction;
[1125]19import de.ugoe.cs.autoquest.eventcore.gui.KeyInteraction;
20import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed;
21import de.ugoe.cs.autoquest.eventcore.gui.KeyReleased;
22import de.ugoe.cs.autoquest.eventcore.gui.KeyTyped;
23import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonDown;
24import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction;
25import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonUp;
[1043]26import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
[1056]27import de.ugoe.cs.autoquest.eventcore.gui.MouseDoubleClick;
[1043]28import de.ugoe.cs.autoquest.eventcore.gui.MouseDragAndDrop;
[1125]29import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
[922]30import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
31import de.ugoe.cs.autoquest.eventcore.gui.ValueSelection;
[1061]32import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
33import de.ugoe.cs.autoquest.eventcore.guimodel.ICheckBox;
34import de.ugoe.cs.autoquest.eventcore.guimodel.IComboBox;
35import de.ugoe.cs.autoquest.eventcore.guimodel.IImage;
36import de.ugoe.cs.autoquest.eventcore.guimodel.IListBox;
[1125]37import de.ugoe.cs.autoquest.eventcore.guimodel.IMenu;
[1061]38import de.ugoe.cs.autoquest.eventcore.guimodel.IMenuButton;
39import de.ugoe.cs.autoquest.eventcore.guimodel.IRadioButton;
40import de.ugoe.cs.autoquest.eventcore.guimodel.IShape;
41import de.ugoe.cs.autoquest.eventcore.guimodel.IText;
42import de.ugoe.cs.autoquest.eventcore.guimodel.IToolTip;
[922]43import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
[1146]44import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
[807]45
46/**
47 * <p>
48 * This rule compares GUI event tasks (i.e. it is more concrete, than the
49 * {@link EventTaskComparisonRule}). Two GUI event tasks are only equal if their event type and
50 * target are equal. The returned equality is even more fine-grained for events whose type is
51 * {@link TextInput} and {@link ValueSelection}. For text inputs, lexical equality is returned if
52 * the same text is entered using the same key interactions. Syntactical equality is returned if
53 * the same text is entered using different key interactions. Semantical equality is returned if
54 * different text is entered, but into the same event target. Value selections are syntactically
55 * equal, if the same value is selected. Otherwise they are semantically equal.
56 * </p>
57 *
58 * @author Patrick Harms
59 */
[1146]60public class GUIEventTaskComparisonRule implements TaskComparisonRule {
[807]61   
[1125]62    /* (non-Javadoc)
[1146]63     * @see NodeComparisonRule#isApplicable(ITask, ITask)
[807]64     */
65    @Override
[1146]66    public boolean isApplicable(ITask task1, ITask task2) {
[1125]67        return
[1146]68            ((task1 instanceof IEventTask) && (task2 instanceof IEventTask) &&
69            (((IEventTask) task1).getEventType() instanceof IInteraction) &&
70            (((IEventTask) task2).getEventType() instanceof IInteraction));
[1125]71    }
72
73    /* (non-Javadoc)
[1146]74     * @see NodeComparisonRule#areLexicallyEqual(ITask, ITask)
[1125]75     */
76    @Override
[1146]77    public boolean areLexicallyEqual(ITask task1, ITask task2) {
78        TaskEquality equality = getEquality(task1, task2, TaskEquality.LEXICALLY_EQUAL);
79        return (equality != null) && (equality.isAtLeast(TaskEquality.LEXICALLY_EQUAL));
[1125]80    }
81
82    /* (non-Javadoc)
[1146]83     * @see NodeComparisonRule#areSyntacticallyEqual(ITask, ITask)
[1125]84     */
85    @Override
[1146]86    public boolean areSyntacticallyEqual(ITask task1, ITask task2) {
87        TaskEquality equality = getEquality(task1, task2, TaskEquality.SYNTACTICALLY_EQUAL);
88        return (equality != null) && (equality.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL));
[1125]89    }
90
91    /* (non-Javadoc)
[1146]92     * @see NodeComparisonRule#areSemanticallyEqual(ITask, ITask)
[1125]93     */
94    @Override
[1146]95    public boolean areSemanticallyEqual(ITask task1, ITask task2) {
96        TaskEquality equality = getEquality(task1, task2, TaskEquality.SEMANTICALLY_EQUAL);
97        return (equality != null) && (equality.isAtLeast(TaskEquality.SEMANTICALLY_EQUAL));
[1125]98    }
99
100    /* (non-Javadoc)
[1146]101     * @see NodeComparisonRule#compare(ITask, ITask)
[1125]102     */
103    @Override
[1146]104    public TaskEquality compare(ITask task1, ITask task2) {
105        return getEquality(task1, task2, null);
[1125]106    }
107
108    /**
109     *
110     */
[1146]111    private TaskEquality getEquality(ITask task1, ITask task2, TaskEquality requiredEqualityLevel) {
112        IEventTask eventTask1 = (IEventTask) task1;
113        IEventTask eventTask2 = (IEventTask) task2;
[807]114       
[1146]115        if (!eventTask1.getEventTarget().equals(eventTask2.getEventTarget())) {
116            return TaskEquality.UNEQUAL;
[807]117        }
118       
[1146]119        IInteraction interaction1 = (IInteraction) eventTask1.getEventType();
120        IInteraction interaction2 = (IInteraction) eventTask2.getEventType();
[807]121       
[1125]122        return compareInteractions
[1146]123            (interaction1, interaction2, eventTask1.getEventTarget(), requiredEqualityLevel);
[807]124    }
125
126    /**
127     * <p>
[1061]128     * compares two interactions. The method delegates to other, more specific compare method, e.g.,
[807]129     * {@link #compareTextInputs(TextInput, TextInput)} and
[1061]130     * {@link #compareValueSelections(ValueSelection, ValueSelection)}, if any exist for the
131     * concrete interaction types. Otherwise it uses the equals method of the interactions for
132     * comparison. In this case, if the interactions equals method returns true, this method
133     * returns lexical equality.
[807]134     * </p>
[1154]135     * <p>
136     * The provided equality level can be used to restrict the quality check to the given level.
137     * This is done for optimization purposes. The returned equality level can be at most as
138     * concrete as the provided one. If the provided one is null, it is expected to be lexical
139     * equality.
140     * </p>
[807]141     *
[1154]142     * @param interaction1  the first interaction to compare
143     * @param interaction2  the second interaction to compare
144     * @param eventTarget   the event target on which the interactions happened (used within
145     *                      special comparisons like mouse clicks on buttons, where the coordinates
146     *                      can be ignored)
147     * @param equalityLevel the equality level to be checked for
[807]148     *
149     * @return as described
150     */
[1146]151    private TaskEquality compareInteractions(IInteraction interaction1,
[1061]152                                             IInteraction interaction2,
[1125]153                                             IEventTarget eventTarget,
[1146]154                                             TaskEquality equalityLevel)
[1061]155    {
[1146]156        TaskEquality level = equalityLevel;
[1125]157       
158        if (level == null) {
[1146]159            level = TaskEquality.LEXICALLY_EQUAL;
[1125]160        }
161       
[807]162        if (interaction1 == interaction2) {
[1146]163            return TaskEquality.LEXICALLY_EQUAL;
[807]164        }
[1125]165        else if ((interaction1 instanceof KeyInteraction) &&
166                 (interaction2 instanceof KeyInteraction))
167        {
168            return compareKeyInteractions
169                ((KeyInteraction) interaction1, (KeyInteraction) interaction2, level);
170        }
171        else if ((interaction1 instanceof MouseButtonInteraction) &&
172                 (interaction2 instanceof MouseButtonInteraction))
173        {
174            return compareMouseButtonInteractions
175                ((MouseButtonInteraction) interaction1, (MouseButtonInteraction) interaction2,
176                 eventTarget, level);
177        }
178        else if ((interaction1 instanceof Scroll) && (interaction2 instanceof Scroll)) {
179            return compareScrolls((Scroll) interaction1, (Scroll) interaction2, level);
180        }
[807]181        else if ((interaction1 instanceof TextInput) && (interaction2 instanceof TextInput)) {
[1125]182            return compareTextInputs
183                ((TextInput) interaction1, (TextInput) interaction2, level);
[807]184        }
185        else if ((interaction1 instanceof ValueSelection) &&
186                 (interaction2 instanceof ValueSelection))
187        {
188            return compareValueSelections
[1125]189                ((ValueSelection<?>) interaction1, (ValueSelection<?>) interaction2, level);
[807]190        }
191        else if (interaction1.equals(interaction2)) {
[1146]192            return TaskEquality.LEXICALLY_EQUAL;
[807]193        }
194        else {
[1146]195            return TaskEquality.UNEQUAL;
[807]196        }
197    }
198
199    /**
200     * <p>
[1154]201     * compares two key interactions. If both are of the same type and if both have the
202     * same key, they are lexically equal. If both are only of the same type, they are
203     * semantically equal. Otherwise, they are unequal.
[807]204     * </p>
[1154]205     * <p>
206     * The provided equality level can be used to restrict the quality check to the given level.
207     * This is done for optimization purposes. The returned equality level is as concrete as
208     * the provided one. It may be more concrete if there is no difference regarding the
209     * comparison on the levels.
210     * </p>
[807]211     *
[1154]212     * @param interaction1  the first key interaction
213     * @param interaction2  the second key interaction
214     * @param equalityLevel the equality level to be checked for
215     *
216     * @return as described
[807]217     */
[1146]218    private TaskEquality compareKeyInteractions(KeyInteraction interaction1,
[1125]219                                                KeyInteraction interaction2,
[1146]220                                                TaskEquality   equalityLevel)
[1125]221    {
222        if (((interaction1 instanceof KeyPressed) && (interaction2 instanceof KeyPressed)) ||
223            ((interaction1 instanceof KeyReleased) && (interaction2 instanceof KeyReleased)) ||
224            ((interaction1 instanceof KeyTyped) && (interaction2 instanceof KeyTyped)))
225        {
[1146]226            if ((equalityLevel.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL)) &&
[1125]227                (interaction1.getKey() == interaction2.getKey()))
228            {
[1146]229                return TaskEquality.LEXICALLY_EQUAL;
[807]230            }
231            else {
[1146]232                return TaskEquality.SEMANTICALLY_EQUAL;
[807]233            }
234        }
[1125]235       
[1146]236        return TaskEquality.UNEQUAL;
[807]237    }
[1125]238   
[807]239    /**
240     * <p>
[1125]241     * compares two mouse drag and drops. If both drag and drops have the same start and end
242     * coordinates, they are lexically equal. Otherwise, they are semantically equal.
[807]243     * </p>
[1154]244     * <p>
245     * The provided equality level can be used to restrict the quality check to the given level.
246     * This is done for optimization purposes. The returned equality level is as concrete as
247     * the provided one. It may be more concrete if there is no difference regarding the
248     * comparison on the levels.
249     * </p>
[807]250     *
[1154]251     * @param interaction1  the first mouse drag and drop to compare
252     * @param interaction2  the second mouse drag and drop to compare
253     * @param equalityLevel the equality level to be checked for
[807]254     *
255     * @return as described
256     */
[1146]257    private TaskEquality compareMouseDragAndDrops(MouseDragAndDrop interaction1,
[1125]258                                                  MouseDragAndDrop interaction2,
[1146]259                                                  TaskEquality     equalityLevel)
[807]260    {
[1125]261        if (interaction1.getButton() != interaction2.getButton()) {
[1146]262            return TaskEquality.UNEQUAL;
[1125]263        }
[807]264       
[1146]265        if (equalityLevel.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL)) {
[1125]266            int x1 = interaction1.getX();
267            int x1Start = interaction1.getXStart();
268            int x2 = interaction2.getX();
269            int x2Start = interaction2.getXStart();
270            int y1 = interaction1.getY();
271            int y1Start = interaction1.getYStart();
272            int y2 = interaction2.getY();
273            int y2Start = interaction2.getYStart();
274       
275            if ((x1Start == x2Start) && (x1 == x2) && (y1Start == y2Start) && (y1 == y2)) {
[1146]276                return TaskEquality.LEXICALLY_EQUAL;
[1125]277            }
[807]278        }
[1125]279       
[1146]280        return TaskEquality.SEMANTICALLY_EQUAL;
[807]281    }
282
[1043]283    /**
284     * <p>
[1125]285     * compares two mouse button interactions such as clicks, mouse button down, or double clicks.
286     * If both interactions have the same coordinates, they are lexically equal. Otherwise, they
287     * are semantically equal. Mouse clicks for which the coordinates make no lexical difference
288     * (see {@link #clickCoordinatesMakeLexicalDifference(IEventTarget)}) are treated as
289     * lexically equal.
[1043]290     * </p>
[1154]291     * <p>
292     * The provided equality level can be used to restrict the quality check to the given level.
293     * This is done for optimization purposes. The returned equality level is as concrete as
294     * the provided one. It may be more concrete if there is no difference regarding the
295     * comparison on the levels.
296     * </p>
[1043]297     *
[1154]298     * @param interaction1  the first mouse button interaction to compare
299     * @param interaction2  the second mouse button interaction to compare
300     * @param eventTarget   the event target on which the interactions happened (used within
301     *                      special comparisons like mouse clicks on buttons, where the coordinates
302     *                      can be ignored)
303     * @param equalityLevel the equality level to be checked for
[1043]304     *
305     * @return as described
306     */
[1146]307    private TaskEquality compareMouseButtonInteractions(MouseButtonInteraction interaction1,
[1125]308                                                        MouseButtonInteraction interaction2,
309                                                        IEventTarget           eventTarget,
[1146]310                                                        TaskEquality           equalityLevel)
[1043]311    {
[1125]312        boolean coordinatesMatch = true;
313       
314        if ((interaction1 instanceof MouseDragAndDrop) &&
315            (interaction2 instanceof MouseDragAndDrop))
316        {
317            return compareMouseDragAndDrops
318                ((MouseDragAndDrop) interaction1, (MouseDragAndDrop) interaction2, equalityLevel);
319        }
320        else if (interaction1.getButton() != interaction2.getButton()) {
[1146]321            return TaskEquality.UNEQUAL;
[1057]322        }
[1146]323        else if (equalityLevel.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL) &&
[1125]324                 clickCoordinatesMakeLexicalDifference(eventTarget))
325        {
326            int x1 = interaction1.getX();
327            int x2 = interaction2.getX();
328            int y1 = interaction1.getY();
329            int y2 = interaction2.getY();
330
331            if ((x1 != x2) || (y1 != y2)) {
332                coordinatesMatch = false;
333            }
334        }
[1057]335       
[1125]336        // up to now, they can be equal. Now check the types. Do it as last action as these
337        // checks take the most time and should, therefore, only be done latest
338        if (((interaction1 instanceof MouseClick) && (interaction2 instanceof MouseClick)) ||
339            ((interaction1 instanceof MouseDoubleClick) &&
340             (interaction2 instanceof MouseDoubleClick)) ||
341            ((interaction1 instanceof MouseButtonDown) &&
342             (interaction2 instanceof MouseButtonDown)) ||
343            ((interaction1 instanceof MouseButtonUp) &&
344             (interaction2 instanceof MouseButtonUp)))
345        {
346            if (coordinatesMatch) {
[1146]347                return TaskEquality.LEXICALLY_EQUAL;
[1125]348            }
349            else {
[1146]350                return TaskEquality.SEMANTICALLY_EQUAL;
[1125]351            }
[1061]352        }
353       
[1146]354        return TaskEquality.UNEQUAL;
[1043]355    }
356
357    /**
358     * <p>
[1125]359     * compares two mouse button interactions such as clicks, mouse button down, or double clicks.
360     * If both interactions have the same coordinates, they are lexically equal. Otherwise, they
361     * are semantically equal. Mouse clicks for which the coordinates make no lexical difference
362     * (see {@link #clickCoordinatesMakeLexicalDifference(IEventTarget)}) are treated as
363     * lexically equal.
[1056]364     * </p>
[1154]365     * <p>
366     * The provided equality level can be used to restrict the quality check to the given level.
367     * This is done for optimization purposes. The returned equality level is as concrete as
368     * the provided one. It may be more concrete if there is no difference regarding the
369     * comparison on the levels.
370     * </p>
[1056]371     *
[1154]372     * @param interaction1  the first mouse button interaction to compare
373     * @param interaction2  the second mouse button interaction to compare
374     * @param eventTarget   the event target on which the interactions happened (used within
375     *                      special comparisons like mouse clicks on buttons, where the coordinates
376     *                      can be ignored)
377     * @param equalityLevel the equality level to be checked for
[1056]378     *
379     * @return as described
380     */
[1146]381    private TaskEquality compareScrolls(Scroll       interaction1,
[1125]382                                        Scroll       interaction2,
[1146]383                                        TaskEquality equalityLevel)
[1056]384    {
[1146]385        if (equalityLevel.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL)) {
[1125]386            int x1 = interaction1.getXPosition();
387            int x2 = interaction2.getXPosition();
388            int y1 = interaction1.getYPosition();
389            int y2 = interaction2.getYPosition();
[1057]390       
[1125]391            if ((x1 == x2) && (y1 == y2)) {
[1146]392                return TaskEquality.LEXICALLY_EQUAL;
[1125]393            }
[1061]394        }
395       
[1146]396        return TaskEquality.SEMANTICALLY_EQUAL;
[1125]397    }
398
399    /**
400     * <p>
401     * compares two text inputs. If both text inputs have the same entered text and text input
402     * events, they are lexically equal. If they only have the same entered text, they are
403     * syntactically equal. If they are only both text inputs, they are semantically equal.
404     * (the equality of the event targets is checked beforehand).
405     * </p>
[1154]406     * <p>
407     * The provided equality level can be used to restrict the quality check to the given level.
408     * This is done for optimization purposes. The returned equality level is as concrete as
409     * the provided one. It may be more concrete if there is no difference regarding the
410     * comparison on the levels.
411     * </p>
[1125]412     *
[1154]413     * @param interaction1  the first text input to compare
414     * @param interaction2  the second text input to compare
415     * @param equalityLevel the equality level to be checked for
[1125]416     *
417     * @return as described
418     */
[1146]419    private TaskEquality compareTextInputs(TextInput    interaction1,
[1125]420                                           TextInput    interaction2,
[1146]421                                           TaskEquality equalityLevel)
[1125]422    {
423        switch (equalityLevel) {
424            case LEXICALLY_EQUAL:
425                if (interaction1.getTextInputEvents().equals(interaction2.getTextInputEvents())) {
[1146]426                    return TaskEquality.LEXICALLY_EQUAL;
[1125]427                }
428                // fall through
429            case SYNTACTICALLY_EQUAL:
430                if (interaction1.getEnteredText().equals(interaction2.getEnteredText())) {
[1146]431                    return TaskEquality.SYNTACTICALLY_EQUAL;
[1125]432                }
433                // fall through
434            case SEMANTICALLY_EQUAL:
[1146]435                return TaskEquality.SEMANTICALLY_EQUAL;
[1125]436            default:
[1146]437                return TaskEquality.UNEQUAL;
[1056]438        }
439    }
440
441    /**
442     * <p>
[1125]443     * compares two value selections. If both value selections have the same selected value, they
444     * are syntactically equal, otherwise they are semantically equal.
445     * (the equality of the event targets is checked beforehand).
[1043]446     * </p>
[1154]447     * <p>
448     * The provided equality level can be used to restrict the quality check to the given level.
449     * This is done for optimization purposes. The returned equality level is as concrete as
450     * the provided one. It may be more concrete if there is no difference regarding the
451     * comparison on the levels.
452     * </p>
[1043]453     *
[1154]454     * @param interaction1  the first value selection to compare
455     * @param interaction2  the second value selection to compare
456     * @param equalityLevel the equality level to be checked for
[1043]457     *
458     * @return as described
459     */
[1146]460    private TaskEquality compareValueSelections(ValueSelection<?> interaction1,
[1125]461                                                ValueSelection<?> interaction2,
[1146]462                                                TaskEquality      equalityLevel)
[1043]463    {
[1146]464        if (equalityLevel.isAtLeast(TaskEquality.SYNTACTICALLY_EQUAL)) {
[1125]465            Object value1 = interaction1.getSelectedValue();
466            Object value2 = interaction2.getSelectedValue();
467       
468            if ((value1 == value2) || ((value1 != null) && (value1.equals(value2)))) {
[1146]469                return TaskEquality.LEXICALLY_EQUAL;
[1125]470            }
[1057]471        }
472       
[1146]473        return TaskEquality.SEMANTICALLY_EQUAL;
[1043]474    }
475
[1061]476    /**
477     * <p>
478     * Checks, if the coordinates of a click or double click on the provided event target makes
479     * a lexical difference. Mouse clicks and double clicks on buttons, check boxes,
480     * combo boxes, images, list boxes, menu buttons, radio buttons, shapes, uneditable text,
481     * and tool tips have no lexical difference as long as they happen on the same event target.
482     * The concrete coordinates are not relevant.
483     * </p>
484     *
485     * @param eventTarget the event target on which the interaction occurred
486     *
487     * @return if the coordinates are important to be considered for clicks and double clicks,
488     *         false else
489     */
490    private boolean clickCoordinatesMakeLexicalDifference(IEventTarget eventTarget) {
491        if ((eventTarget instanceof IButton) ||
492            (eventTarget instanceof ICheckBox) ||
493            (eventTarget instanceof IComboBox) ||
494            (eventTarget instanceof IImage) ||
495            (eventTarget instanceof IListBox) ||
[1125]496            (eventTarget instanceof IMenu) ||
[1061]497            (eventTarget instanceof IMenuButton) ||
498            (eventTarget instanceof IRadioButton) ||
499            (eventTarget instanceof IShape) ||
500            (eventTarget instanceof IText) ||
501            (eventTarget instanceof IToolTip))
502        {
503            return false;
504        }
505        else {
506            return true;
507        }
508    }
509
[807]510}
Note: See TracBrowser for help on using the repository browser.