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:
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 
     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} 
Note: See TracChangeset for help on using the changeset viewer.