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

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