- 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:
-
- 13 added
- 2 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 } -
trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/guimodel/WindowTree.java
r578 r619 1 package de.ugoe.cs.quest.plugin.mfc.eventcore; 2 1 2 package de.ugoe.cs.quest.plugin.mfc.guimodel; 3 4 import java.util.ArrayList; 3 5 import java.util.HashMap; 6 import java.util.HashSet; 4 7 import java.util.List; 5 8 import java.util.Map; 6 import java.util.SortedSet; 7 import java.util.TreeSet; 9 import java.util.Set; 10 11 import de.ugoe.cs.quest.eventcore.guimodel.GUIElementFactory; 12 import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 13 import de.ugoe.cs.quest.eventcore.guimodel.GUIModelException; 14 import de.ugoe.cs.quest.eventcore.guimodel.IGUIElementFactory; 15 8 16 9 17 /** … … 12 20 * </p> 13 21 * <p> 14 * The window tree represents the hierarchical structure of the windows 15 * "as it is" currently during a session. It may change during the session due 16 * to creation and destruction of windows. 17 * </p> 18 * <p> 19 * The class is implemented as a singleton. The rational behind implementing 20 * this class as a singleton is to ease the access of all class that may request 21 * information about the windows during the parsing of a session. As the tree 22 * may change during the session, it does not make sense to preserve it after a 23 * session. Thus, it can just be deleted. Therefore, as long as only one session 24 * is parsed at a time, a single instance is sufficient. 22 * The window tree represents the hierarchical structure of the windows "as it is" currently during 23 * a session. It may change during the session due to creation and destruction of windows. 25 24 * </p> 26 25 * … … 30 29 public class WindowTree { 31 30 32 /** 33 * <p> 34 * Handle to the window instance. 35 * </p> 36 */ 37 private static WindowTree theInstance = null; 38 39 /** 40 * <p> 41 * Maintains a set of all the target strings of all widgets that were at 42 * some point part of the window tree. 43 * </p> 44 */ 45 private SortedSet<String> targets; 46 47 /** 48 * <p> 49 * Obtain a handle to the window instance. 50 * </p> 51 * 52 * @return instance of the window tree 53 */ 54 public static WindowTree getInstance() { 55 if (theInstance == null) { 56 theInstance = new WindowTree(); 57 } 58 return theInstance; 59 } 60 61 /** 62 * <p> 63 * Resets the tree. Should be used between sessions. 64 * </p> 65 */ 66 public static void resetTree() { 67 theInstance = null; 68 } 69 70 /** 71 * <p> 72 * Map of all windows that are part of the tree for efficient searching. The 73 * keys of the map are the hwnd's of the windows. 74 * </p> 75 */ 76 private Map<Integer, WindowTreeNode> nodes; 77 78 /** 79 * <p> 80 * Creates a new WindowTree. 81 * </p> 82 * <p> 83 * Private, as the class is a singleton. 84 * </p> 85 */ 86 private WindowTree() { 87 nodes = new HashMap<Integer, WindowTreeNode>(); 88 targets = new TreeSet<String>(); 89 } 90 91 /** 92 * <p> 93 * Adds a new window to the tree. 94 * </p> 95 * 96 * @param parentHwnd 97 * hwnd of the parent window 98 * @param childHwnd 99 * hwnd of the window to be created 100 * @param childWindowName 101 * resource id of the window to be created 102 * @param resourceId 103 * resource id of the window to be created 104 * @param className 105 * class name of the window to be created 106 */ 107 public void add(int parentHwnd, int childHwnd, String childWindowName, 108 int resourceId, String className, boolean isModal) { 109 WindowTreeNode parent = nodes.get(parentHwnd); 110 WindowTreeNode child = nodes.get(childHwnd); 111 if (child == null) { 112 if (parent != null) { 113 child = parent.addChild(childHwnd, childWindowName, resourceId, 114 className, isModal); 115 } else { 116 child = new WindowTreeNode(childHwnd, null, childWindowName, 117 resourceId, className, isModal); 118 } 119 nodes.put(childHwnd, child); 120 targets.add(child.xmlRepresentation()); 121 } 122 } 123 124 /** 125 * <p> 126 * Removes a window (defined by its hwnd) from the tree. All children of the 127 * window will be removed recursively. 128 * </p> 129 * 130 * @param hwnd 131 * hwnd of the window to be removed 132 * @return number of windows that were removed 133 */ 134 public int remove(int hwnd) { 135 int removedCounter = 0; 136 WindowTreeNode node = nodes.get(hwnd); 137 if (node != null) { 138 List<WindowTreeNode> nodesToBeRemoved = node.remove(); 139 for (int i = 0; i < nodesToBeRemoved.size(); i++) { 140 WindowTreeNode nodeToBeRemoved = nodesToBeRemoved.get(i); 141 nodesToBeRemoved.addAll(nodeToBeRemoved.getChildren()); 142 nodes.remove(nodeToBeRemoved.getHwnd()); 143 removedCounter++; 144 } 145 nodes.remove(hwnd); 146 removedCounter++; 147 } 148 return removedCounter; 149 } 150 151 /** 152 * <p> 153 * Searches the tree for a window with the specified hwnd and returns its 154 * {@link WindowTreeNode}. 155 * </p> 156 * 157 * @param hwnd 158 * hwnd that is looked for 159 * @return {@link WindowTreeNode} of the window with the given hwnd if 160 * found, null otherwise 161 */ 162 public WindowTreeNode find(int hwnd) { 163 return nodes.get(hwnd); 164 } 165 166 /** 167 * <p> 168 * Returns the number of nodes contained in the WindowTree. 169 * </p> 170 * 171 * @return number of nodes 172 */ 173 public int size() { 174 return nodes.size(); 175 } 176 177 /** 178 * <p> 179 * Returns a sorted set of all targets that existed any time in the window 180 * tree. 181 * </p> 182 * 183 * @return set of targets 184 */ 185 public SortedSet<String> getTargets() { 186 return targets; 187 } 31 /** 32 * <p> 33 * Maintains a set of all the targets of all widgets that were at some point part of the 34 * window tree. 35 * </p> 36 */ 37 private Set<MFCGUIElementSpec> targets; 38 39 /** 40 * <p> 41 * Map of all GUI element specifications that are part of the tree for efficient searching. 42 * The keys of the map are the hwnd's of the GUI elements. 43 * </p> 44 */ 45 private Map<Long, MFCGUIElementSpec> guiElementSpecs; 46 47 /** 48 * <p> 49 * Map of all children of GUI elements that are part of the tree. The keys of the map are 50 * the hwnd's of the parent GUI elements. 51 * </p> 52 */ 53 private Map<Long, List<MFCGUIElementSpec>> childRelations; 54 55 /** 56 * <p> 57 * Map of all parents of GUI elements that are part of the tree. The keys of the map are 58 * the hwnd's of the child GUI elements. 59 * </p> 60 */ 61 private Map<Long, MFCGUIElementSpec> parentRelations; 62 63 /** 64 * <p> 65 * the internally created GUI model 66 * </p> 67 */ 68 private GUIModel guiModel = new GUIModel(); 69 70 /** 71 * <p> 72 * the GUI element factory used in the model 73 * </p> 74 */ 75 private IGUIElementFactory guiElementFactory = GUIElementFactory.getInstance(); 76 77 /** 78 * <p> 79 * Map of all GUI elements that are part of the tree for efficient searching. The keys of the 80 * map are the hwnd's of the GUI elements. 81 * </p> 82 */ 83 private Map<Long, MFCGUIElement> guiElements; 84 85 /** 86 * <p> 87 * Creates a new WindowTree. 88 * </p> 89 * <p> 90 * Private, as the class is a singleton. 91 * </p> 92 */ 93 public WindowTree() { 94 guiElementSpecs = new HashMap<Long, MFCGUIElementSpec>(); 95 targets = new HashSet<MFCGUIElementSpec>(); 96 childRelations = new HashMap<Long, List<MFCGUIElementSpec>>(); 97 parentRelations = new HashMap<Long, MFCGUIElementSpec>(); 98 guiElements = new HashMap<Long, MFCGUIElement>(); 99 } 100 101 /** 102 * <p> 103 * Adds a new window to the tree. 104 * </p> 105 * 106 * @param parentHwnd 107 * hwnd of the parent window 108 * @param childHwnd 109 * hwnd of the window to be created 110 * @param childWindowName 111 * resource id of the window to be created 112 * @param resourceId 113 * resource id of the window to be created 114 * @param className 115 * class name of the window to be created 116 */ 117 public void add(long parentHwnd, 118 long childHwnd, 119 String childWindowName, 120 int resourceId, 121 String className, 122 boolean isModal) 123 { 124 MFCGUIElementSpec parent = guiElementSpecs.get(parentHwnd); 125 MFCGUIElementSpec child = guiElementSpecs.get(childHwnd); 126 if (child == null) { 127 child = 128 new MFCGUIElementSpec(childHwnd, childWindowName, resourceId, className, isModal); 129 if (parent != null) { 130 List<MFCGUIElementSpec> otherChildren = childRelations.get(parentHwnd); 131 132 if (otherChildren == null) { 133 otherChildren = new ArrayList<MFCGUIElementSpec>(); 134 childRelations.put(parentHwnd, otherChildren); 135 } 136 137 otherChildren.add(child); 138 139 parentRelations.put(childHwnd, parent); 140 } 141 guiElementSpecs.put(childHwnd, child); 142 targets.add(child); 143 } 144 } 145 146 /** 147 * <p> 148 * Searches the tree for a window with the specified hwnd and returns its {@link MFCGUIElementSpec} 149 * . 150 * </p> 151 * 152 * @param hwnd 153 * hwnd that is looked for 154 * @return {@link MFCGUIElementSpec} of the window with the given hwnd if found, null otherwise 155 */ 156 public MFCGUIElement find(long hwnd) { 157 MFCGUIElement guiElement = guiElements.get(hwnd); 158 if (guiElement == null) { 159 List<MFCGUIElementSpec> guiElementPath = new ArrayList<MFCGUIElementSpec>(); 160 161 MFCGUIElementSpec child = guiElementSpecs.get(hwnd); 162 163 if (child == null) { 164 throw new RuntimeException("no GUI element found with id " + hwnd); 165 } 166 167 while (child != null) { 168 guiElementPath.add(0, child); 169 child = parentRelations.get(child.getHwnd()); 170 } 171 172 try { 173 guiElement = (MFCGUIElement) 174 guiModel.integratePath(guiElementPath, guiElementFactory); 175 } 176 catch (GUIModelException e) { 177 throw new RuntimeException("could not instantiate GUI element with id " + hwnd, e); 178 } 179 guiElements.put(hwnd, guiElement); 180 } 181 return guiElement; 182 } 183 184 /** 185 * <p> 186 * TODO: comment 187 * </p> 188 * 189 * @param hwnd 190 * @param windowName 191 */ 192 public void setName(long hwnd, String windowName) { 193 MFCGUIElementSpec child = guiElementSpecs.get(hwnd); 194 if (child != null) { 195 child.setName(windowName); 196 197 MFCGUIElement guiElement = guiElements.remove(hwnd); 198 if (guiElement == null) { 199 // we need to update the GUI model as well 200 find(hwnd); 201 } 202 } 203 } 204 205 /** 206 * <p> 207 * Removes a window (defined by its hwnd) from the tree. All children of the window will be 208 * removed recursively. 209 * </p> 210 * 211 * @param hwnd 212 * hwnd of the window to be removed 213 * @return number of windows that were removed 214 */ 215 public int remove(long hwnd) { 216 MFCGUIElementSpec node = guiElementSpecs.remove(hwnd); 217 int removedCounter = 1; 218 219 if (node != null) { 220 List<MFCGUIElementSpec> nodesToBeRemoved = childRelations.remove(hwnd); 221 222 // remove all children and sub-children, if any 223 if (nodesToBeRemoved != null) { 224 for (int i = 0; i < nodesToBeRemoved.size(); i++) { 225 MFCGUIElementSpec nodeToBeRemoved = nodesToBeRemoved.get(i); 226 List<MFCGUIElementSpec> children = 227 childRelations.remove(nodeToBeRemoved.getHwnd()); 228 229 if (children != null) { 230 nodesToBeRemoved.addAll(children); 231 } 232 233 guiElementSpecs.remove(nodeToBeRemoved.getHwnd()); 234 parentRelations.remove(nodeToBeRemoved.getHwnd()); 235 removedCounter++; 236 } 237 } 238 239 // the node may be a child node of a parent. So search for it and remove it 240 MFCGUIElementSpec parent = parentRelations.remove(hwnd); 241 if (parent != null) { 242 List<MFCGUIElementSpec> children = childRelations.get(parent.getHwnd()); 243 244 if (children != null) { 245 for (int i = 0; i < children.size(); i++) { 246 if (children.get(i).getHwnd() == hwnd) { 247 children.remove(i); 248 break; 249 } 250 } 251 252 if (children.size() <= 0) { 253 childRelations.remove(parent.getHwnd()); 254 } 255 } 256 } 257 } 258 return removedCounter; 259 } 260 261 /** 262 * @return the guiModel 263 */ 264 public GUIModel getGUIModel() { 265 return guiModel; 266 } 267 268 /** 269 * <p> 270 * Returns the number of nodes contained in the WindowTree. 271 * </p> 272 * 273 * @return number of nodes 274 */ 275 public int size() { 276 return guiElementSpecs.size(); 277 } 278 279 /** 280 * <p> 281 * Returns a sorted set of all targets that existed any time in the window tree. 282 * </p> 283 * 284 * @return set of targets 285 */ 286 public Set<MFCGUIElementSpec> getTargets() { 287 return targets; 288 } 289 188 290 }
Note: See TracChangeset
for help on using the changeset viewer.