source: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/jfc/data/JFCTargetComparator.java @ 404

Last change on this file since 404 was 404, checked in by sherbold, 12 years ago
  • code clean-up
  • Property svn:mime-type set to text/plain
File size: 10.1 KB
Line 
1package de.ugoe.cs.eventbench.jfc.data;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.HashSet;
6import java.util.LinkedHashSet;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10
11import org.apache.commons.collections15.CollectionUtils;
12
13/**
14 * <p>
15 * This class implements a comparator for target string for JFC GUIs. It
16 * internally maintains a collection of all targets that have been compared, to
17 * ensure transitivity of the equals relation. This memory can always be deleted
18 * by calling {@link #reset()}.
19 * </p>
20 *
21 * @author Steffen Herbold
22 * @version 1.0
23 */
24public class JFCTargetComparator {
25       
26        private static boolean mutable = true;
27       
28        private static Set<String> knownTargets = new LinkedHashSet<String>();
29       
30        private static Map<String, Set<String>> equalTargets;
31       
32        public static void setMutable(boolean mutable) {
33                if( JFCTargetComparator.mutable==true && mutable == false ) {
34                        equalTargets = new HashMap<String, Set<String>>();
35                        for( String target1 : knownTargets ) {
36                                Set<String> curEqualTargets = new HashSet<String>();
37                                for( String target2 : knownTargets ) {
38                                        if( compare(target1, target2) ) {
39                                                curEqualTargets.add(target2);
40                                        }
41                                }
42                                equalTargets.put(target1, curEqualTargets);
43                        }
44                }
45                JFCTargetComparator.mutable = mutable;
46        }
47
48        /**
49         * <p>
50         * Compares to target strings. The strings are equal, if
51         * <ul>
52         * <li>the class, index, and text of all widgets are equal</li>
53         * <li>either the title or the hashCode of all widgets are equal</li>
54         * <li>either the title or the hashCode has been observed in one equal
55         * instance of a widget, for all widgets.</li>
56         * </ul>
57         * </p>
58         * <p>
59         * All target strings are remembered internally, to be able to test for the
60         * third property.
61         * </p>
62         *
63         * @param target1
64         *            first target string
65         * @param target2
66         *            second target string
67         * @return true, if both targets are equal; false otherwise
68         */
69        public static boolean compare(String target1, String target2) {
70                boolean result = false;
71                if( mutable ) {
72                        instance.addTarget(target1);
73                        instance.addTarget(target2);
74                        knownTargets.add(target1);
75                        knownTargets.add(target2);
76                        JFCWidget widget1 = instance.find(target1);
77                        JFCWidget widget2 = instance.find(target2);
78                        result = (widget1==widget2);
79                }
80               
81               
82                if( !mutable ) {
83                        Set<String> curEquals = equalTargets.get(target1);
84                        if( curEquals!=null ) {
85                                result = curEquals.contains(target2);
86                        }                       
87                }
88               
89                return result;
90        }
91
92        /**
93         * <p>
94         * Resets the internal memory of targets.
95         * </p>
96         */
97        public static void reset() {
98                instance = new JFCTargetComparator();
99        }
100
101        /**
102         * <p>
103         * Internal handle to the instance of this class (implemented as
104         * Singleton!).
105         * </p>
106         */
107        private static JFCTargetComparator instance = new JFCTargetComparator();
108
109        /**
110         * <p>
111         * Private Constructor. Creates a new instance of the class and prevents
112         * instantiation from outside of this class.
113         * </p>
114         */
115        private JFCTargetComparator() {
116        }
117
118        /**
119         * <p>
120         * List of the root widgets found in the target string.
121         * </p>
122         */
123        private List<JFCWidget> rootWidgets = new ArrayList<JFCTargetComparator.JFCWidget>();
124
125        /**
126         * <p>
127         * Adds a target to the memory.
128         * </p>
129         *
130         * @param target
131         *            target to be added
132         */
133        private void addTarget(String target) {
134                if (target != null) {
135                        String[] targetParts = target.split("\\]\\.\\[");
136                        if (targetParts.length == 1) {
137                                addWidget(target.substring(1, target.length() - 1), null);
138                        } else {
139                                JFCWidget parent = null;
140                                for (int i = 0; i < targetParts.length; i++) {
141                                        if (i == 0) {
142                                                parent = addWidget(targetParts[i].substring(1), parent);
143                                        } else if (i == targetParts.length - 1) {
144                                                parent = addWidget(
145                                                                targetParts[i].substring(0,
146                                                                                targetParts[i].length() - 1), parent);
147                                        } else {
148                                                parent = addWidget(targetParts[i], parent);
149                                        }
150                                }
151                        }
152                }
153        }
154
155        /**
156         * <p>
157         * Adds a widget extracted from a target to the memory. The widget is placed
158         * as a child/parent of other widget according to the GUI hierarchy of the
159         * application.
160         * </p>
161         * <p>
162         * In case the widget already exists, the existing widget is returned and
163         * the known targets and hashCodes of the existing widget are updated.
164         * </p>
165         *
166         * @param widgetString
167         *            string identifying the widget
168         * @param parent
169         *            parent widget; if null, it is a root widget and added to
170         *            {@link #rootWidgets}
171         * @return the created widget.
172         */
173        private JFCWidget addWidget(String widgetString, JFCWidget parent) {
174                String[] widgetInfo = widgetString.split("','");
175                JFCWidget widget = generateWidget(widgetString);
176
177                if (parent == null) {
178                        int index = rootWidgets.indexOf(widget);
179                        if (index >= 0) {
180                                widget = rootWidgets.get(index);
181                                widget.titles.add(widgetInfo[0]);
182                                widget.hashCodes.add(widgetInfo[4]);
183                        } else {
184                                rootWidgets.add(widget);
185                        }
186                } else {
187                        int index = parent.children.indexOf(widget);
188                        if (index >= 0) {
189                                widget = parent.children.get(index);
190                                widget.titles.add(widgetInfo[0]);
191                                widget.hashCodes.add(widgetInfo[4]);
192                        } else {
193                                parent.children.add(widget);
194                        }
195                }
196
197                return widget;
198        }
199
200        /**
201         * <p>
202         * Creates a new {@link JFCWidget} from a widget string.
203         * </p>
204         *
205         * @param widgetString
206         *            string describing the widget
207         * @return created {@link JFCWidget}
208         */
209        private JFCWidget generateWidget(String widgetString) {
210                String[] widgetInfo = widgetString.split("','");
211                JFCWidget widget = new JFCWidget();
212                if (widgetInfo[0].startsWith("'Pos(")) {
213                        widget.titles.add("Pos");
214                } else {
215                        widget.titles.add(widgetInfo[0]);
216                }
217                widget.widgetClass = widgetInfo[1];
218                widget.text = widgetInfo[2];
219                widget.index = widgetInfo[3];
220                widget.hashCodes.add(widgetInfo[4]);
221                return widget;
222        }
223
224        /**
225         * <p>
226         * Tries to find the {@link JFCWidget} that the target string identifies in
227         * the known GUI hierarchy, by traversing the known widgets starting with
228         * the {@link #rootWidgets}.
229         *
230         * @param target
231         *            target string whose widget is searched for
232         * @return respective {@link JFCWidget} instance if it is found; null
233         *         otherwise
234         */
235        private JFCWidget find(String target) {
236                JFCWidget widget = null;
237                if (target != null) {
238                        String[] targetParts = target.split("\\]\\.\\[");
239                        if (targetParts.length == 1) {
240                                JFCWidget generatedWidget = generateWidget(target.substring(1,
241                                                target.length() - 1));
242                                int index = rootWidgets.indexOf(generatedWidget);
243                                if (index >= 0) {
244                                        widget = rootWidgets.get(index);
245                                } else {
246                                        return null;
247                                }
248                        } else {
249                                JFCWidget parent = null;
250                                for (int i = 0; i < targetParts.length; i++) {
251                                        if (i == 0) {
252                                                JFCWidget generatedWidget = generateWidget(targetParts[i]
253                                                                .substring(1));
254                                                int index = rootWidgets.indexOf(generatedWidget);
255                                                if (index >= 0) {
256                                                        parent = rootWidgets.get(index);
257                                                } else {
258                                                        return null;
259                                                }
260                                        } else if (i == targetParts.length - 1) {
261                                                JFCWidget generatedWidget = generateWidget(targetParts[i]
262                                                                .substring(0, targetParts[i].length() - 1));
263                                                int index = parent.children.indexOf(generatedWidget);
264                                                if (index >= 0) {
265                                                        widget = parent.children.get(index);
266                                                } else {
267                                                        return null;
268                                                }
269                                        } else {
270                                                JFCWidget generatedWidget = generateWidget(targetParts[i]);
271                                                int index = parent.children.indexOf(generatedWidget);
272                                                if (index >= 0) {
273                                                        parent = parent.children.get(index);
274                                                } else {
275                                                        return null;
276                                                }
277                                        }
278                                }
279                        }
280                }
281                return widget;
282        }
283
284        /**
285         * <p>
286         * Internal class used to store JFCWidgets. The implementation is more like
287         * a C-style structure, than a actual class.
288         * </p>
289         *
290         * @author Steffen Herbold
291         * @version 1.0
292         */
293        private static class JFCWidget {
294
295                /**
296                 * <p>
297                 * Set of all known title strings of the widget.
298                 * </p>
299                 */
300                Set<String> titles = new LinkedHashSet<String>();
301
302                /**
303                 * <p>
304                 * Set of all known hashCodes of the widget.
305                 * </p>
306                 */
307                Set<String> hashCodes = new LinkedHashSet<String>();
308
309                /**
310                 * <p>
311                 * Class of the widget.
312                 * </p>
313                 */
314                String widgetClass;
315
316                /**
317                 * <p>
318                 * Index of the widget.
319                 * </p>
320                 */
321                String index;
322
323                /**
324                 * <p>
325                 * Text of the widget.
326                 * </p>
327                 */
328                String text;
329               
330                int hashCode=0;
331
332                /**
333                 * <p>
334                 * List of children of the widget.
335                 * </p>
336                 */
337                List<JFCWidget> children = new ArrayList<JFCTargetComparator.JFCWidget>();
338
339                /**
340                 * <p>
341                 * Two widgets are equal, if {@link #widgetClass}, {@link #index}, and
342                 * {@link #text} are equal and the intersection of either the
343                 * {@link #hashCodes}, the {@link #titles}, or both of them is not
344                 * empty.
345                 * </p>
346                 *
347                 * @see java.lang.Object#equals(java.lang.Object)
348                 */
349                @Override
350                public boolean equals(Object obj) {
351                        if (obj instanceof JFCWidget) {
352                                JFCWidget other = (JFCWidget) obj;
353                                boolean titleEqual = CollectionUtils.containsAny(titles, other.titles);
354                                boolean hashEqual = CollectionUtils.containsAny(hashCodes, other.hashCodes);
355
356                                boolean retVal;
357                               
358                                if (widgetClass.equals("Class")) {
359                                        retVal = (widgetClass.equals(other.widgetClass)
360                                                        && text.equals(other.text) && (titleEqual || hashEqual));
361                                } else {
362                                        retVal = (widgetClass.equals(other.widgetClass)
363                                                        && index.equals(other.index)
364                                                        && text.equals(other.text) && (titleEqual || hashEqual));
365                                }
366                                return retVal;
367                        }
368                        return false;
369                }
370
371                /*
372                 * (non-Javadoc)
373                 *
374                 * @see java.lang.Object#hashCode()
375                 */
376                @Override
377                public int hashCode() {
378                        if( hashCode==0 ) {
379                                int multiplier = 7;
380                                hashCode = multiplier * hashCode + widgetClass.hashCode();
381                                if (!widgetClass.equals("Class")) {
382                                        hashCode = multiplier * hashCode + index.hashCode();
383                                }
384                                hashCode = multiplier * hashCode + text.hashCode();
385                        }
386                        return hashCode;
387                }
388        }
389}
Note: See TracBrowser for help on using the repository browser.