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

Last change on this file since 785 was 785, checked in by sherbold, 12 years ago
  • changed field to static
  • Property svn:mime-type set to text/plain
File size: 6.2 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        static 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                        String name = spec.getName();
149                        // spec returns extra "" that need to be removed
150                        idProperties.put("Title", name.substring(1, name.length() - 1));
151                }
152                if (ID_PROPERTIES.contains("Icon")){
153                        idProperties.put("Icon", spec.getIcon());
154                }
155                if (ID_PROPERTIES.contains("Index")){
156                        idProperties.put("Index", Integer.toString(spec.getIndex()));
157                }       
158                return idProperties;
159        }
160       
161        /**
162         * Guitar has a special way to deal with window titles when
163         * calculating unique widget IDs. This method mimics Guitar's
164         * behavior (compare guitar source code: edu.umd.cs.guitar.
165         * model.JFCDefaultIDGeneratorSimple).
166         * @param title
167         * @return fuzzyTitle
168         */
169
170        private String getFuzzyTitle(String title){
171                final List<String> PATTERNS =
172                                Arrays.asList("Rachota .*",
173                                                "OmegaT-.*",
174                                                "Buddi.*",
175                                                "Open:.*",
176                                                "JabRef.*",
177                                                "GanttProject.*",
178                                                ".*Pauker.*",
179                                                ".*FreeMind.*",
180                                                ".* - ArgoUML.*",
181                                                "Save Project .*");
182
183
184                for (String sPattern : PATTERNS) {
185                        if (matchRegex(title, sPattern)) {
186                                return sPattern;
187                        }
188                }
189
190                return title;
191        }
192
193        /**
194         * Determine if the input string matches the input regex pattern.
195         * This method mimics Guitars behavior.
196         * Attempt to match the pattern 'sPattern' with the string 'sInputString'.
197
198         * @param sInputString    Input string to match with pattern
199         * @param sPattern        Regex pattern to match with string
200         * @return                True if match, false otherwise
201         */
202       
203        private static boolean
204        matchRegex(String sInputString,
205                        String sPattern)
206        {
207                Pattern pattern;
208                Matcher matcher;
209
210                pattern = Pattern.compile(sPattern);
211                matcher = pattern.matcher(sInputString);
212                if (matcher.matches()) {
213                        return true;
214                }
215
216                return false;
217        }
218       
219};
Note: See TracBrowser for help on using the repository browser.