Ignore:
Timestamp:
08/27/12 11:45:09 (12 years ago)
Author:
pharms
Message:
  • adapted implementation to now generate a full GUI model as well as concrete GUI interaction events
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 
     2package de.ugoe.cs.quest.plugin.mfc.guimodel; 
    23 
    34import java.util.ArrayList; 
    45import java.util.List; 
    56 
     7import de.ugoe.cs.quest.eventcore.guimodel.IGUIElementSpec; 
    68import de.ugoe.cs.util.StringTools; 
    79 
    810/** 
    911 * <p> 
    10  * This class implements a node in the {@link WindowTree} that is maintained 
    11  * during parsing a session. 
     12 * This class implements a node in the {@link WindowTree} that is maintained during parsing a 
     13 * session. 
    1214 * </p> 
    1315 * <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. 
    1718 * </p> 
    1819 *  
     
    2021 * @version 1.0 
    2122 */ 
    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          * &lt;window name="this.windowname" class="this.className" resourceId="this.resourceId" isModal="this.isModel"/&gt; 
    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         } 
     23public 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    } 
    291391 
    292392} 
  • 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 
     2package de.ugoe.cs.quest.plugin.mfc.guimodel; 
     3 
     4import java.util.ArrayList; 
    35import java.util.HashMap; 
     6import java.util.HashSet; 
    47import java.util.List; 
    58import java.util.Map; 
    6 import java.util.SortedSet; 
    7 import java.util.TreeSet; 
     9import java.util.Set; 
     10 
     11import de.ugoe.cs.quest.eventcore.guimodel.GUIElementFactory; 
     12import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 
     13import de.ugoe.cs.quest.eventcore.guimodel.GUIModelException; 
     14import de.ugoe.cs.quest.eventcore.guimodel.IGUIElementFactory; 
     15 
    816 
    917/** 
     
    1220 * </p> 
    1321 * <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. 
    2524 * </p> 
    2625 *  
     
    3029public class WindowTree { 
    3130 
    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 
    188290} 
Note: See TracChangeset for help on using the changeset viewer.