Changeset 619 for trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/guimodel/MFCGUIElementSpec.java
- Timestamp:
- 08/27/12 11:45:09 (12 years ago)
- Location:
- trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/guimodel
- Files:
-
- 1 added
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/guimodel/MFCGUIElementSpec.java
r578 r619 1 package de.ugoe.cs.quest.plugin.mfc.eventcore; 1 2 package de.ugoe.cs.quest.plugin.mfc.guimodel; 2 3 3 4 import java.util.ArrayList; 4 5 import java.util.List; 5 6 7 import de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec; 6 8 import de.ugoe.cs.util.StringTools; 7 9 8 10 /** 9 11 * <p> 10 * This class implements a node in the {@link WindowTree} that is maintained 11 * during parsing asession.12 * This class implements a node in the {@link WindowTree} that is maintained during parsing a 13 * session. 12 14 * </p> 13 15 * <p> 14 * The window tree is structure that contains the hierarchy of the windows of a 15 * application as well as basic information about each window: the hwnd; its 16 * name; its resource id; its class name. 16 * The window tree is structure that contains the hierarchy of the windows of a application as well 17 * as basic information about each window: the hwnd; its name; its resource id; its class name. 17 18 * </p> 18 19 * … … 20 21 * @version 1.0 21 22 */ 22 public class WindowTreeNode { 23 24 /** 25 * <p> 26 * Name of the window. May change over time. 27 * </p> 28 */ 29 private String windowName; 30 31 /** 32 * <p> 33 * Handle of the window. Used as unique identifier during its existence. 34 * </p> 35 */ 36 private final int hwnd; 37 38 /** 39 * <p> 40 * Resource id of the window. 41 * </p> 42 */ 43 private final int resourceId; 44 45 /** 46 * <p> 47 * Class name of the window. 48 * </p> 49 */ 50 private final String className; 51 52 /** 53 * <p> 54 * True, if the window is modal. 55 * </p> 56 */ 57 private final boolean isModal; 58 59 /** 60 * <p> 61 * Parent of the window. <code>null</code> if the window has no parent. 62 * </p> 63 */ 64 private WindowTreeNode parent; 65 66 /** 67 * <p> 68 * List of the windows children. May be empty. 69 * </p> 70 */ 71 private List<WindowTreeNode> children; 72 73 /** 74 * <p> 75 * Creates a new WindowTreeNode. 76 * </p> 77 * <p> 78 * The constructor is protected WindowTreeNode may only be created from the 79 * WindowTree. 80 * </p> 81 * 82 * @param hwnd 83 * hwnd of the window 84 * @param parent 85 * reference to the parent's WindowTreeNode 86 * @param windowName 87 * name of the window 88 * @param resourceId 89 * resource id of the window 90 * @param className 91 * class name of the window 92 * @param isModal 93 * modality of the window 94 */ 95 protected WindowTreeNode(int hwnd, WindowTreeNode parent, 96 String windowName, int resourceId, String className, boolean isModal) { 97 this.hwnd = hwnd; 98 this.parent = parent; 99 this.windowName = windowName; 100 this.resourceId = resourceId; 101 this.className = className; 102 this.isModal = isModal; 103 children = new ArrayList<WindowTreeNode>(); 104 } 105 106 /** 107 * <p> 108 * Returns a reference to the WindowTreeNode of the parent. 109 * </p> 110 * 111 * @return WindowTreeNode of the parent 112 */ 113 public WindowTreeNode getParent() { 114 return parent; 115 } 116 117 /** 118 * <p> 119 * Returns the list of the windows children. 120 * </p> 121 * 122 * @return list of the windows children 123 */ 124 public List<WindowTreeNode> getChildren() { 125 return children; 126 } 127 128 /** 129 * <p> 130 * Returns the name of the window. 131 * </p> 132 * 133 * @return name of the window 134 */ 135 public String getName() { 136 return windowName; 137 } 138 139 /** 140 * <p> 141 * Returns the hwnd of the window. 142 * </p> 143 * 144 * @return hwnd of the window 145 */ 146 public int getHwnd() { 147 return hwnd; 148 } 149 150 /** 151 * <p> 152 * Returns the resource id of the window. 153 * </p> 154 * 155 * @return resource id of the window 156 */ 157 public int getResourceId() { 158 return resourceId; 159 } 160 161 /** 162 * <p> 163 * Returns the class name of the window. 164 * </p> 165 * 166 * @return class name of the window 167 */ 168 public String getClassName() { 169 return className; 170 } 171 172 /** 173 * <p> 174 * Sets the name of the window. 175 * </p> 176 * 177 * @param text 178 * new name of the window 179 */ 180 public void setName(String text) { 181 windowName = text; 182 } 183 184 /** 185 * <p> 186 * Removes a the window and all its children from the {@link WindowTree}. 187 * </p> 188 * 189 * @return list of the children of the window for further clean up. 190 */ 191 public List<WindowTreeNode> remove() { 192 if (parent != null) { 193 parent.removeChild(this); 194 } 195 return children; 196 } 197 198 /** 199 * <p> 200 * Removes a child window. 201 * </p> 202 * 203 * @param child 204 * reference to the child window to be removed 205 */ 206 public void removeChild(WindowTreeNode child) { 207 children.remove(child); 208 } 209 210 /** 211 * <p> 212 * Adds a new child window and creates WindowTreeNode for it. 213 * </p> 214 * 215 * @param childHwnd 216 * hwnd of the child window 217 * @param childWindowName 218 * name of the child window 219 * @param resourceId 220 * resource id of the child window 221 * @param className 222 * class name of the child window 223 * @param isModal 224 * modality of the child window 225 * @return reference to the WindowTreeNode created for the child window 226 */ 227 public WindowTreeNode addChild(int childHwnd, String childWindowName, 228 int resourceId, String className, boolean isModal) { 229 WindowTreeNode child = new WindowTreeNode(childHwnd, this, 230 childWindowName, resourceId, className, isModal); 231 children.add(child); 232 return child; 233 } 234 235 /** 236 * <p> 237 * Returns a string identfier of the window:<br> 238 * {@code [resourceId;"windowName";"className";modality]} 239 * </p> 240 * 241 * @return identifier string of the window 242 */ 243 @Override 244 public String toString() { 245 return "[" + resourceId + ";\"" + windowName + "\";\"" + className 246 + "\";" + isModal + "]"; 247 } 248 249 /** 250 * <p> 251 * Returns an XML representation of the window, including its parents. It is 252 * defined as follows:<br> 253 * <code> 254 * parent#xmlRepresentation()<br> 255 * <window name="this.windowname" class="this.className" resourceId="this.resourceId" isModal="this.isModel"/> 256 * </code> 257 * </p> 258 * 259 * @return xml representation of the window 260 */ 261 public String xmlRepresentation() { 262 String xmlString = ""; 263 if (parent != null) { 264 xmlString = parent.xmlRepresentation(); 265 } 266 xmlString += "<window name=\"" 267 + StringTools.xmlEntityReplacement(windowName) + "\" class=\"" 268 + StringTools.xmlEntityReplacement(className) 269 + "\" resourceId=\"" + resourceId + "\" isModal=\"" + isModal 270 + "\" hwnd=\"" + hwnd + "\"" 271 + "/>"; 272 return xmlString; 273 } 274 275 /** 276 * <p> 277 * Returns the names of the parents and itself separated by dots, e.g., 278 * "GrandParent.Parent.windowName" 279 * </p> 280 * 281 * @return names of the parents separated by dots 282 */ 283 public String getParentNames() { 284 String parentNames = ""; 285 if (parent != null) { 286 parentNames = parent.getParentNames() + "."; 287 } 288 parentNames += windowName; 289 return parentNames; 290 } 23 public class MFCGUIElementSpec implements IGUIElementSpec { 24 25 /** 26 * <p> 27 * current name of the window 28 * </p> 29 */ 30 private String name; 31 32 /** 33 * <p> 34 * previous names of the window as it may have changed over time. 35 * </p> 36 */ 37 private List<String> formerNames = new ArrayList<String>(); 38 39 /** 40 * <p> 41 * Handle of the window. Used as unique identifier during its existence. 42 * </p> 43 */ 44 private long hwnd; 45 46 /** 47 * <p> 48 * previous handles of the window as the window may have been destroyed and recreated 49 * </p> 50 */ 51 private List<Long> formerHwnds = new ArrayList<Long>(); 52 53 /** 54 * <p> 55 * Resource id of the window. 56 * </p> 57 */ 58 private final int resourceId; 59 60 /** 61 * <p> 62 * type (class name) of the window. 63 * </p> 64 */ 65 private final String type; 66 67 /** 68 * <p> 69 * True, if the window is modal. 70 * </p> 71 */ 72 private final boolean isModal; 73 74 /** 75 * <p> 76 * Creates a new WindowTreeNode. 77 * </p> 78 * <p> 79 * The constructor is protected WindowTreeNode may only be created from the WindowTree. 80 * </p> 81 * 82 * @param hwnd 83 * hwnd of the window 84 * @param parent 85 * reference to the parent's WindowTreeNode 86 * @param name 87 * name of the window 88 * @param resourceId 89 * resource id of the window 90 * @param type 91 * type, i.e. class name of the window 92 * @param isModal 93 * modality of the window 94 */ 95 protected MFCGUIElementSpec(long hwnd, 96 String name, 97 int resourceId, 98 String type, 99 boolean isModal) 100 { 101 this.hwnd = hwnd; 102 this.name = name; 103 this.resourceId = resourceId; 104 this.type = type; 105 this.isModal = isModal; 106 } 107 108 /** 109 * <p> 110 * Returns the name of the window. 111 * </p> 112 * 113 * @return name of the window 114 */ 115 public String getName() { 116 StringBuffer names = new StringBuffer(); 117 118 if (name != null) { 119 names.append('"'); 120 names.append(name); 121 names.append('"'); 122 } 123 else { 124 names.append("NOT_SET"); 125 } 126 127 if (formerNames.size() > 0) { 128 129 names.append(" (aka "); 130 131 for (int i = 0; i < formerNames.size(); i++) { 132 if (i > 0) { 133 names.append("/"); 134 } 135 136 names.append('"'); 137 names.append(formerNames.get(i)); 138 names.append('"'); 139 } 140 141 names.append(")"); 142 } 143 144 return names.toString(); 145 } 146 147 /** 148 * <p> 149 * Returns the hwnd of the window. 150 * </p> 151 * 152 * @return hwnd of the window 153 */ 154 public long getHwnd() { 155 return hwnd; 156 } 157 158 /** 159 * <p> 160 * Returns the resource id of the window. 161 * </p> 162 * 163 * @return resource id of the window 164 */ 165 public int getResourceId() { 166 return resourceId; 167 } 168 169 /* (non-Javadoc) 170 * @see de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec#getType() 171 */ 172 @Override 173 public String getType() { 174 return type; 175 } 176 177 /** 178 * <p> 179 * TODO: comment 180 * </p> 181 * 182 * @return 183 */ 184 public boolean isModal() { 185 return isModal; 186 } 187 188 /** 189 * <p> 190 * Sets the name of the window. 191 * </p> 192 * 193 * @param text 194 * new name of the window 195 */ 196 public void setName(String newName) { 197 if ((this.name != null) && 198 (!this.name.equals(newName)) && 199 (!this.formerNames.contains(this.name))) 200 { 201 this.formerNames.add(this.name); 202 } 203 204 this.name = newName; 205 } 206 207 /** 208 * <p> 209 * Sets the hwnd of the window. 210 * </p> 211 * 212 * @param text 213 * new name of the window 214 */ 215 public void setHwnd(long newHwnd) { 216 if (!this.formerHwnds.contains(this.hwnd)) { 217 this.formerHwnds.add(this.hwnd); 218 } 219 220 this.hwnd = newHwnd; 221 } 222 223 /* (non-Javadoc) 224 * @see de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec#getSimilarity(de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec) 225 */ 226 @Override 227 public boolean getSimilarity(IGUIElementSpec other) { 228 229 if (this == other) { 230 return true; 231 } 232 233 if (!(other instanceof MFCGUIElementSpec)) { 234 return false; 235 } 236 237 MFCGUIElementSpec otherSpec = (MFCGUIElementSpec) other; 238 239 if ((type != otherSpec.type) && ((type != null) && (!type.equals(otherSpec.type)))) { 240 return false; 241 } 242 243 if (isModal != otherSpec.isModal) { 244 return false; 245 } 246 247 if (resourceId != otherSpec.resourceId) { 248 return false; 249 } 250 251 // up to now, we compared, if the basics match. Now lets compare the id and the 252 // name. Both may change. The name may be reset (e.g. the title of a frame using the 253 // asterisk in the case data was changed). The id may change if e.g. a dialog is closed 254 // and reopend, i.e. a new instance is created. If one of them stays the same, then 255 // similarity is given. Therefore these are the first two comparisons 256 257 if (hwnd == otherSpec.hwnd) { 258 return true; 259 } 260 261 if ((name != null) && (name.equals(otherSpec.name))) { 262 return true; 263 } 264 265 if ((((name == null) && (otherSpec.name == null)) || 266 (("".equals(name)) && ("".equals(otherSpec.name)))) && 267 (formerNames.size() == 0) && (otherSpec.formerNames.size() == 0)) 268 { 269 return true; 270 } 271 272 // if the hwnd and the name did not stay the same, then the name should be checked first. 273 // the current name of one of the specs must be contained in the former names of the 274 // respective other spec for similarity. Either of the specs should contain the name of the 275 // respective other spec in its former names. We can rely on this, as in the MFC context 276 // we get to know each name change. I.e. although currently the names of the specs differ, 277 // once they were identical. But it is sufficient to do it for the current names of the 278 // elements, as only one of them may have experienced more name changes then the other. 279 280 if ((otherSpec.name != null) && formerNames.contains(otherSpec.name)) 281 { 282 return true; 283 } 284 285 if ((name != null) && otherSpec.formerNames.contains(name)) { 286 return true; 287 } 288 289 // ok. Even the names to not match. This is usually a clear indication, that the elements 290 // are distinct. However, we check, if the former handles matched. This is very unlikely 291 // to happen. But it may occur, if a GUI element does not have a name or its name stays 292 // the empty string and if this GUI element is created, destroyed, and created again. 293 294 if (formerHwnds.contains(otherSpec.hwnd) || otherSpec.formerHwnds.contains(hwnd)) { 295 return true; 296 } 297 298 // now we can be really sure, that the GUI elements differ 299 300 return false; 301 } 302 303 /* (non-Javadoc) 304 * @see de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec) 305 */ 306 @Override 307 public boolean equals(IGUIElementSpec other) { 308 309 if (this == other) { 310 return true; 311 } 312 313 if (!(other instanceof MFCGUIElementSpec)) { 314 return false; 315 } 316 317 MFCGUIElementSpec otherSpec = (MFCGUIElementSpec) other; 318 319 return 320 (hwnd == otherSpec.hwnd) && (isModal == otherSpec.isModal) && 321 (resourceId == otherSpec.resourceId) && 322 ((type == otherSpec.type) || ((type != null) && (type.equals(otherSpec.type)))) && 323 ((name == otherSpec.name) || ((name != null) && (name.equals(otherSpec.name)))); 324 } 325 326 /* (non-Javadoc) 327 * @see java.lang.Object#hashCode() 328 */ 329 @Override 330 public int hashCode() { 331 // reuse only invariable elements 332 return (type + isModal + resourceId).hashCode(); 333 } 334 335 /** 336 * <p> 337 * Returns a string identfier of the window:<br> 338 * {@code [resourceId;"windowName";"className";modality]} 339 * </p> 340 * 341 * @return identifier string of the window 342 */ 343 @Override 344 public String toString() { 345 return "[" + resourceId + ";" + getName() + ";\"" + type + "\";" + isModal + ";" + 346 hwnd + "]"; 347 } 348 349 /** 350 * <p> 351 * TODO: comment 352 * </p> 353 */ 354 String toXML() { 355 return 356 "<window name=\"" + (name != null ? StringTools.xmlEntityReplacement(name) : "") + 357 "\" class=\"" + StringTools.xmlEntityReplacement(type) + 358 "\" resourceId=\"" + resourceId + "\" isModal=\"" + 359 isModal + "\" hwnd=\"" + hwnd + "\"" + "/>"; 360 } 361 362 /** 363 * <p> 364 * TODO: comment 365 * </p> 366 * 367 * @param furtherSpec 368 */ 369 void update(IGUIElementSpec furtherSpec) { 370 MFCGUIElementSpec other = (MFCGUIElementSpec) furtherSpec; 371 372 if (other != this) { 373 for (long formerHwnd : other.formerHwnds) { 374 setHwnd(formerHwnd); 375 } 376 377 if (hwnd != other.hwnd) { 378 hwnd = other.hwnd; 379 } 380 381 for (String formerName : other.formerNames) { 382 setName(formerName); 383 } 384 385 if ((name != other.name) && (name != null) && (!name.equals(other.name))) 386 { 387 setName(other.name); 388 } 389 } 390 } 291 391 292 392 }
Note: See TracChangeset
for help on using the changeset viewer.