source: trunk/quest-plugin-jfc/src/main/java/de/ugoe/cs/quest/plugin/jfc/JFCReplayIDCalculator.java @ 675

Last change on this file since 675 was 675, checked in by fglaser, 12 years ago
  • added new JFCReplayIDCalculator, which was merged with new event representation.
  • TestCase? for JFCReplayIDCalculator added.
  • TestData? for JFCReplayIDCalculator added.
  • guimapping for freemind added.
  • Property svn:mime-type set to text/plain
File size: 6.1 KB
Line 
1package de.ugoe.cs.quest.plugin.jfc;
2
3import java.util.Arrays;
4import java.util.LinkedHashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.Stack;
8import java.util.regex.Matcher;
9import java.util.regex.Pattern;
10
11import de.ugoe.cs.quest.eventcore.Event;
12import de.ugoe.cs.quest.eventcore.IEventTarget;
13import de.ugoe.cs.quest.plugin.jfc.guimodel.JFCGUIElement;
14import de.ugoe.cs.quest.plugin.jfc.guimodel.JFCGUIElementSpec;
15
16
17/**
18 * <p>
19 * This class provides the functionality to calculate the unique GUITAR replayIDs
20 * for {@link JFCEvent}s. This code is mainly based on guitar source code: edu.umd.cs.guitar.
21 * model.JFCDefaultIDGeneratorSimple
22 *   
23 * </p>
24 * @author fabian.glaser
25 *
26 */
27
28public class JFCReplayIDCalculator {
29       
30        final int prime = 31;
31       
32        /**
33         * Properties that are used to identify widgets
34         */
35        private static List<String> ID_PROPERTIES = Arrays.asList(
36                        "Class","Title","Icon");
37       
38   /**
39    * Those classes are invisible widgets but cause false-positive when
40    * calculating ID (compare guitar source code: edu.umd.cs.guitar.
41    * model.JFCDefaultIDGeneratorSimple)
42    */
43   private static List<String> IGNORED_CLASSES = Arrays.asList("javax.swing.JPanel",
44         "javax.swing.JTabbedPane", "javax.swing.JScrollPane",
45         "javax.swing.JSplitPane", "javax.swing.Box",
46         "javax.swing.JViewport", "javax.swing.JScrollBar",
47         "javax.swing.JLayeredPane",
48         "javax.swing.JList$AccessibleJList$AccessibleJListChild",
49         "javax.swing.JList$AccessibleJList", "javax.swing.JList",
50         "javax.swing.JScrollPane$ScrollBar",
51         "javax.swing.plaf.metal.MetalScrollButton");
52       
53       
54        /**
55         * Calculates the replayID needed for compatibility with Guitar suite of a JFCEvent
56         * @param event for which the ID should be calculated
57         * @return replayID
58         */
59        public String calculateReplayID(Event event){
60                String replayID = "";
61                long hashCode = 1;
62                Stack<JFCGUIElement> path = new Stack<JFCGUIElement>();
63               
64                IEventTarget target = event.getTarget();
65                JFCGUIElement jfcTarget = (JFCGUIElement) target;
66               
67                // extract target path
68                JFCGUIElement currentTarget = jfcTarget;
69                while (currentTarget != null){
70                        path.push(currentTarget);
71                        currentTarget = (JFCGUIElement) currentTarget.getParent();
72                }
73               
74                // calculate window hashcode
75                currentTarget = path.pop();
76               
77                JFCGUIElementSpec currentSpec = (JFCGUIElementSpec) currentTarget.getSpecification();
78                String title = currentSpec.getName();
79                String fuzzyTitle = getFuzzyTitle(title);
80                long windowHashCode = fuzzyTitle.hashCode();
81                windowHashCode = (windowHashCode * 2) & 0xffffffffL;
82               
83                long propagatedHashCode = windowHashCode;
84               
85                // walk through component path and calculate hashcode
86               
87                while(!path.isEmpty()){
88                        currentTarget = path.pop();
89                        currentSpec = (JFCGUIElementSpec) currentTarget.getSpecification();
90                        long localHashCode = getLocalHashCode(currentSpec);
91                        hashCode = propagatedHashCode * prime + localHashCode;
92                hashCode = (hashCode * 2) & 0xffffffffL;
93                       
94                if (!path.isEmpty()){
95                        Integer index = ((JFCGUIElementSpec) path.lastElement().getSpecification()).getIndex();
96                                propagatedHashCode = prime * propagatedHashCode
97                                + index.hashCode();
98                }
99                }
100               
101                replayID = "e" + hashCode;
102               
103                return replayID;
104        }
105       
106        /**
107         * Calculates the hashcode part of a component.
108         * @param spec The {@link JFCGUIElementSpec} for which the hashcode should be calculated.
109         * @return the local hashcode
110         */
111       
112        private long getLocalHashCode(JFCGUIElementSpec spec){
113                long hashcode = 1;
114                String wClass = spec.getType();
115                if (IGNORED_CLASSES.contains(wClass)) {
116                    hashcode = (prime * hashcode + (wClass.equals("null") ? 0 : (wClass
117                               .hashCode())));
118                    return hashcode;
119                }
120                else{
121                        Map<String, String> idProperties = extractIDProperties(spec);
122                        for (String property: idProperties.keySet()){
123                                String value = idProperties.get(property);
124                                if (!value.equals("null")){
125                                        hashcode = prime * hashcode + property.hashCode();
126                                        hashcode = prime * hashcode + value.hashCode();
127                                }
128                        }
129                }
130               
131                hashcode = (hashcode * 2) & 0xffffffffL;
132               
133                return hashcode;
134        }
135       
136        /**
137         * Extracts the IDProperties from a given {@link JFCGUIElementSpec}.
138         * @param spec
139         * @return LinkedHashMap that contains the IDProperties and its values.
140         */
141       
142        private Map<String, String> extractIDProperties(JFCGUIElementSpec spec){
143                LinkedHashMap<String, String> idProperties = new LinkedHashMap<String, String>();
144                if (ID_PROPERTIES.contains("Class")){
145                        idProperties.put("Class", spec.getType());
146                }
147                if (ID_PROPERTIES.contains("Title")){
148                        idProperties.put("Title", spec.getName());
149                }
150                if (ID_PROPERTIES.contains("Icon")){
151                        idProperties.put("Icon", spec.getIcon());
152                }
153                if (ID_PROPERTIES.contains("Index")){
154                        idProperties.put("Index", Integer.toString(spec.getIndex()));
155                }       
156                return idProperties;
157        }
158       
159        /**
160         * Guitar has a special way to deal with window titles when
161         * calculating unique widget IDs. This method mimics Guitar's
162         * behavior (compare guitar source code: edu.umd.cs.guitar.
163         * model.JFCDefaultIDGeneratorSimple).
164         * @param title
165         * @return fuzzyTitle
166         */
167
168        private String getFuzzyTitle(String title){
169                final List<String> PATTERNS =
170                                Arrays.asList("Rachota .*",
171                                                "OmegaT-.*",
172                                                "Buddi.*",
173                                                "Open:.*",
174                                                "JabRef.*",
175                                                "GanttProject.*",
176                                                ".*Pauker.*",
177                                                ".*FreeMind.*",
178                                                ".* - ArgoUML.*",
179                                                "Save Project .*");
180
181
182                for (String sPattern : PATTERNS) {
183                        if (matchRegex(title, sPattern)) {
184                                return sPattern;
185                        }
186                }
187
188                return title;
189        }
190
191        /**
192         * Determine if the input string matches the input regex pattern.
193         * This method mimics Guitars behavior.
194         * Attempt to match the pattern 'sPattern' with the string 'sInputString'.
195
196         * @param sInputString    Input string to match with pattern
197         * @param sPattern        Regex pattern to match with string
198         * @return                True if match, false otherwise
199         */
200       
201        private static boolean
202        matchRegex(String sInputString,
203                        String sPattern)
204        {
205                Pattern pattern;
206                Matcher matcher;
207
208                pattern = Pattern.compile(sPattern);
209                matcher = pattern.matcher(sInputString);
210                if (matcher.matches()) {
211                        return true;
212                }
213
214                return false;
215        }
216       
217};
Note: See TracBrowser for help on using the repository browser.