Changeset 619


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
Files:
17 added
6 deleted
10 edited
4 copied

Legend:

Unmodified
Added
Removed
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/EventGenerator.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
    34import java.io.IOException; 
    45import java.security.InvalidParameterException; 
     6import java.util.ArrayList; 
    57import java.util.HashMap; 
    68import java.util.Iterator; 
     
    1820 
    1921import de.ugoe.cs.quest.eventcore.Event; 
    20 import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventTarget; 
    21 import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventType; 
    22 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
    23 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTreeNode; 
     22import de.ugoe.cs.quest.eventcore.IEventType; 
     23import de.ugoe.cs.quest.plugin.mfc.EventGenerationRule.Term; 
     24import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEvent; 
     25import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCEventTypeFactory; 
     26import de.ugoe.cs.quest.plugin.mfc.eventcore.ReplayWindowsMessage; 
    2427import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage; 
     28import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; 
     29import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 
     30import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    2531import de.ugoe.cs.util.console.Console; 
    2632 
    2733/** 
    2834 * <p> 
    29  * Translates sequences of windows messages into {@link WindowsEvent}s that can 
    30  * be used by the EventBench core libraries. 
     35 * Translates sequences of windows messages into {@link WindowsEvent}s that can be used by the 
     36 * EventBench core libraries. 
    3137 * </p> 
    3238 *  
     
    3642public class EventGenerator { 
    3743 
    38         /** 
    39          * <p> 
    40          * Helper method that fetches the document node of an XML file. 
    41          * </p> 
    42          *  
    43          * @param filename 
    44          *            name of the XML file 
    45          * @return the document node 
    46          */ 
    47         private static Document getDocument(String filename) { 
    48                 SAXBuilder builder = new SAXBuilder(); 
    49                 Document doc = null; 
    50  
    51                 try { 
    52                         doc = builder.build(filename); 
    53                         rulesNamespace = Namespace.getNamespace("ul:rules"); 
    54                 } catch (JDOMException e) { 
    55                         Console.printerrln("Invalid rules file."); 
    56                         e.printStackTrace(); 
    57                 } catch (IOException e) { 
    58                         Console.printerrln("Invalid rules file."); 
    59                         e.printStackTrace(); 
    60                 } 
    61  
    62                 return doc; 
    63         } 
    64  
    65         /** 
    66          * <p> 
    67          * Name and path of the XML files containing the rules. 
    68          * </p> 
    69          */ 
    70         private String rulesFile; 
    71  
    72         /** 
    73          * <p> 
    74          * Iterator used for the current sequence. 
    75          * </p> 
    76          */ 
    77         private ListIterator<WindowsMessage> sequenceIterator; 
    78  
    79         /** 
    80          * <p> 
    81          * Token that is currently being generated. 
    82          * </p> 
    83          */ 
    84         private Event currentToken; 
    85          
    86         /** 
    87          * <p> 
    88          * Event type of the current token. Stored as a member to be able to update it during the parsing of the idinfo tag. 
    89          * </p> 
    90          */ 
    91         private MFCEventType currentType; 
    92  
    93         /** 
    94          * <p> 
    95          * Reference to the ul:rules namespace. 
    96          * </p> 
    97          */ 
    98         private static Namespace rulesNamespace; 
    99  
    100         /** 
    101          * <p> 
    102          * The name of the rule that is currently being evaluated. 
    103          * </p> 
    104          */ 
    105         private String currentRuleName; 
    106  
    107         /** 
    108          * <p> 
    109          * Internal message storage. Used to implement the 
    110          * <code>{@literal <store>}</code> and <code>{@literal <storeSeq>}</code> 
    111          * tags. 
    112          * </p> 
    113          */ 
    114         private Map<String, Object> messageStorage; 
    115  
    116         /** 
    117          * <p> 
    118          * Creates a new EventGenerator. Sets "data/rules.xml" as default file for 
    119          * the rules. 
    120          * </p> 
    121          */ 
    122         public EventGenerator() { 
    123                 rulesFile = "data/rules.xml"; 
    124         } 
    125  
    126         /** 
    127          * <p> 
    128          * Tries to match the rules to the given sequence to generate an 
    129          * {@link WindowsEvent}. 
    130          * </p> 
    131          * <p> 
    132          * The rules are matched the order, in which they are defined in the XML 
    133          * file. Therefore, the order of the rules in the file defines priorities, 
    134          * when multiple rules could be matched to the same sequence. 
    135          * </p> 
    136          *  
    137          * @param sequence 
    138          *            sequence of message for which an event will be generated 
    139          * @return event that matches the messages; null, if no rule can be matched 
    140          */ 
    141         @SuppressWarnings("unchecked") 
    142         public Event generateEvent(List<WindowsMessage> sequence) { 
    143                 Document rulesDoc = getDocument(rulesFile); 
    144                 Element rulesRoot = rulesDoc.getRootElement(); 
    145  
    146                 List<Element> ruleElements = rulesRoot.getChildren("rule", 
    147                                 rulesNamespace); 
    148  
    149                 boolean isMatch = false; 
    150  
    151                 for (int ruleIndex = 0; ruleIndex < ruleElements.size() && !isMatch; ruleIndex++) { 
    152                         Element currentRule = ruleElements.get(ruleIndex); 
    153                         currentRuleName = currentRule.getAttributeValue("name"); 
    154                         currentType = new MFCEventType(currentRuleName); 
    155                         currentToken = new Event(currentType); 
    156                          
    157                         isMatch = true; 
    158                         messageStorage = new HashMap<String, Object>(); 
    159                         sequenceIterator = sequence.listIterator(); 
    160                         List<Element> ruleChildrenMsg = currentRule.getChildren("msg", 
    161                                         rulesNamespace); 
    162  
    163                         int i = 0; 
    164                         while (isMatch && i < ruleChildrenMsg.size()) { 
    165                                 Element messageElement = ruleChildrenMsg.get(i); 
    166                                 if ("true".equals(messageElement.getAttributeValue("multiple"))) { 
    167                                         Element nextMessageElement = null; 
    168                                         if (i + 1 < ruleChildrenMsg.size()) { 
    169                                                 nextMessageElement = ruleChildrenMsg.get(i + 1); 
    170                                         } 
    171                                         try { 
    172                                                 isMatch = matchMultipleMessages(messageElement, 
    173                                                                 nextMessageElement); 
    174                                         } catch (InvalidParameterException e) { 
    175                                                 Console.printerrln(e.getMessage()); 
    176                                         } 
    177                                 } else { 
    178                                         try { 
    179                                                 isMatch = matchSingleMessage(messageElement); 
    180                                         } catch (InvalidParameterException e) { 
    181                                                 Console.printerrln(e.getMessage()); 
    182                                         } 
    183                                 } 
    184                                 i++; 
    185                         } 
    186                         if (isMatch) { 
    187                                 List<Element> ruleChildren = currentRule.getChildren(); 
    188                                 for (Element genMsgElement : ruleChildren) { 
    189                                         if (genMsgElement.getName().equals("genMsg")) { 
    190                                                 try { 
    191                                                         generateReplayMessage(genMsgElement); 
    192                                                 } catch (InvalidParameterException e) { 
    193                                                         Console.printerrln(e.getMessage()); 
    194                                                         // TODO currentToken.invalidateReplay(); 
    195                                                 } 
    196                                         } else if (genMsgElement.getName().equals("genMsgSeq")) { 
    197                                                 try { 
    198                                                         generateReplaySequence(genMsgElement); 
    199                                                         // TODO currentToken.invalidateReplay(); 
    200                                                 } catch (InvalidParameterException e) { 
    201                                                         Console.printerrln(e.getMessage()); 
    202                                                         // TODO currentToken.invalidateReplay(); 
    203                                                 } 
    204                                         } 
    205                                 } 
    206                                 Element idinfoElement = currentRule.getChild("idinfo", 
    207                                                 rulesNamespace); 
    208                                 if (idinfoElement != null) { 
    209                                         // cannot be empty if document is valid 
    210                                         List<Element> valueElements = idinfoElement.getChildren(); 
    211                                         currentType.setInfo(getTermValue(null, 
    212                                                         valueElements.get(0))); 
    213                                 } 
    214                                 Console.traceln(currentToken.getType().toString() + " matched"); 
    215                         } else { 
    216                                 currentToken = null; 
    217                         } 
    218                 } 
    219                 if (!isMatch) { 
    220                         Console.traceln("no match found for sequence: " 
    221                                         + sequence.toString()); 
    222                 } 
    223                 return currentToken; 
    224         } 
    225  
    226         // //////////////////////////////////////////////////////////// 
    227         // Helper functions for matching of events, i.e., msg-nodes // 
    228         // //////////////////////////////////////////////////////////// 
    229  
    230         /** 
    231          * <p> 
    232          * Handles msg-nodes where multiple is not true, i.e., not a sequences. 
    233          * </p> 
    234          *  
    235          * @param messageElement 
    236          *            {@link Element} representing the msg-node 
    237          * @return true, if a match is found; false otherwise 
    238          */ 
    239         private boolean matchSingleMessage(Element messageElement) { 
    240                 boolean isMatch = false; 
    241                 WindowsMessage currentMessage = null; 
    242  
    243                 int type = Integer.parseInt(messageElement.getAttributeValue("type")); 
    244  
    245                 while (!isMatch && sequenceIterator.hasNext()) { 
    246                         /* 
    247                          * traverses the messages from the current position forward till a 
    248                          * message with the correct type is found 
    249                          */ 
    250                         currentMessage = sequenceIterator.next(); 
    251                         if (type == currentMessage.getType()) { 
    252                                 // message with the correct type found 
    253                                 // eval child nodes for further matching/storing 
    254                                 isMatch = evalEqualRestrictions(currentMessage, messageElement); 
    255  
    256                                 // in case the message is a match, eval storage children 
    257                                 if (isMatch) { 
    258                                         handleStorage(messageElement, currentMessage); 
    259                                         currentToken.setTarget(new MFCEventTarget(currentMessage 
    260                                                         .getXmlWindowDescription())); 
    261                                         // TODO currentToken.setTargetShort(currentMessage.getParentNames()); 
    262                                 } 
    263                         } 
    264                 } 
    265  
    266                 return isMatch; 
    267         } 
    268  
    269         /** 
    270          * <p> 
    271          * Handles msg-nodes where multiple is true, i.e., sequences. Requires 
    272          * knowledge about the next msg-node to determine the end of the sequence. 
    273          * </p> 
    274          *  
    275          * @param messageElement 
    276          *            {@link Element} representing the msg-node 
    277          * @param nextMessageElement 
    278          *            {@link Element} representing the next msg-node; {@code null} 
    279          *            if the current node is the last one 
    280          * @return true, if a sequence is matched; false otherwise 
    281          */ 
    282         private boolean matchMultipleMessages(Element messageElement, 
    283                         Element nextMessageElement) { 
    284                 boolean isMatch = false; 
    285                 boolean isCurrentMatch = false; 
    286                 boolean nextMatchFound = false; 
    287                 WindowsMessage currentMessage = null; 
    288                 WindowsMessage nextMessage = null; 
    289  
    290                 int type = Integer.parseInt(messageElement.getAttributeValue("type")); 
    291  
    292                 int nextType = -1; 
    293                 if (nextMessageElement != null) { 
    294                         nextType = Integer.parseInt(nextMessageElement 
    295                                         .getAttributeValue("type")); 
    296                 } 
    297  
    298                 while (!nextMatchFound && sequenceIterator.hasNext()) { 
    299                         currentMessage = sequenceIterator.next(); 
    300                         if (type == currentMessage.getType()) { 
    301                                 isCurrentMatch = evalEqualRestrictions(currentMessage, 
    302                                                 messageElement); 
    303                                 isMatch = isMatch || isCurrentMatch; 
    304  
    305                                 if (isCurrentMatch) { 
    306                                         handleStorage(messageElement, currentMessage); 
    307                                         currentToken.setTarget(new MFCEventTarget(currentMessage 
    308                                                         .getXmlWindowDescription())); 
    309                                         // TODO currentToken.setTargetShort(currentMessage.getParentNames()); 
    310                                 } 
    311                         } 
    312                         if (nextMessageElement != null && isMatch) { 
    313                                 // peek next message to check if the sequence ends and the next 
    314                                 // match is found 
    315                                 if (!sequenceIterator.hasNext()) { 
    316                                         return false; // sequence is over, but not all messages are 
    317                                                                         // found 
    318                                 } 
    319                                 nextMessage = sequenceIterator.next(); 
    320                                 sequenceIterator.previous(); 
    321  
    322                                 if (nextType == nextMessage.getType()) { 
    323                                         nextMatchFound = evalEqualRestrictions(nextMessage, 
    324                                                         nextMessageElement); 
    325                                 } 
    326  
    327                         } 
    328                 } 
    329  
    330                 return isMatch; 
    331         } 
    332  
    333         /** 
    334          * <p> 
    335          * Handles equals-nodes. 
    336          * </p> 
    337          *  
    338          * @param currentMessage 
    339          *            {@link Element} representing the msg-node the equals-node 
    340          *            belongs to 
    341          * @param messageElement 
    342          *            {@link Element} representing the equals-node to be evaluated 
    343          * @return true, if constraint is fulfilled; false otherwise 
    344          */ 
    345         @SuppressWarnings("unchecked") 
    346         private boolean evalEqualRestrictions(WindowsMessage currentMessage, 
    347                         Element messageElement) { 
    348                 boolean isMatch = true; 
    349                 for (Element childElement : (List<Element>) messageElement.getChildren( 
    350                                 "equals", rulesNamespace)) { 
    351                         List<Element> termElements = childElement.getChildren(); 
    352                         // the size 2 of termElements is guaranteed by the XML schema 
    353                         String value1 = getTermValue(currentMessage, termElements.get(0)); 
    354                         String value2 = getTermValue(currentMessage, termElements.get(1)); 
    355                         if (value1 == null || value2 == null) { 
    356                                 isMatch = false; 
    357                         } else { 
    358                                 isMatch = isMatch && value1.equals(value2); 
    359                         } 
    360                 } 
    361                 for (Element childElement : (List<Element>) messageElement.getChildren( 
    362                                 "equalsSeq", rulesNamespace)) { 
    363                         List<Element> termElements = childElement.getChildren(); 
    364                         List<String> values1 = getTermValueSeq(termElements.get(0)); 
    365                         List<String> values2 = getTermValueSeq(termElements.get(0)); 
    366                         if (values1 == null || values2 == null) { 
    367                                 isMatch = false; 
    368                         } else { 
    369                                 isMatch = isMatch && values1.equals(values2); 
    370                         } 
    371                 } 
    372                 return isMatch; 
    373         } 
    374  
    375         /** 
    376          * <p> 
    377          * Handles store-nodes and storeSeq-nodes. 
    378          * </p> 
    379          *  
    380          * @param messageElement 
    381          *            {@link Element} representing the msg-node that is currently 
    382          *            being evaluated 
    383          * @param currentMessage 
    384          *            current message in the message sequence that is matched; this 
    385          *            is the message that is stored 
    386          */ 
    387         @SuppressWarnings("unchecked") 
    388         private void handleStorage(Element messageElement, 
    389                         WindowsMessage currentMessage) { 
    390                 for (Element childElement : (List<Element>) messageElement.getChildren( 
    391                                 "store", rulesNamespace)) { 
    392                         String identifier = childElement.getAttributeValue("var"); 
    393                         messageStorage.put(identifier, currentMessage); 
    394                         resolveHwnd(currentMessage, childElement); 
    395                 } 
    396                 for (Element childElement : (List<Element>) messageElement.getChildren( 
    397                                 "storeSeq", rulesNamespace)) { 
    398                         String identifier = childElement.getAttributeValue("varSeq"); 
    399                         Object tmp = messageStorage.get(identifier); 
    400                         List<WindowsMessage> storedSequence; 
    401                         if (tmp == null || tmp instanceof WindowsMessage) { 
    402                                 storedSequence = new LinkedList<WindowsMessage>(); 
    403                                 storedSequence.add(currentMessage); 
    404                                 messageStorage.put(identifier, storedSequence); 
    405                         } else if (tmp instanceof List<?>) { 
    406                                 storedSequence = (List<WindowsMessage>) tmp; 
    407                                 storedSequence.add(currentMessage); 
    408                                 messageStorage.put(identifier, storedSequence); 
    409                         } 
    410                         resolveHwnd(currentMessage, childElement); 
    411                 } 
    412         } 
    413  
    414         /** 
    415          * <p> 
    416          * Resolves a parameter that contains a HWND of a message to the target 
    417          * string of the HWND and stores it. 
    418          * </p> 
    419          *  
    420          * @param currentMessage 
    421          *            message whose HWND is resolved 
    422          * @param childElement 
    423          *            child element of the store node that represents the resolve 
    424          */ 
    425         @SuppressWarnings("unchecked") 
    426         private void resolveHwnd(WindowsMessage currentMessage, Element childElement) { 
    427                 List<Element> resolveElements = childElement.getChildren("resolveHwnd", 
    428                                 rulesNamespace); 
    429                 for (Element resolveElement : resolveElements) { 
    430                         String param = resolveElement.getAttributeValue("param"); 
    431                         String storeParam = resolveElement.getAttributeValue("storeParam"); 
    432                         int paramHwnd = Integer 
    433                                         .parseInt(currentMessage.getParameter(param)); 
    434                         WindowTreeNode node = WindowTree.getInstance().find(paramHwnd); 
    435                         if (node != null) { 
    436                                 currentMessage.addParameter(storeParam, 
    437                                                 node.xmlRepresentation()); 
    438                         } 
    439                 } 
    440         } 
    441  
    442         // ///////////////////////////////////////////////////// 
    443         // Helper functions for generating the replay, i.e., 
    444         // parsing of genMsg und genMsgSeq-nodes 
    445         // ///////////////////////////////////////////////////// 
    446  
    447         /** 
    448          * <p> 
    449          * Handles genMsg-nodes and adds the replay to the {@link Event} that is 
    450          * generated. 
    451          * </p> 
    452          *  
    453          * @param genMsgElement 
    454          *            {@link Element} representing the genMsg-node 
    455          */ 
    456         @SuppressWarnings("unchecked") 
    457         private void generateReplayMessage(Element genMsgElement) { 
    458                 List<Element> genMsgChildren = genMsgElement.getChildren(); 
    459                 WindowsMessage generatedMessage = null; 
    460                 if (genMsgChildren.size() == 1) { // replay stored message without 
    461                                                                                         // change 
    462                         String obj = genMsgChildren.get(0).getAttributeValue("obj"); 
    463                         generatedMessage = getStoredMessageVariable(null, obj); 
    464                 } else { // generate message according to the rule 
    465                         for (Element genMsgChild : genMsgChildren) { 
    466                                 Element termElement = (Element) genMsgChild.getChildren() 
    467                                                 .get(0); 
    468                                 if (genMsgChild.getName().equals("type")) { 
    469                                         try { 
    470                                                 int msgType = Integer.parseInt(getTermValue(null, 
    471                                                                 termElement)); 
    472                                                 generatedMessage = new WindowsMessage(msgType); 
    473                                         } catch (NumberFormatException e) { 
    474                                                 throw new InvalidParameterException( 
    475                                                                 "Failure generating replay sequence for rule " 
    476                                                                                 + currentRuleName 
    477                                                                                 + ": Defined type is not an integer."); 
    478                                         } 
    479                                 } else if (genMsgChild.getName().equals("target")) { 
    480                                         String targetString = getTermValue(null, termElement); 
    481                                         generatedMessage.setXmlWindowDescription(targetString); 
    482                                 } else if (genMsgChild.getName().equals("LPARAM")) { 
    483                                         String paramValueStr = getTermValue(null, termElement); 
    484                                         long paramValue = 0; 
    485                                         Element loword = genMsgChild.getChild("LOWORD", 
    486                                                         rulesNamespace); 
    487                                         if (loword != null) { 
    488                                                 paramValue = loHiWord(genMsgChild); 
    489                                                 generatedMessage.setLPARAM(paramValue); 
    490                                         } else { 
    491                                                 try { 
    492                                                         paramValue = Integer.parseInt(paramValueStr); 
    493                                                         generatedMessage.setLPARAM(paramValue); 
    494                                                 } catch (NumberFormatException e) { 
    495                                                         generatedMessage 
    496                                                                         .setLPARAMasWindowDesc(paramValueStr); 
    497                                                 } 
    498                                         } 
    499                                 } else if (genMsgChild.getName().equals("WPARAM")) { 
    500                                         String paramValueStr = getTermValue(null, termElement); 
    501                                         long paramValue = 0; 
    502                                         Element loword = genMsgChild.getChild("LOWORD", 
    503                                                         rulesNamespace); 
    504                                         if (loword != null) { 
    505                                                 paramValue = loHiWord(genMsgChild); 
    506                                                 generatedMessage.setWPARAM(paramValue); 
    507                                         } else { 
    508                                                 try { 
    509                                                         paramValue = Integer.parseInt(paramValueStr); 
    510                                                         generatedMessage.setWPARAM(paramValue); 
    511                                                 } catch (NumberFormatException e) { 
    512                                                         generatedMessage 
    513                                                                         .setWPARAMasWindowDesc(paramValueStr); 
    514                                                 } 
    515                                         } 
    516                                 } 
    517                         } 
    518                 } 
    519                 if (generatedMessage != null) { 
    520                         int delay = Integer.parseInt(genMsgElement 
    521                                         .getAttributeValue("delay")); 
    522                         generatedMessage.setDelay(delay); 
    523                 } else { 
    524                         // TODO currentToken.invalidateReplay(); 
    525                 } 
    526                 currentToken.addReplayable(generatedMessage); 
    527         } 
    528  
    529         /** 
    530          * Handles genMsgSeq-nodes and adds the replay to the {@link Event} that is 
    531          * generated.</p> 
    532          *  
    533          * @param genMsgElement 
    534          *            {@link Element} representing the genMsgSeq-node. 
    535          */ 
    536         @SuppressWarnings("unchecked") 
    537         private void generateReplaySequence(Element genMsgElement) { 
    538                 List<Element> genMsgSeqChildren = genMsgElement.getChildren(); 
    539                 List<WindowsMessage> generatedMessageSeq = new LinkedList<WindowsMessage>(); 
    540                 if (genMsgSeqChildren.size() == 1) { 
    541                         String obj = genMsgSeqChildren.get(0).getAttributeValue("seqObj"); 
    542                         generatedMessageSeq = getStoredSeqVariable(obj); 
    543                 } else { 
    544                         boolean msgsGenerated = false; 
    545                         int constMsgType = 0; 
    546                         for (Element genMsgSeqChild : genMsgSeqChildren) { 
    547                                 Element termElement = (Element) genMsgSeqChild.getChildren() 
    548                                                 .get(0); 
    549                                 if (genMsgSeqChild.getName().equals("type")) { 
    550                                         // note: cannot easily be extracted because of mulitple 
    551                                         // return values 
    552                                         if (termElement.getName().equals("seqValue")) { 
    553                                                 String obj = termElement.getAttributeValue("seqObj"); 
    554                                                 List<WindowsMessage> seqVar = getStoredSeqVariable(obj); 
    555                                                 for (WindowsMessage msg : seqVar) { 
    556                                                         generatedMessageSeq.add(new WindowsMessage(msg 
    557                                                                         .getType())); 
    558                                                 } 
    559                                                 msgsGenerated = true; 
    560                                         } else { // constValue type 
    561                                                 constMsgType = Integer.parseInt(getTermValue(null, 
    562                                                                 termElement)); 
    563                                         } 
    564                                 } else if (genMsgSeqChild.getName().equals("target")) { 
    565                                         msgsGenerated = createSequenceTarget(generatedMessageSeq, 
    566                                                         msgsGenerated, constMsgType, termElement); 
    567                                 } else if (genMsgSeqChild.getName().equals("LPARAM")) { 
    568                                         msgsGenerated = createSequenceLParam(generatedMessageSeq, 
    569                                                         msgsGenerated, constMsgType, termElement); 
    570                                 } else if (genMsgSeqChild.getName().equals("WPARAM")) { 
    571                                         msgsGenerated = createSequenceWParam(generatedMessageSeq, 
    572                                                         msgsGenerated, constMsgType, termElement); 
    573                                 } 
    574                         } 
    575                 } 
    576                 currentToken.addReplayableSequence(generatedMessageSeq); 
    577         } 
    578  
    579         /** 
    580          * <p> 
    581          * Creates the targets for replay sequences generated with genMsgSeq-nodes. 
    582          * </p> 
    583          *  
    584          * @param generatedMessageSeq 
    585          *            list of the messages that is being generated 
    586          * @param msgsGenerated 
    587          *            boolean stating if the list of messages is already generated 
    588          *            or if the generation has to be handles by this method 
    589          * @param constMsgType 
    590          *            a constant message type that is used for message generation, 
    591          *            in case the list of message is generated by this method 
    592          * @param termElement 
    593          *            {@link Element} representing the term-node describing the 
    594          *            target 
    595          * @return true, if the list of message is generated after calling this 
    596          *         method; false otherwise 
    597          * @throws NoSuchElementException 
    598          *             thrown if the seqVar referred to in the termElement contains 
    599          *             a different number of messages than is contained in 
    600          *             messageSeq 
    601          */ 
    602         private boolean createSequenceTarget( 
    603                         List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated, 
    604                         int constMsgType, Element termElement) 
    605                         throws NoSuchElementException { 
    606                 Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
    607                 if (termElement.getName().equals("seqValue")) { 
    608                         String obj = termElement.getAttributeValue("seqObj"); 
    609                         List<WindowsMessage> seqVar = getStoredSeqVariable(obj); 
    610                         if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) { 
    611                                 throw new InvalidParameterException( 
    612                                                 "Failure generating replay sequence for rule " 
    613                                                                 + currentRuleName 
    614                                                                 + ": One or more of the sequence variables used to generate a sequence have different lenghts."); 
    615                         } 
    616                         for (WindowsMessage msg : seqVar) { 
    617                                 WindowsMessage currentSeqMsg = getCurrentSeqMsg( 
    618                                                 generatedMessageSeq, msgsGenerated, constMsgType, 
    619                                                 seqIterator); 
    620                                 String targetString = msg.getParameter(termElement 
    621                                                 .getAttributeValue("param")); 
    622                                 currentSeqMsg.setXmlWindowDescription(targetString); 
    623                         } 
    624                         msgsGenerated = true; 
    625                 } else { // const value 
    626                         throw new AssertionError("target must be a sequence variable!"); 
    627                         /* 
    628                          * If target would not be a variable, the message-elements could not 
    629                          * yet be created and the whole sequence might be broken. If this is 
    630                          * to be changed, createSequenceLParam and createSequenceWParam need 
    631                          * to be addepted, too. 
    632                          */ 
    633                 } 
    634                 return msgsGenerated; 
    635         } 
    636  
    637         /** 
    638          * <p> 
    639          * Creates the LPARAMs for replay sequences generated with genMsgSeq-nodes. 
    640          * </p> 
    641          *  
    642          * @param generatedMessageSeq 
    643          *            list of the messages that is being generated 
    644          * @param msgsGenerated 
    645          *            boolean stating if the list of messages is already generated 
    646          *            or if the generation has to be handles by this method 
    647          * @param constMsgType 
    648          *            a constant message type that is used for message generation, 
    649          *            in case the list of message is generated by this method 
    650          * @param termElement 
    651          *            {@link Element} representing the term-node describing the 
    652          *            LPARAM 
    653          * @return true, if the list of message is generated after calling this 
    654          *         method; false otherwise 
    655          * @throws NoSuchElementException 
    656          *             thrown if the seqVar referred to in the termElement contains 
    657          *             a different number of messages than is contained in 
    658          *             messageSeq 
    659          */ 
    660         private boolean createSequenceLParam( 
    661                         List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated, 
    662                         int constMsgType, Element termElement) 
    663                         throws NoSuchElementException { 
    664                 Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
    665                 if (termElement.getName().equals("seqValue")) { 
    666                         String obj = termElement.getAttributeValue("seqObj"); 
    667                         List<WindowsMessage> seqVar = getStoredSeqVariable(obj); 
    668                         if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) { 
    669                                 throw new InvalidParameterException( 
    670                                                 "Failure generating replay sequence for rule " 
    671                                                                 + currentRuleName 
    672                                                                 + ": One or more of the sequence variables used to generate a sequence have different lenghts."); 
    673                         } 
    674                         for (WindowsMessage msg : seqVar) { 
    675                                 WindowsMessage currentSeqMsg = getCurrentSeqMsg( 
    676                                                 generatedMessageSeq, msgsGenerated, constMsgType, 
    677                                                 seqIterator); 
    678                                 String paramValueStr = msg.getParameter(termElement 
    679                                                 .getAttributeValue("param")); 
    680                                 int paramValue = 0; 
    681                                 try { 
    682                                         paramValue = Integer.parseInt(paramValueStr); 
    683                                         currentSeqMsg.setLPARAM(paramValue); 
    684                                 } catch (NumberFormatException e) { 
    685                                         currentSeqMsg.setLPARAMasWindowDesc(paramValueStr); 
    686                                 } 
    687                         } 
    688                         if (seqIterator.hasNext()) { 
    689                                 // the first seq-var has a different number of elements than the 
    690                                 // current one 
    691                                 throw new NoSuchElementException(); 
    692                         } 
    693                         msgsGenerated = true; 
    694                 } else { // const value 
    695                         int paramValue = Integer.parseInt(getTermValue(null, termElement)); 
    696                         while (seqIterator.hasNext()) { 
    697                                 seqIterator.next().setLPARAM(paramValue); 
    698                         } 
    699                 } 
    700                 return msgsGenerated; 
    701         } 
    702  
    703         /** 
    704          * <p> 
    705          * Creates the WPARAMs for replay sequences generated with genMsgSeq-nodes. 
    706          * </p> 
    707          *  
    708          * @param generatedMessageSeq 
    709          *            list of the messages that is being generated 
    710          * @param msgsGenerated 
    711          *            boolean stating if the list of messages is already generated 
    712          *            or if the generation has to be handles by this method 
    713          * @param constMsgType 
    714          *            a constant message type that is used for message generation, 
    715          *            in case the list of message is generated by this method 
    716          * @param termElement 
    717          *            {@link Element} representing the term-node describing the 
    718          *            WPARAM 
    719          * @return true, if the list of message is generated after calling this 
    720          *         method; false otherwise 
    721          * @throws NoSuchElementException 
    722          *             thrown if the seqVar referred to in the termElement contains 
    723          *             a different number of messages than is contained in 
    724          *             messageSeq 
    725          */ 
    726         private boolean createSequenceWParam( 
    727                         List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated, 
    728                         int constMsgType, Element termElement) 
    729                         throws NoSuchElementException { 
    730                 Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
    731                 if (termElement.getName().equals("seqValue")) { 
    732                         String obj = termElement.getAttributeValue("seqObj"); 
    733                         List<WindowsMessage> seqVar = getStoredSeqVariable(obj); 
    734                         if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) { 
    735                                 throw new InvalidParameterException( 
    736                                                 "Failure generating replay sequence for rule " 
    737                                                                 + currentRuleName 
    738                                                                 + ": One or more of the sequence variables used to generate a sequence have different lenghts."); 
    739                         } 
    740                         for (WindowsMessage msg : seqVar) { 
    741                                 WindowsMessage currentSeqMsg = getCurrentSeqMsg( 
    742                                                 generatedMessageSeq, msgsGenerated, constMsgType, 
    743                                                 seqIterator); 
    744                                 String paramValueStr = msg.getParameter(termElement 
    745                                                 .getAttributeValue("param")); 
    746                                 int paramValue = 0; 
    747                                 try { 
    748                                         paramValue = Integer.parseInt(paramValueStr); 
    749                                         currentSeqMsg.setWPARAM(paramValue); 
    750                                 } catch (NumberFormatException e) { 
    751                                         currentSeqMsg.setWPARAMasWindowDesc(paramValueStr); 
    752                                 } 
    753                         } 
    754                         if (seqIterator.hasNext()) { 
    755                                 // the first seq-var has a different number of elements than the 
    756                                 // current one 
    757                                 throw new NoSuchElementException(); 
    758                         } 
    759                         msgsGenerated = true; 
    760                 } else { // const value 
    761                         int paramValue = Integer.parseInt(getTermValue(null, termElement)); 
    762                         while (seqIterator.hasNext()) { 
    763                                 seqIterator.next().setWPARAM(paramValue); 
    764                         } 
    765                 } 
    766                 return msgsGenerated; 
    767         } 
    768  
    769         /** 
    770          * <p> 
    771          * If a message sequence is already generated, i.e., msgsGenerated is true, 
    772          * the seqIterator is used to iterate through these messages and return the 
    773          * current one. If the message sequence is not yet generated, i.e., 
    774          * msgsGenerated is false, the message sequence is generated on the fly 
    775          * during each call of this message and the newly generated messages are 
    776          * returned. 
    777          * </p> 
    778          *  
    779          * @param generatedMessageSeq 
    780          *            message sequence 
    781          * @param msgsGenerated 
    782          *            indicates if generatedMessageSeq is already generated or has 
    783          *            to be generated on the fly by this method 
    784          * @param constMsgType 
    785          *            type of the message to be used for message generation 
    786          * @param seqIterator 
    787          *            iterates through an already generated message sequence; must 
    788          *            not be {@code null}, if msgsGenerated is true 
    789          * @return current message 
    790          */ 
    791         private WindowsMessage getCurrentSeqMsg( 
    792                         List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated, 
    793                         int constMsgType, Iterator<WindowsMessage> seqIterator) { 
    794                 WindowsMessage currentSeqMsg = null; 
    795                 if (msgsGenerated) { 
    796                         currentSeqMsg = seqIterator.next(); 
    797                 } else { 
    798                         currentSeqMsg = new WindowsMessage(constMsgType); 
    799                         generatedMessageSeq.add(currentSeqMsg); 
    800                 } 
    801                 return currentSeqMsg; 
    802         } 
    803  
    804         // //////////////////////////// 
    805         // General helper functions // 
    806         // //////////////////////////// 
    807  
    808         /** 
    809          * <p> 
    810          * Retrieves a message from the storage for, e.g., comparison or replay. 
    811          * "this" is used to refer to the current message. 
    812          * </p> 
    813          *  
    814          * @param currentMessage 
    815          *            current message during the parsing; passed to handle "this" 
    816          * @param obj 
    817          *            object identifier in the storage 
    818          * @return message retrieved from the storage 
    819          * @throws InvalidParameterException 
    820          *             thrown in case of invalid uses of "this" or if no message 
    821          *             with the identifier obj is found in the storage 
    822          */ 
    823         private WindowsMessage getStoredMessageVariable( 
    824                         WindowsMessage currentMessage, String obj) 
    825                         throws InvalidParameterException { 
    826                 WindowsMessage varMessage = null; 
    827                 if (obj.equals("this")) { 
    828                         if (currentMessage == null) { 
    829                                 throw new InvalidParameterException( 
    830                                                 "Failure obtaining term value for rule " 
    831                                                                 + currentRuleName 
    832                                                                 + ": \"this\" is not a valid name for generating runtime messages."); 
    833                         } 
    834                         varMessage = currentMessage; 
    835                 } else { 
    836                         Object tmp = messageStorage.get(obj); 
    837                         if (tmp instanceof WindowsMessage) { 
    838                                 varMessage = (WindowsMessage) tmp; 
    839                         } else { 
    840                                 throw new InvalidParameterException( 
    841                                                 "Failure obtaining term value for rule " 
    842                                                                 + currentRuleName + ": No message \"" + obj 
    843                                                                 + "\" stored."); 
    844                         } 
    845                 } 
    846                 return varMessage; 
    847         } 
    848  
    849         /** 
    850          * <p> 
    851          * Retrieves a stored message sequence from the storage. 
    852          * </p> 
    853          *  
    854          * @param obj 
    855          *            object identifier in the storage 
    856          * @return message sequence retrieved from the storage 
    857          * @throws InvalidParameterException 
    858          *             thrown if no message sequences with the identifier obj is 
    859          *             found in the storage 
    860          */ 
    861         @SuppressWarnings("unchecked") 
    862         private List<WindowsMessage> getStoredSeqVariable(String obj) 
    863                         throws InvalidParameterException { 
    864                 List<WindowsMessage> varMsgSeq = null; 
    865                 Object tmp = messageStorage.get(obj); 
    866                 if (tmp instanceof List<?>) { 
    867                         varMsgSeq = (List<WindowsMessage>) tmp; 
    868                 } else { 
    869                         throw new InvalidParameterException( 
    870                                         "Failure obtaining term value for rule " + currentRuleName 
    871                                                         + ": No sequence \"" + obj + "\" store."); 
    872                 } 
    873                 return varMsgSeq; 
    874         } 
    875  
    876         /** 
    877          * <p> 
    878          * Handles term-nodes and returns the value of the described term. 
    879          * </p> 
    880          *  
    881          * @param currentMessage 
    882          *            current message during the parsing; required to resolve 
    883          *            references to "this" in a term 
    884          * @param termElement 
    885          *            {@link Element} representing the term node 
    886          * @return value of the term or {@code null} of the term node could not be 
    887          *         evaluated 
    888          */ 
    889         private String getTermValue(WindowsMessage currentMessage, 
    890                         Element termElement) { 
    891                 String value = null; 
    892                 WindowsMessage varMessage = null; 
    893                 if (termElement.getName().equals("constValue")) { 
    894                         value = termElement.getAttributeValue("value"); 
    895                 } else if (termElement.getName().equals("paramValue")) { 
    896                         String objectName = termElement.getAttributeValue("obj"); 
    897                         varMessage = getStoredMessageVariable(currentMessage, objectName); 
    898                         if (varMessage != null) { 
    899                                 String param = termElement.getAttributeValue("param"); 
    900                                 value = varMessage.getParameter(param); 
    901                         } 
    902                 } else if (termElement.getName().equals("winInfoValue")) { 
    903                         String objectName = termElement.getAttributeValue("obj"); 
    904                         varMessage = getStoredMessageVariable(currentMessage, objectName); 
    905                         if (varMessage != null) { 
    906                                 String paramString = termElement.getAttributeValue("winParam"); 
    907                                 if (paramString.equals("class")) { 
    908                                         value = varMessage.getWindowClass(); 
    909                                 } else if (paramString.equals("resourceId")) { 
    910                                         value = "" + varMessage.getWindowResourceId(); 
    911                                 } else if (paramString.equals("hwnd")) { 
    912                                         value = "" + varMessage.getHwnd(); 
    913                                 } else if (paramString.equals("parentTarget")) { 
    914                                         String target = varMessage.getXmlWindowDescription(); 
    915                                         int index = target.lastIndexOf("<"); 
    916                                         if (index == 0) { 
    917                                                 Console.traceln("Trying to adress parent of top-level window! Replay probably invalid!"); 
    918                                         } 
    919                                         value = target.substring(0, index); 
    920                                 } else if (paramString.equals("parentClass")) { 
    921                                         value = varMessage.getParentClass(); 
    922                                 } 
    923                         } 
    924                 } else if (termElement.getName().equals("msgInfoValue")) { 
    925                         String objectName = termElement.getAttributeValue("obj"); 
    926                         varMessage = getStoredMessageVariable(currentMessage, objectName); 
    927                         if (varMessage != null) { 
    928                                 String paramString = termElement.getAttributeValue("msgParam"); 
    929                                 if (paramString.equals("type")) { 
    930                                         value = "" + varMessage.getType(); 
    931                                 } else if (paramString.equals("target")) { 
    932                                         value = varMessage.getXmlWindowDescription(); 
    933                                 } 
    934                         } 
    935                 } 
    936                 return value; 
    937         } 
    938  
    939         /** 
    940          * <p> 
    941          * Handles term-nodes contained by equalSeq nodes. 
    942          * </p> 
    943          *  
    944          * @param termElement 
    945          *            {@link Element} representing the term-node 
    946          * @return list of values of the term 
    947          */ 
    948         private List<String> getTermValueSeq(Element termElement) { 
    949                 List<String> values = new LinkedList<String>(); 
    950                 if (termElement.getName().equals("seqValue")) { 
    951                         String obj = termElement.getAttributeValue("seqObj"); 
    952                         String param = termElement.getAttributeValue("param"); 
    953                         List<WindowsMessage> seqVar = getStoredSeqVariable(obj); 
    954  
    955                         for (WindowsMessage msg : seqVar) { 
    956                                 // msg.getParameter returns null, if parameter is not found, 
    957                                 // therefore the List can contain null-values 
    958                                 values.add(msg.getParameter(param)); 
    959                         } 
    960                 } 
    961                 return values; 
    962         } 
    963  
    964         /** 
    965          * <p> 
    966          * Handles LOWORD and HIWORD child nodes of LPARAM and WPARAM nodes. The 
    967          * returned value is the LPARAM/WPARAM value based on the LOWORD and HIWORD. 
    968          * </p> 
    969          *  
    970          * @param param 
    971          *            {@link Element} representing the LPARAM/WPARAM node 
    972          * @return value of the LPARAM/WPARAM 
    973          */ 
    974         private long loHiWord(Element param) { 
    975                 Element loword = param.getChild("LOWORD", rulesNamespace); 
    976                 Element hiword = param.getChild("HIWORD", rulesNamespace); 
    977                 String lowordStr = getTermValue(null, (Element) loword.getChildren() 
    978                                 .get(0)); 
    979                 String hiwordStr = getTermValue(null, (Element) hiword.getChildren() 
    980                                 .get(0)); 
    981                 return MAKEPARAM(Short.parseShort(lowordStr), 
    982                                 Short.parseShort(hiwordStr)); 
    983         } 
    984  
    985         /** 
    986          * <p> 
    987          * Takes to short integers and combines them into the high and low order 
    988          * bits of an integer. 
    989          * </p> 
    990          *  
    991          * @param loword 
    992          *            low word 
    993          * @param hiword 
    994          *            high word 
    995          * @return combined integer 
    996          */ 
    997         private static int MAKEPARAM(short loword, short hiword) { 
    998                 return loword | ((int) hiword) << Short.SIZE; 
    999         } 
     44    /** 
     45     * <p> 
     46     * the list of all event generation rules available 
     47     * </p> 
     48     */ 
     49    private List<EventGenerationRule> generationRules; 
     50     
     51    /** 
     52     * <p> 
     53     * Name and path of the XML files containing the rules. 
     54     * </p> 
     55     */ 
     56    private String rulesFile; 
     57 
     58    /** 
     59     * <p> 
     60     * Iterator used for the current sequence. 
     61     * </p> 
     62     */ 
     63    private ListIterator<WindowsMessage> sequenceIterator; 
     64 
     65    /** 
     66     * <p> 
     67     * Token that is currently being generated. 
     68     * </p> 
     69     */ 
     70    private MFCEvent currentEvent; 
     71 
     72    /** 
     73     * <p> 
     74     * Event type of the current token. Stored as a member to be able to update it during the 
     75     * parsing of the idinfo tag. 
     76     * </p> 
     77     */ 
     78    private IEventType currentType; 
     79 
     80    /** 
     81     * <p> 
     82     *  
     83     * </p> 
     84     */ 
     85    private MFCGUIElement currentTarget; 
     86 
     87    /** 
     88     * <p> 
     89     * Reference to the ul:rules namespace. 
     90     * </p> 
     91     */ 
     92    private static Namespace rulesNamespace; 
     93 
     94    /** 
     95     * <p> 
     96     * The name of the rule that is currently being evaluated. 
     97     * </p> 
     98     */ 
     99    private String currentRuleName; 
     100 
     101    /** 
     102     * <p> 
     103     * Internal message storage. Used to implement the <code>{@literal <store>}</code> and 
     104     * <code>{@literal <storeSeq>}</code> tags. 
     105     * </p> 
     106     */ 
     107    private Map<String, Object> messageStorage; 
     108 
     109    /** 
     110     * <p> 
     111     * reference to the window tree created during parsing 
     112     * </p> 
     113     */ 
     114    private WindowTree windowTree; 
     115 
     116    /** 
     117     * <p> 
     118     * Creates a new EventGenerator. Sets "data/rules.xml" as default file for the rules. 
     119     * </p> 
     120     */ 
     121    public EventGenerator(WindowTree windowTree) { 
     122        rulesFile = "data/rules.xml"; 
     123        this.windowTree = windowTree; 
     124    } 
     125 
     126    /** 
     127     * <p> 
     128     * Tries to match the rules to the given sequence to generate an {@link WindowsEvent}. 
     129     * </p> 
     130     * <p> 
     131     * The rules are matched the order, in which they are defined in the XML file. Therefore, the 
     132     * order of the rules in the file defines priorities, when multiple rules could be matched to 
     133     * the same sequence. 
     134     * </p> 
     135     *  
     136     * @param sequence 
     137     *            sequence of message for which an event will be generated 
     138     * @return event that matches the messages; null, if no rule can be matched 
     139     */ 
     140    public Event generateEvent(List<WindowsMessage> sequence) { 
     141        if (generationRules == null) { 
     142            parseGenerationRules(); 
     143        } 
     144         
     145         
     146        /*System.out.println("generating event for "); 
     147        for (WindowsMessage msg : sequence) { 
     148            System.out.println("    " + msg + "  " + msg.getParameter("scrollBarHandle") + "  " + msg.getTargetXML()); 
     149        }*/ 
     150 
     151        boolean isMatch = false; 
     152 
     153        for (int ruleIndex = 0; ruleIndex < generationRules.size() && !isMatch; ruleIndex++) { 
     154            EventGenerationRule currentRule = generationRules.get(ruleIndex); 
     155            currentRuleName = currentRule.getName(); 
     156             
     157            //System.out.println("checking rule " + currentRuleName); 
     158             
     159            messageStorage = new HashMap<String, Object>(); 
     160            sequenceIterator = sequence.listIterator(); 
     161             
     162            isMatch = evaluateMessageConditions(currentRule); 
     163 
     164            if (isMatch) { 
     165                currentType = MFCEventTypeFactory.getInstance().getEventType 
     166                    (currentRuleName, resolveParameters(currentRule.getEventParameters())); 
     167                 
     168                currentEvent = new MFCEvent(currentType, currentTarget, windowTree.getGUIModel()); 
     169                 
     170                for (EventGenerationRule.ReplayMessageSpec replayMessageSpec : 
     171                      currentRule.getReplayMessageSpecifications()) 
     172                { 
     173                    if (replayMessageSpec.generateSingleMessage()) { 
     174                        try { 
     175                            generateReplayMessage(replayMessageSpec); 
     176                        } 
     177                        catch (InvalidParameterException e) { 
     178                            Console.printerrln(e.getMessage()); 
     179                            // TODO currentToken.invalidateReplay(); 
     180                        } 
     181                    } 
     182                    else { 
     183                        try { 
     184                            generateReplaySequence(replayMessageSpec); 
     185                            // TODO currentToken.invalidateReplay(); 
     186                        } 
     187                        catch (InvalidParameterException e) { 
     188                            Console.printerrln(e.getMessage()); 
     189                            // TODO currentToken.invalidateReplay(); 
     190                        } 
     191                    } 
     192                } 
     193 
     194                Console.traceln(currentEvent.getType().toString() + " matched"); 
     195            } 
     196            else { 
     197                currentEvent = null; 
     198            } 
     199        } 
     200        if (!isMatch) { 
     201            Console.traceln("no match found for sequence: " + sequence.toString()); 
     202        } 
     203         
     204         
     205        /*if (currentEvent != null && currentEvent.getReplayables() != null) { 
     206            System.out.println("replay messages are "); 
     207            for (de.ugoe.cs.quest.eventcore.IReplayable msg : currentEvent.getReplayables()) { 
     208                System.out.println("    " + msg + "  " + msg.getReplay()); 
     209            } 
     210        } 
     211 
     212        System.out.println();*/ 
     213 
     214 
     215        return currentEvent; 
     216    } 
     217 
     218    // //////////////////////////////////////////////////////////// 
     219    // Helper functions for matching of events, i.e., msg-nodes // 
     220    // //////////////////////////////////////////////////////////// 
     221 
     222    /** 
     223     * <p> 
     224     * TODO: comment 
     225     * </p> 
     226     * 
     227     * @param currentRule 
     228     */ 
     229    private boolean evaluateMessageConditions(EventGenerationRule currentRule) { 
     230        boolean isMatch = true; 
     231        List<EventGenerationRule.MessageCondition> messageConditions = 
     232            currentRule.getMessageConditions(); 
     233 
     234        int i = 0; 
     235        while (isMatch && i < messageConditions.size()) { 
     236            EventGenerationRule.MessageCondition messageCondition = messageConditions.get(i); 
     237            if (messageCondition.matchMultiple()) { 
     238                EventGenerationRule.MessageCondition nextMessageCondition = null; 
     239                if (i + 1 < messageConditions.size()) { 
     240                    nextMessageCondition = messageConditions.get(i + 1); 
     241                } 
     242                try { 
     243                    isMatch = matchMultipleConditions(messageCondition, nextMessageCondition); 
     244                } 
     245                catch (InvalidParameterException e) { 
     246                    Console.printerrln(e.getMessage()); 
     247                } 
     248            } 
     249            else { 
     250                try { 
     251                    isMatch = matchSingleMessage(messageCondition); 
     252                } 
     253                catch (InvalidParameterException e) { 
     254                    Console.printerrln(e.getMessage()); 
     255                } 
     256            } 
     257            i++; 
     258        } 
     259         
     260        return isMatch; 
     261    } 
     262 
     263    /** 
     264     * <p> 
     265     * Handles msg-nodes where multiple is not true, i.e., not a sequences. 
     266     * </p> 
     267     *  
     268     * @param messageElement 
     269     *            {@link Element} representing the msg-node 
     270     * @return true, if a match is found; false otherwise 
     271     */ 
     272    private boolean matchSingleMessage(EventGenerationRule.MessageCondition condition) { 
     273        boolean isMatch = false; 
     274        WindowsMessage currentMessage = null; 
     275 
     276        WindowsMessageType type = condition.getMessageType(); 
     277 
     278        while (!isMatch && sequenceIterator.hasNext()) { 
     279            /* 
     280             * traverses the messages from the current position forward till a message with the 
     281             * correct type is found 
     282             */ 
     283            currentMessage = sequenceIterator.next(); 
     284            if (type == currentMessage.getType()) { 
     285                // message with the correct type found 
     286                // eval child nodes for further matching/storing 
     287                isMatch = evaluateMessageCondition(currentMessage, condition); 
     288 
     289                // in case the message is a match, eval storage children 
     290                if (isMatch) { 
     291                    handleStorage(condition, currentMessage); 
     292                    currentTarget = currentMessage.getTarget(); 
     293                    // TODO currentToken.setTargetShort(currentMessage.getParentNames()); 
     294                } 
     295            } 
     296        } 
     297 
     298        return isMatch; 
     299    } 
     300 
     301    /** 
     302     * <p> 
     303     * Handles msg-nodes where multiple is true, i.e., sequences. Requires knowledge about the next 
     304     * msg-node to determine the end of the sequence. 
     305     * </p> 
     306     *  
     307     * @param messageElement 
     308     *            {@link Element} representing the msg-node 
     309     * @param nextMessageElement 
     310     *            {@link Element} representing the next msg-node; {@code null} if the current node 
     311     *            is the last one 
     312     * @return true, if a sequence is matched; false otherwise 
     313     */ 
     314    private boolean matchMultipleConditions(EventGenerationRule.MessageCondition condition, 
     315                                            EventGenerationRule.MessageCondition nextCondition) 
     316    { 
     317        boolean isMatch = false; 
     318        boolean isCurrentMatch = false; 
     319        boolean nextMatchFound = false; 
     320        WindowsMessage currentMessage = null; 
     321        WindowsMessage nextMessage = null; 
     322 
     323        WindowsMessageType type = condition.getMessageType(); 
     324 
     325        WindowsMessageType nextType = null; 
     326        if (nextCondition != null) { 
     327            nextType = nextCondition.getMessageType(); 
     328        } 
     329 
     330        while (!nextMatchFound && sequenceIterator.hasNext()) { 
     331            currentMessage = sequenceIterator.next(); 
     332            if (type == currentMessage.getType()) { 
     333                isCurrentMatch = evaluateMessageCondition(currentMessage, condition); 
     334                isMatch = isMatch || isCurrentMatch; 
     335 
     336                if (isCurrentMatch) { 
     337                    handleStorage(condition, currentMessage); 
     338                    currentTarget = currentMessage.getTarget(); 
     339                    // TODO currentToken.setTargetShort(currentMessage.getParentNames()); 
     340                } 
     341            } 
     342            if (nextCondition != null && isMatch) { 
     343                // peek next message to check if the sequence ends and the next 
     344                // match is found 
     345                if (!sequenceIterator.hasNext()) { 
     346                    return false; // sequence is over, but not all messages are 
     347                                  // found 
     348                } 
     349                nextMessage = sequenceIterator.next(); 
     350                sequenceIterator.previous(); 
     351 
     352                if (nextType == nextMessage.getType()) { 
     353                    nextMatchFound = evaluateMessageCondition(nextMessage, nextCondition); 
     354                } 
     355 
     356            } 
     357        } 
     358 
     359        return isMatch; 
     360    } 
     361 
     362    /** 
     363     * <p> 
     364     * Handles equals-nodes. 
     365     * </p> 
     366     *  
     367     * @param currentMessage 
     368     *            {@link Element} representing the msg-node the equals-node belongs to 
     369     * @param messageElement 
     370     *            {@link Element} representing the equals-node to be evaluated 
     371     * @return true, if constraint is fulfilled; false otherwise 
     372     */ 
     373    private boolean evaluateMessageCondition(WindowsMessage                       currentMessage, 
     374                                             EventGenerationRule.MessageCondition condition) 
     375    { 
     376        boolean isMatch = true; 
     377        for (int i = 0; isMatch && (i < condition.getAttributeConditions().size()); i++) 
     378        { 
     379            EventGenerationRule.AttributeCondition attrCond = 
     380                condition.getAttributeConditions().get(i); 
     381             
     382            // the size 2 of termElements is guaranteed by the XML schema 
     383            Object value1 = getTermValue(currentMessage, attrCond.getLeftHandSide(), Object.class); 
     384            Object value2 = getTermValue(currentMessage, attrCond.getRightHandSide(), Object.class); 
     385            if (value1 == null || value2 == null) { 
     386                isMatch = false; 
     387            } 
     388            else { 
     389                isMatch = isMatch && value1.equals(value2); 
     390            } 
     391        } 
     392//        for (Element childElement : (List<Element>) messageElement.getChildren("equalsSeq", 
     393//                                                                               rulesNamespace)) 
     394//        { 
     395//            List<Element> termElements = childElement.getChildren(); 
     396//            List<String> values1 = getTermValueSeq(termElements.get(0)); 
     397//            List<String> values2 = getTermValueSeq(termElements.get(0)); 
     398//            if (values1 == null || values2 == null) { 
     399//                isMatch = false; 
     400//            } 
     401//            else { 
     402//                isMatch = isMatch && values1.equals(values2); 
     403//            } 
     404//        } 
     405        return isMatch; 
     406    } 
     407 
     408    /** 
     409     * <p> 
     410     * Handles store-nodes and storeSeq-nodes. 
     411     * </p> 
     412     *  
     413     * @param messageElement 
     414     *            {@link Element} representing the msg-node that is currently being evaluated 
     415     * @param currentMessage 
     416     *            current message in the message sequence that is matched; this is the message that 
     417     *            is stored 
     418     */ 
     419    @SuppressWarnings("unchecked") 
     420    private void handleStorage(EventGenerationRule.MessageCondition messageCondition, 
     421                               WindowsMessage                       currentMessage) 
     422    { 
     423        for (Term valueToStore : messageCondition.getMessagesToStore()) 
     424        { 
     425            if (valueToStore.getMessageId() != null) { 
     426              ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(currentMessage); 
     427              messageStorage.put(valueToStore.getMessageId(), replayMessage); 
     428              resolveHwnd(replayMessage, valueToStore.getResolveHandles()); 
     429            } 
     430            else if (valueToStore.getSequenceId() != null) { 
     431                Object tmp = messageStorage.get(valueToStore.getSequenceId()); 
     432                ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(currentMessage); 
     433                List<ReplayWindowsMessage> storedSequence; 
     434                if (tmp == null || tmp instanceof ReplayWindowsMessage) { 
     435                    storedSequence = new LinkedList<ReplayWindowsMessage>(); 
     436                    storedSequence.add(replayMessage); 
     437                    messageStorage.put(valueToStore.getSequenceId(), storedSequence); 
     438                } 
     439                else if (tmp instanceof List<?>) { 
     440                    storedSequence = (List<ReplayWindowsMessage>) tmp; 
     441                    storedSequence.add(replayMessage); 
     442                    messageStorage.put(valueToStore.getSequenceId(), storedSequence); 
     443                } 
     444                resolveHwnd(replayMessage, valueToStore.getResolveHandles()); 
     445            } 
     446        } 
     447    } 
     448 
     449    /** 
     450     * <p> 
     451     * Resolves a parameter that contains a HWND of a message to the target string of the HWND and 
     452     * stores it. 
     453     * </p> 
     454     *  
     455     * @param currentMessage 
     456     *            message whose HWND is resolved 
     457     * @param list 
     458     *            child element of the store node that represents the resolve 
     459     */ 
     460    private void resolveHwnd(ReplayWindowsMessage currentMessage, List<Term> resolveHandles) { 
     461        if (resolveHandles != null) { 
     462            for (Term resolveElement : resolveHandles) { 
     463                String param = resolveElement.getMessageParameterName(); 
     464                String storeParam = resolveElement.getStoreParameterName(); 
     465                long paramHwnd = (Long) currentMessage.getParameter(param); 
     466                MFCGUIElement guiElement = windowTree.find(paramHwnd); 
     467                if (guiElement != null) { 
     468                    currentMessage.addParameter(storeParam, "" + guiElement.toXML()); 
     469                } 
     470            } 
     471        } 
     472    } 
     473 
     474    // ///////////////////////////////////////////////////// 
     475    // Helper functions for generating the replay, i.e., 
     476    // parsing of genMsg und genMsgSeq-nodes 
     477    // ///////////////////////////////////////////////////// 
     478 
     479    /** 
     480     * <p> 
     481     * Handles genMsg-nodes and adds the replay to the {@link Event} that is generated. 
     482     * </p> 
     483     *  
     484     * @param genMsgElement 
     485     *            {@link Element} representing the genMsg-node 
     486     */ 
     487    private void generateReplayMessage(EventGenerationRule.ReplayMessageSpec messageSpec) { 
     488        ReplayWindowsMessage generatedMessage = null; 
     489        if (messageSpec.getReplayObjectId() != null) { // replay stored message without change 
     490            generatedMessage = getStoredMessageVariable(null, messageSpec.getReplayObjectId()); 
     491        } 
     492        else { // generate message according to the rule 
     493            generatedMessage = new ReplayWindowsMessage 
     494                (getTermValue(messageSpec.getType(), WindowsMessageType.class)); 
     495            generatedMessage.setTargetXML(getTermValue(messageSpec.getTarget(), String.class)); 
     496 
     497            if ((messageSpec.getLparamHiWord() != null) || 
     498                    (messageSpec.getLparamLoWord() != null)) 
     499            { 
     500                generatedMessage.setLPARAM 
     501                    (loHiWord(messageSpec.getLparamLoWord(), messageSpec.getLparamHiWord())); 
     502            } 
     503            else if (messageSpec.getLparam() != null) { 
     504                try { 
     505                    generatedMessage.setLPARAM(getTermValue(messageSpec.getLparam(), Long.class)); 
     506                } 
     507                catch (IllegalArgumentException e) { 
     508                    generatedMessage.setLPARAMasWindowDesc 
     509                        (getTermValue(messageSpec.getLparam(), String.class)); 
     510                } 
     511            } 
     512 
     513            if ((messageSpec.getWparamHiWord() != null) || 
     514                    (messageSpec.getWparamLoWord() != null)) 
     515            { 
     516                generatedMessage.setWPARAM 
     517                    (loHiWord(messageSpec.getWparamLoWord(), messageSpec.getWparamHiWord())); 
     518            } 
     519            else if (messageSpec.getWparam() != null) { 
     520                try { 
     521                    generatedMessage.setWPARAM(getTermValue(messageSpec.getWparam(), Long.class)); 
     522                } 
     523                catch (IllegalArgumentException e) { 
     524                    generatedMessage.setWPARAMasWindowDesc 
     525                        (getTermValue(messageSpec.getWparam(), String.class)); 
     526                } 
     527            } 
     528             
     529             
     530        } 
     531 
     532        generatedMessage.setDelay(messageSpec.getDelay()); 
     533 
     534        currentEvent.addReplayable(generatedMessage); 
     535    } 
     536 
     537    /** 
     538     * Handles genMsgSeq-nodes and adds the replay to the {@link Event} that is generated.</p> 
     539     *  
     540     * @param genMsgElement 
     541     *            {@link Element} representing the genMsgSeq-node. 
     542     */ 
     543    private void generateReplaySequence(EventGenerationRule.ReplayMessageSpec messageSpec) 
     544    { 
     545        List<ReplayWindowsMessage> generatedMessageSeq = new LinkedList<ReplayWindowsMessage>(); 
     546        if (messageSpec.getReplayObjectId() != null) { // replay stored sequence without changes 
     547            generatedMessageSeq = getStoredSeqVariable(messageSpec.getReplayObjectId()); 
     548        } 
     549        else { 
     550            List<ReplayWindowsMessage> seqVar = 
     551                getStoredSeqVariable(messageSpec.getReplayObjectId()); 
     552             
     553            Term typeTerm = messageSpec.getType(); 
     554            if (typeTerm.getSequenceId() != null) { 
     555                seqVar = getStoredSeqVariable(typeTerm.getSequenceId()); 
     556                for (WindowsMessage msg : seqVar) { 
     557                    ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(msg.getType()); 
     558                    replayMessage.setDelay(messageSpec.getDelay()); 
     559                    generatedMessageSeq.add(replayMessage); 
     560                } 
     561            } 
     562            else { // constValue type 
     563                WindowsMessageType constMsgType = getTermValue(typeTerm, WindowsMessageType.class); 
     564                for (int i = 0; i < seqVar.size(); i++) { 
     565                    ReplayWindowsMessage replayMessage = new ReplayWindowsMessage(constMsgType); 
     566                    replayMessage.setDelay(messageSpec.getDelay()); 
     567                    generatedMessageSeq.add(replayMessage); 
     568                } 
     569            } 
     570 
     571            createSequenceTarget(generatedMessageSeq, messageSpec); 
     572            createSequenceLParam(generatedMessageSeq, messageSpec); 
     573            createSequenceWParam(generatedMessageSeq, messageSpec); 
     574        } 
     575         
     576        currentEvent.addReplayableSequence(generatedMessageSeq); 
     577    } 
     578 
     579    /** 
     580     * <p> 
     581     * Creates the targets for replay sequences generated with genMsgSeq-nodes. 
     582     * </p> 
     583     *  
     584     * @param generatedMessageSeq 
     585     *            list of the messages that is being generated 
     586     * @param msgsGenerated 
     587     *            boolean stating if the list of messages is already generated or if the generation 
     588     *            has to be handles by this method 
     589     * @param constMsgType 
     590     *            a constant message type that is used for message generation, in case the list of 
     591     *            message is generated by this method 
     592     * @param termElement 
     593     *            {@link Element} representing the term-node describing the target 
     594     * @return true, if the list of message is generated after calling this method; false otherwise 
     595     * @throws NoSuchElementException 
     596     *             thrown if the seqVar referred to in the termElement contains a different number 
     597     *             of messages than is contained in messageSeq 
     598     */ 
     599    private void createSequenceTarget(List<ReplayWindowsMessage>            generatedMessageSeq, 
     600                                      EventGenerationRule.ReplayMessageSpec messageSpec) 
     601        throws NoSuchElementException 
     602    { 
     603        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
     604        if (messageSpec.getTarget().getSequenceId() != null) { 
     605            List<ReplayWindowsMessage> seqVar = 
     606                getStoredSeqVariable(messageSpec.getTarget().getSequenceId()); 
     607 
     608            if (seqVar.size() != generatedMessageSeq.size()) { 
     609                throw new InvalidParameterException 
     610                    ("Failure generating replay sequence for rule " + currentRuleName + 
     611                     ": One or more of the sequence variables used to generate a sequence have " + 
     612                     "different lenghts."); 
     613            } 
     614             
     615            for (WindowsMessage msg : seqVar) { 
     616                seqIterator.next().setTarget(msg.getTarget()); 
     617            } 
     618        } 
     619        else { // const value 
     620            throw new AssertionError("target must be a sequence variable!"); 
     621            /* 
     622             * If target would not be a variable, the message-elements could not yet be created and 
     623             * the whole sequence might be broken. If this is to be changed, createSequenceLParam 
     624             * and createSequenceWParam need to be addepted, too. 
     625             */ 
     626        } 
     627    } 
     628 
     629    /** 
     630     * <p> 
     631     * Creates the LPARAMs for replay sequences generated with genMsgSeq-nodes. 
     632     * </p> 
     633     *  
     634     * @param generatedMessageSeq 
     635     *            list of the messages that is being generated 
     636     * @param msgsGenerated 
     637     *            boolean stating if the list of messages is already generated or if the generation 
     638     *            has to be handles by this method 
     639     * @param constMsgType 
     640     *            a constant message type that is used for message generation, in case the list of 
     641     *            message is generated by this method 
     642     * @param termElement 
     643     *            {@link Element} representing the term-node describing the LPARAM 
     644     * @return true, if the list of message is generated after calling this method; false otherwise 
     645     * @throws NoSuchElementException 
     646     *             thrown if the seqVar referred to in the termElement contains a different number 
     647     *             of messages than is contained in messageSeq 
     648     */ 
     649    private void createSequenceLParam(List<ReplayWindowsMessage>            generatedMessageSeq, 
     650                                      EventGenerationRule.ReplayMessageSpec messageSpec) 
     651        throws NoSuchElementException 
     652    { 
     653        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
     654        if (messageSpec.getLparam().getSequenceId() != null) { 
     655            List<ReplayWindowsMessage> seqVar = 
     656                getStoredSeqVariable(messageSpec.getLparam().getSequenceId()); 
     657             
     658            if (seqVar.size() != generatedMessageSeq.size()) { 
     659                throw new InvalidParameterException 
     660                    ("Failure generating replay sequence for rule " + currentRuleName + 
     661                     ": One or more of the sequence variables used to generate a sequence have " + 
     662                     "different lengths."); 
     663            } 
     664            for (WindowsMessage msg : seqVar) { 
     665                ReplayWindowsMessage currentSeqMsg = seqIterator.next(); 
     666                Object paramValue = 
     667                    msg.getParameter(messageSpec.getLparam().getSequenceParameterName()); 
     668                if (paramValue instanceof Long) { 
     669                    currentSeqMsg.setLPARAM((Long) paramValue); 
     670                } 
     671                else { 
     672                    currentSeqMsg.setLPARAMasWindowDesc((String) paramValue); 
     673                } 
     674            } 
     675        } 
     676        else { // const value 
     677            int paramValue = getTermValue(messageSpec.getLparam(), int.class); 
     678            while (seqIterator.hasNext()) { 
     679                seqIterator.next().setLPARAM(paramValue); 
     680            } 
     681        } 
     682 
     683    } 
     684 
     685    /** 
     686     * <p> 
     687     * Creates the WPARAMs for replay sequences generated with genMsgSeq-nodes. 
     688     * </p> 
     689     *  
     690     * @param generatedMessageSeq 
     691     *            list of the messages that is being generated 
     692     * @param msgsGenerated 
     693     *            boolean stating if the list of messages is already generated or if the generation 
     694     *            has to be handles by this method 
     695     * @param constMsgType 
     696     *            a constant message type that is used for message generation, in case the list of 
     697     *            message is generated by this method 
     698     * @param termElement 
     699     *            {@link Element} representing the term-node describing the WPARAM 
     700     * @return true, if the list of message is generated after calling this method; false otherwise 
     701     * @throws NoSuchElementException 
     702     *             thrown if the seqVar referred to in the termElement contains a different number 
     703     *             of messages than is contained in messageSeq 
     704     */ 
     705    private void createSequenceWParam(List<ReplayWindowsMessage>            generatedMessageSeq, 
     706                                      EventGenerationRule.ReplayMessageSpec messageSpec) 
     707        throws NoSuchElementException 
     708    { 
     709        Iterator<ReplayWindowsMessage> seqIterator = generatedMessageSeq.iterator(); 
     710        if (messageSpec.getWparam().getSequenceId() != null) { 
     711            List<ReplayWindowsMessage> seqVar = 
     712                getStoredSeqVariable(messageSpec.getWparam().getSequenceId()); 
     713             
     714            if (seqVar.size() != generatedMessageSeq.size()) { 
     715                throw new InvalidParameterException 
     716                    ("Failure generating replay sequence for rule " + currentRuleName + 
     717                     ": One or more of the sequence variables used to generate a sequence have " + 
     718                     "different lengths."); 
     719            } 
     720            for (WindowsMessage msg : seqVar) { 
     721                ReplayWindowsMessage currentSeqMsg = seqIterator.next(); 
     722                Object paramValue = 
     723                    msg.getParameter(messageSpec.getWparam().getSequenceParameterName()); 
     724                if (paramValue instanceof Long) { 
     725                    currentSeqMsg.setWPARAM((Long) paramValue); 
     726                } 
     727                else { 
     728                    currentSeqMsg.setWPARAMasWindowDesc((String) paramValue); 
     729                } 
     730            } 
     731        } 
     732        else { // const value 
     733            int paramValue = getTermValue(messageSpec.getWparam(), int.class); 
     734            while (seqIterator.hasNext()) { 
     735                seqIterator.next().setWPARAM(paramValue); 
     736            } 
     737        } 
     738    } 
     739 
     740    // //////////////////////////// 
     741    // General helper functions // 
     742    // //////////////////////////// 
     743 
     744    /** 
     745     * <p> 
     746     * TODO: comment 
     747     * </p> 
     748     * 
     749     * @param eventParameters 
     750     * @return 
     751     */ 
     752    private Map<String, String> resolveParameters(List<Term> eventParameters) { 
     753        Map<String, String> resultParameters = null; 
     754         
     755        if ((eventParameters != null) && (eventParameters.size() > 0)) { 
     756            resultParameters = new HashMap<String, String>(); 
     757             
     758            for (Term term : eventParameters) { 
     759                if ("seqValue".equals(term.getName())) { 
     760                    List<String> values = getTermValueAsList(term, String.class); 
     761                                         
     762                    resultParameters.put 
     763                        (term.getSequenceParameterName(), (String) values.get(values.size() - 1)); 
     764                } 
     765                else { 
     766                    resultParameters.put 
     767                        (term.getMessageParameterName(), getTermValue(term, String.class)); 
     768                } 
     769            } 
     770        } 
     771         
     772        return resultParameters; 
     773    } 
     774 
     775    /** 
     776     * <p> 
     777     * Retrieves a message from the storage for, e.g., comparison or replay. "this" is used to refer 
     778     * to the current message. 
     779     * </p> 
     780     *  
     781     * @param currentMessage 
     782     *            current message during the parsing; passed to handle "this" 
     783     * @param obj 
     784     *            object identifier in the storage 
     785     * @return message retrieved from the storage 
     786     * @throws InvalidParameterException 
     787     *             thrown in case of invalid uses of "this" or if no message with the identifier obj 
     788     *             is found in the storage 
     789     */ 
     790    private ReplayWindowsMessage getStoredMessageVariable(WindowsMessage currentMessage, String obj) 
     791        throws InvalidParameterException 
     792    { 
     793        ReplayWindowsMessage varMessage = null; 
     794        if (obj.equals("this")) { 
     795            if (currentMessage == null) { 
     796                throw new InvalidParameterException("Failure obtaining term value for rule " + 
     797                    currentRuleName + 
     798                    ": \"this\" is not a valid name for generating runtime messages."); 
     799            } 
     800            varMessage = new ReplayWindowsMessage(currentMessage); 
     801        } 
     802        else { 
     803            Object tmp = messageStorage.get(obj); 
     804            if (tmp instanceof ReplayWindowsMessage) { 
     805                varMessage = (ReplayWindowsMessage) tmp; 
     806            } 
     807            else { 
     808                throw new InvalidParameterException("Failure obtaining term value for rule " + 
     809                    currentRuleName + ": No message \"" + obj + "\" stored."); 
     810            } 
     811        } 
     812        return varMessage; 
     813    } 
     814 
     815    /** 
     816     * <p> 
     817     * Retrieves a stored message sequence from the storage. 
     818     * </p> 
     819     *  
     820     * @param obj 
     821     *            object identifier in the storage 
     822     * @return message sequence retrieved from the storage 
     823     * @throws IllegalArgumentException 
     824     *             thrown if no message sequences with the identifier obj is found in the storage 
     825     */ 
     826    @SuppressWarnings("unchecked") 
     827    private List<ReplayWindowsMessage> getStoredSeqVariable(String obj) 
     828        throws IllegalArgumentException 
     829    { 
     830        List<ReplayWindowsMessage> varMsgSeq = null; 
     831        Object tmp = messageStorage.get(obj); 
     832        if (tmp instanceof List<?>) { 
     833            varMsgSeq = (List<ReplayWindowsMessage>) tmp; 
     834        } 
     835        else { 
     836            throw new IllegalArgumentException("Failure obtaining term value for rule " + 
     837                                               currentRuleName + ": No sequence \"" + obj + 
     838                                               "\" store."); 
     839        } 
     840        return varMsgSeq; 
     841    } 
     842 
     843    /** 
     844     * <p> 
     845     * convenience method for {@link #getTermValue(WindowsMessage, Term)} with current message is 
     846     * null. 
     847     * </p> 
     848     *  
     849     * @param termElement 
     850     *            {@link Element} representing the term node 
     851     * @return value of the term or {@code null} of the term node could not be evaluated 
     852     */ 
     853    private <T> T getTermValue(EventGenerationRule.Term term, Class<T> expectedType) { 
     854        return getTermValue(null, term, expectedType); 
     855    } 
     856 
     857    /** 
     858     * <p> 
     859     * Handles term-nodes and returns the value of the described term. 
     860     * </p> 
     861     *  
     862     * @param currentMessage 
     863     *            current message during the parsing; required to resolve references to "this" in a 
     864     *            term 
     865     * @param termElement 
     866     *            {@link Element} representing the term node 
     867     * @return value of the term or {@code null} of the term node could not be evaluated 
     868     */ 
     869    private <T> T getTermValue(WindowsMessage           currentMessage, 
     870                               EventGenerationRule.Term term, 
     871                               Class<T>                 expectedType) 
     872    { 
     873        T value = null; 
     874         
     875        if ("constValue".equals(term.getName())) { 
     876            value = getValueAsType(term.getValue(), expectedType); 
     877        } 
     878        else if ("paramValue".equals(term.getName())) { 
     879            String objectName = term.getMessageId(); 
     880            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName); 
     881            if (varMessage != null) { 
     882                String param = term.getMessageParameterName(); 
     883                value = getValueAsType(varMessage.getParameter(param), expectedType); 
     884            } 
     885        } 
     886        else if ("winInfoValue".equals(term.getName())) { 
     887            String objectName = term.getMessageId(); 
     888            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName); 
     889            if (varMessage != null) { 
     890                String paramString = term.getWindowParameterName(); 
     891                if (paramString.equals("class")) { 
     892                    value = getValueAsType 
     893                        (((MFCGUIElement) varMessage.getTarget()).getType(), expectedType); 
     894                } 
     895                else if (paramString.equals("resourceId")) { 
     896                    value = getValueAsType 
     897                        (((MFCGUIElement) varMessage.getTarget()).getResourceId(), expectedType); 
     898                } 
     899                else if (paramString.equals("hwnd")) { 
     900                    value = getValueAsType 
     901                        (((MFCGUIElement) varMessage.getTarget()).getId(), expectedType); 
     902                } 
     903                else if (paramString.equals("parentTarget")) { 
     904                    String target = varMessage.getTargetXML(); 
     905                    int index = target.lastIndexOf("<"); 
     906                    if (index == 0) { 
     907                        Console.traceln("Trying to adress parent of top-level window! Replay " + 
     908                                        "probably invalid!"); 
     909                    } 
     910                    value =  getValueAsType(target.substring(0, index), expectedType); 
     911                } 
     912                else if (paramString.equals("parentClass")) { 
     913                    value =  getValueAsType 
     914                        (((MFCGUIElement) varMessage.getTarget()) 
     915                        .getParent().getSpecification().getType(), expectedType); 
     916                } 
     917            } 
     918        } 
     919        else if ("msgInfoValue".equals(term.getName())) { 
     920            String objectName = term.getMessageId(); 
     921            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName); 
     922            if (varMessage != null) { 
     923                String paramString = term.getMessageInfoName(); 
     924                if (paramString.equals("type")) { 
     925                    value = getValueAsType(varMessage.getType(), expectedType); 
     926                } 
     927                else if (paramString.equals("target")) { 
     928                    value = getValueAsType(varMessage.getTargetXML(), expectedType); 
     929                } 
     930            } 
     931        } 
     932        else if ("msgInfoValue".equals(term.getName())) { 
     933            String objectName = term.getMessageId(); 
     934            WindowsMessage varMessage = getStoredMessageVariable(currentMessage, objectName); 
     935            if (varMessage != null) { 
     936                String paramString = term.getMessageInfoName(); 
     937                if (paramString.equals("type")) { 
     938                    value = getValueAsType(varMessage.getType(), expectedType); 
     939                } 
     940                else if (paramString.equals("target")) { 
     941                    value = getValueAsType(varMessage.getTargetXML(), expectedType); 
     942                } 
     943            } 
     944        } 
     945         
     946        return value; 
     947    } 
     948     
     949    /** 
     950     * <p> 
     951     * convenience method for {@link #getTermValueAsList(WindowsMessage, Term)} with current 
     952     * message is null. 
     953     * </p> 
     954     *  
     955     * @param termElement 
     956     *            {@link Element} representing the term node 
     957     * @return value of the term or {@code null} of the term node could not be evaluated 
     958     */ 
     959    private <T> List<T> getTermValueAsList(EventGenerationRule.Term term, Class<T> expectedType) { 
     960        return getTermValueAsList(null, term, expectedType); 
     961    } 
     962 
     963    /** 
     964     * <p> 
     965     * Handles term-nodes and returns the value of the described term. 
     966     * </p> 
     967     *  
     968     * @param currentMessage 
     969     *            current message during the parsing; required to resolve references to "this" in a 
     970     *            term 
     971     * @param termElement 
     972     *            {@link Element} representing the term node 
     973     * @return value of the term or {@code null} of the term node could not be evaluated 
     974     */ 
     975    private <T> List<T> getTermValueAsList(WindowsMessage           currentMessage, 
     976                                           EventGenerationRule.Term term, 
     977                                           Class<T>                 expectedElementType) 
     978    { 
     979        List<T> values = new ArrayList<T>(); 
     980        if ("seqValue".equals(term.getName())) { 
     981            List<ReplayWindowsMessage> seqVar = getStoredSeqVariable(term.getSequenceId()); 
     982            Object value; 
     983             
     984            for (ReplayWindowsMessage msg : seqVar) { 
     985                // msg.getParameter returns null, if parameter is not found, 
     986                // therefore the List can contain null-values 
     987                value = msg.getParameter(term.getSequenceParameterName()); 
     988                values.add(getValueAsType(value, expectedElementType)); 
     989            } 
     990        } 
     991        else { 
     992            values.add(getTermValue(currentMessage, term, expectedElementType)); 
     993        } 
     994         
     995        return values; 
     996    } 
     997     
     998    /** 
     999     * <p> 
     1000     * TODO: comment 
     1001     * </p> 
     1002     * 
     1003     * @param value 
     1004     * @param expectedType 
     1005     * @return 
     1006     */ 
     1007    @SuppressWarnings("unchecked") 
     1008    private <T> T getValueAsType(Object value, Class<T> expectedType) { 
     1009        if (expectedType.isInstance(value)) { 
     1010            return (T) value; 
     1011        } 
     1012        else if (value instanceof String) { 
     1013            try { 
     1014                if (WindowsMessageType.class.equals(expectedType)) { 
     1015                    return (T) WindowsMessageType.parseMessageType((String) value); 
     1016                } 
     1017                else if (Short.class.equals(expectedType)) { 
     1018                    return (T) (Short) Short.parseShort((String) value); 
     1019                } 
     1020            } 
     1021            catch (Exception e) { 
     1022                // in this case, the value can not be transformed to the expected value. So ignore 
     1023                // the exception and fall through to the exception thrown anyway 
     1024            } 
     1025        } 
     1026        else if (value instanceof Long) { 
     1027            try { 
     1028                if (Short.class.equals(expectedType)) { 
     1029                    return (T) (Short) ((Long) value).shortValue(); 
     1030                } 
     1031                else if (String.class.equals(expectedType)) { 
     1032                    return (T) ((Long) value).toString(); 
     1033                } 
     1034            } 
     1035            catch (Exception e) { 
     1036                // in this case, the value can not be transformed to the expected value. So ignore 
     1037                // the exception and fall through to the exception thrown anyway 
     1038            } 
     1039        } 
     1040         
     1041        throw new IllegalArgumentException("the term value is not of the expected type " + 
     1042                                           expectedType + " but a " + 
     1043                                           (value != null ? value.getClass() : "null")); 
     1044    } 
     1045 
     1046    /** 
     1047     * <p> 
     1048     * Handles LOWORD and HIWORD child nodes of LPARAM and WPARAM nodes. The returned value is the 
     1049     * LPARAM/WPARAM value based on the LOWORD and HIWORD. 
     1050     * </p> 
     1051     *  
     1052     * @param param 
     1053     *            {@link Element} representing the LPARAM/WPARAM node 
     1054     * @return value of the LPARAM/WPARAM 
     1055     */ 
     1056    private long loHiWord(EventGenerationRule.Term lword, EventGenerationRule.Term hword) { 
     1057        return MAKEPARAM(getTermValue(lword, Short.class), getTermValue(hword, Short.class)); 
     1058    } 
     1059 
     1060    /** 
     1061     * <p> 
     1062     * Takes to short integers and combines them into the high and low order bits of an integer. 
     1063     * </p> 
     1064     *  
     1065     * @param loword 
     1066     *            low word 
     1067     * @param hiword 
     1068     *            high word 
     1069     * @return combined integer 
     1070     */ 
     1071    private static int MAKEPARAM(short loword, short hiword) { 
     1072        return loword | ((int) hiword) << Short.SIZE; 
     1073    } 
     1074 
     1075    /** 
     1076     * <p> 
     1077     * TODO: comment 
     1078     * </p> 
     1079     * 
     1080     */ 
     1081    @SuppressWarnings("unchecked") 
     1082    private void parseGenerationRules() { 
     1083        SAXBuilder builder = new SAXBuilder(); 
     1084        Document doc = null; 
     1085 
     1086        try { 
     1087            doc = builder.build(rulesFile); 
     1088            rulesNamespace = Namespace.getNamespace("ul:rules"); 
     1089        } 
     1090        catch (JDOMException e) { 
     1091            Console.printerrln("Invalid rules file."); 
     1092            e.printStackTrace(); 
     1093        } 
     1094        catch (IOException e) { 
     1095            Console.printerrln("Invalid rules file."); 
     1096            e.printStackTrace(); 
     1097        } 
     1098 
     1099        Element rulesRoot = doc.getRootElement(); 
     1100         
     1101        List<Element> ruleElements = rulesRoot.getChildren("rule", rulesNamespace); 
     1102 
     1103        generationRules = new ArrayList<EventGenerationRule>(); 
     1104 
     1105        for (Element ruleElement : ruleElements) { 
     1106            generationRules.add(new EventGenerationRule(ruleElement, rulesNamespace)); 
     1107        } 
     1108    } 
    10001109 
    10011110} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/HandlerCreate.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
    3 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
     4import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    45 
    56/** 
    67 * <p> 
    7  * Message handler for {@code WM_CREATE} messages. The handler maintains the 
    8  * {@link WindowTree}. 
     8 * Message handler for {@code WM_CREATE} messages. The handler maintains the {@link WindowTree}. 
    99 * </p> 
    1010 *  
     
    1414public class HandlerCreate extends MessageHandler { 
    1515 
    16         /** 
    17          * <p> 
    18          * Constructor. Creates a new HandlerCreate. 
    19          * </p> 
    20          */ 
    21         public HandlerCreate() { 
    22                 super(); 
    23         } 
     16    /** 
     17     * <p> 
     18     * Constructor. Creates a new HandlerCreate. 
     19     * </p> 
     20     *  
     21     * @param windowTree the tree of GUI element specifications to be created and adapted during 
     22     *                   parsing 
     23     */ 
     24    public HandlerCreate(WindowTree windowTree) { 
     25        super(windowTree); 
     26    } 
    2427 
    25         /** 
    26         * <p> 
    27         * Name of the created window. 
    28         * </p> 
    29         */ 
    30         private String windowName; 
     28    /** 
     29    * <p> 
     30    * Name of the created window. 
     31    * </p> 
     32    */ 
     33    private String windowName; 
    3134 
    32         /** 
    33         * <p> 
    34         * HWND of the created window. 
    35         * </p> 
    36         */ 
    37         private int hwnd; 
     35    /** 
     36    * <p> 
     37    * HWND of the created window. 
     38    * </p> 
     39    */ 
     40    private long hwnd; 
    3841 
    39         /** 
    40         * <p> 
    41         * HWND of the created window's parent. 
    42         * </p> 
    43         */ 
    44         private int parentHwnd; 
     42    /** 
     43    * <p> 
     44    * HWND of the created window's parent. 
     45    * </p> 
     46    */ 
     47    private long parentHwnd; 
    4548 
    46         /** 
    47         * <p> 
    48         * Resource Id of the created window. 
    49         * </p> 
    50         */ 
    51         private int resourceId; 
     49    /** 
     50    * <p> 
     51    * Resource Id of the created window. 
     52    * </p> 
     53    */ 
     54    private int resourceId; 
    5255 
    53         /** 
    54         * <p> 
    55         * Window class of the created window. 
    56         * </p> 
    57         */ 
    58         private String className; 
     56    /** 
     57    * <p> 
     58    * Window class of the created window. 
     59    * </p> 
     60    */ 
     61    private String className; 
    5962 
    60         /** 
    61         * <p> 
    62         * Modality of the created window. 
    63         * </p> 
    64         */ 
    65         private boolean isModal; 
     63    /** 
     64    * <p> 
     65    * Modality of the created window. 
     66    * </p> 
     67    */ 
     68    private boolean isModal; 
    6669 
    67         /* 
    68          * (non-Javadoc) 
    69          *  
    70          * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
    71          */ 
    72         @Override 
    73         public void onEndElement() { 
    74                 if (hwnd != 0) { 
    75                         WindowTree.getInstance().add(parentHwnd, hwnd, windowName, 
    76                                         resourceId, className, isModal); 
    77                 } 
    78         } 
     70    /* 
     71     * (non-Javadoc) 
     72     *  
     73     * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
     74     */ 
     75    @Override 
     76    public void onEndElement() { 
     77        if (hwnd != 0) { 
     78            super.getWindowTree().add(parentHwnd, hwnd, windowName, resourceId, className, isModal); 
     79        } 
     80    } 
    7981 
    80         /* 
    81          * (non-Javadoc) 
    82          *  
    83          * @see 
    84          * de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String 
    85          * , java.lang.String) 
    86          */ 
    87         @Override 
    88         public void onParameter(String name, String value) { 
    89                 if (name.equals("window.hwnd")) { 
    90                         hwnd = Integer.parseInt(value); 
    91                 } else if (name.equals("window.name")) { 
    92                         windowName = value; 
    93                 } else if (name.equals("window.parent.hwnd")) { 
    94                         parentHwnd = Integer.parseInt(value); 
    95                 } else if (name.equals("window.resourceId")) { 
    96                         resourceId = Integer.parseInt(value); 
    97                 } else if (name.equals("window.class")) { 
    98                         if (value.startsWith("Afx:")) { 
    99                                 className = "Afx:"; 
    100                         } else { 
    101                                 className = value; 
    102                         } 
    103                 } else if (name.equals("window.ismodal")) { 
    104                         if (value.equals("true") || value.equals("1")) { 
    105                                 isModal = true; 
    106                         } 
    107                 } 
    108         } 
     82    /* 
     83     * (non-Javadoc) 
     84     *  
     85     * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String , 
     86     * java.lang.String) 
     87     */ 
     88    @Override 
     89    public void onParameter(String name, String value) { 
     90        if (name.equals("window.hwnd")) { 
     91            hwnd = Long.parseLong(value); 
     92        } 
     93        else if (name.equals("window.name")) { 
     94            windowName = value; 
     95        } 
     96        else if (name.equals("window.parent.hwnd")) { 
     97            parentHwnd = Long.parseLong(value); 
     98        } 
     99        else if (name.equals("window.resourceId")) { 
     100            resourceId = Integer.parseInt(value); 
     101        } 
     102        else if (name.equals("window.class")) { 
     103            if (value.startsWith("Afx:")) { 
     104                className = "Afx:"; 
     105            } 
     106            else { 
     107                className = value; 
     108            } 
     109        } 
     110        else if (name.equals("window.ismodal")) { 
     111            if (value.equals("true") || value.equals("1")) { 
     112                isModal = true; 
     113            } 
     114        } 
     115    } 
    109116 
    110         /* 
    111         * (non-Javadoc) 
    112         *  
    113         * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
    114         */ 
    115         @Override 
    116         public void onStartElement() { 
    117                 windowName = ""; 
    118                 hwnd = 0; 
    119                 parentHwnd = 0; 
    120                 resourceId = 0; 
    121                 className = ""; 
    122                 isModal = false; 
    123         } 
     117    /* 
     118    * (non-Javadoc) 
     119    *  
     120    * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
     121    */ 
     122    @Override 
     123    public void onStartElement() { 
     124        windowName = ""; 
     125        hwnd = 0; 
     126        parentHwnd = 0; 
     127        resourceId = 0; 
     128        className = ""; 
     129        isModal = false; 
     130    } 
    124131 
    125132} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/HandlerDestroy.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
    3 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
     4import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    45 
    56/** 
    67 * <p> 
    7  * Handler for {@code WM_DESTROY} message. The handler maintains the 
    8  * {@link WindowTree}. 
     8 * Handler for {@code WM_DESTROY} message. The handler maintains the {@link WindowTree}. 
    99 * </p> 
    1010 *  
     
    1414public class HandlerDestroy extends MessageHandler { 
    1515 
    16         /** 
    17          * <p> 
    18          * Constructor. Creates a new HandlerDestroy. 
    19          * </p> 
    20          */ 
    21         public HandlerDestroy() { 
    22                 super(); 
    23         } 
     16    /** 
     17     * <p> 
     18     * Constructor. Creates a new HandlerDestroy. 
     19     * </p> 
     20     *  
     21     * @param windowTree 
     22     *            the tree of GUI element specifications to be created and adapted during parsing 
     23     */ 
     24    public HandlerDestroy(WindowTree windowTree) { 
     25        super(windowTree); 
     26    } 
    2427 
    25         /** 
    26         * <p> 
    27         * HWND of the window that is destroyed. 
    28         * </p> 
    29         */ 
    30         private int hwnd; 
     28    /** 
     29    * <p> 
     30    * HWND of the window that is destroyed. 
     31    * </p> 
     32    */ 
     33    private long hwnd; 
    3134 
    32         /* 
    33         * (non-Javadoc) 
    34         *  
    35         * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
    36         */ 
    37         @Override 
    38         public void onEndElement() { 
    39                 if (hwnd != 0) { 
    40                         WindowTree.getInstance().remove(hwnd); 
    41                 } 
    42         } 
     35    /* 
     36    * (non-Javadoc) 
     37    *  
     38    * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
     39    */ 
     40    @Override 
     41    public void onEndElement() { 
     42        if (hwnd != 0) { 
     43            super.getWindowTree().remove(hwnd); 
     44        } 
     45    } 
    4346 
    44         /* 
    45          * (non-Javadoc) 
    46          *  
    47          * @see 
    48          * de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String 
    49          * , java.lang.String) 
    50          */ 
    51         @Override 
    52         public void onParameter(String name, String value) { 
    53                 if (name.equals("window.hwnd")) { 
    54                         hwnd = Integer.parseInt(value); 
    55                 } 
    56         } 
     47    /* 
     48     * (non-Javadoc) 
     49     *  
     50     * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String , 
     51     * java.lang.String) 
     52     */ 
     53    @Override 
     54    public void onParameter(String name, String value) { 
     55        if (name.equals("window.hwnd")) { 
     56            hwnd = Long.parseLong(value); 
     57        } 
     58    } 
    5759 
    58         /* 
    59         * (non-Javadoc) 
    60         *  
    61         * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
    62         */ 
    63         @Override 
    64         public void onStartElement() { 
    65                 hwnd = 0; 
    66         } 
     60    /* 
     61    * (non-Javadoc) 
     62    *  
     63    * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
     64    */ 
     65    @Override 
     66    public void onStartElement() { 
     67        hwnd = 0; 
     68    } 
    6769 
    6870} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/HandlerSetText.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
    3 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
    4 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTreeNode; 
     4import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    55 
    66/** 
     
    1414public class HandlerSetText extends MessageHandler { 
    1515 
    16         /** 
    17          * <p> 
    18          * Constructor. Creates a new HanderSetText. 
    19          * </p> 
    20          */ 
    21         public HandlerSetText() { 
    22                 super(); 
    23         } 
     16    /** 
     17     * <p> 
     18     * Constructor. Creates a new HanderSetText. 
     19     * </p> 
     20     *  
     21     * @param windowTree 
     22     *            the tree of GUI element specifications to be created and adapted during parsing 
     23     */ 
     24    public HandlerSetText(WindowTree windowTree) { 
     25        super(windowTree); 
     26    } 
    2427 
    25         /** 
    26         * <p> 
    27         * New name of the window. 
    28         * </p> 
    29         */ 
    30         private String windowName; 
     28    /** 
     29    * <p> 
     30    * New name of the window. 
     31    * </p> 
     32    */ 
     33    private String windowName; 
    3134 
    32         /** 
    33         * <p> 
    34         * HWND of the window. 
    35         * </p> 
    36         */ 
    37         private int hwnd; 
     35    /** 
     36    * <p> 
     37    * HWND of the window. 
     38    * </p> 
     39    */ 
     40    private long hwnd; 
    3841 
    39         /* 
    40          * (non-Javadoc) 
    41          *  
    42          * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
    43          */ 
    44         @Override 
    45         public void onEndElement() { 
    46                 if (hwnd != 0) { 
    47                         WindowTreeNode node = WindowTree.getInstance().find(hwnd); 
    48                         node.setName(windowName); 
    49                 } 
    50         } 
     42    /* 
     43     * (non-Javadoc) 
     44     *  
     45     * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onEndElement() 
     46     */ 
     47    @Override 
     48    public void onEndElement() { 
     49        if (hwnd != 0) { 
     50            super.getWindowTree().setName(hwnd, windowName); 
     51        } 
     52    } 
    5153 
    52         /* 
    53         * (non-Javadoc) 
    54         *  
    55          * @see 
    56          * de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String 
    57          * , java.lang.String) 
    58          */ 
    59         @Override 
    60         public void onParameter(String name, String value) { 
    61                 if (name.equals("window.hwnd")) { 
    62                         hwnd = Integer.parseInt(value); 
    63                 } else if (name.equals("window.newText")) { 
    64                         windowName = value; 
    65                 } 
    66         } 
     54    /* 
     55    * (non-Javadoc) 
     56    *  
     57     * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onParameter(java.lang.String , 
     58     * java.lang.String) 
     59     */ 
     60    @Override 
     61    public void onParameter(String name, String value) { 
     62        if (name.equals("window.hwnd")) { 
     63            hwnd = Long.parseLong(value); 
     64        } 
     65        else if (name.equals("window.newText")) { 
     66            windowName = value; 
     67        } 
     68    } 
    6769 
    68         /* 
    69         * (non-Javadoc) 
    70         *  
    71         * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
    72         */ 
    73         @Override 
    74         public void onStartElement() { 
    75                 windowName = ""; 
    76                 hwnd = 0; 
    77         } 
     70    /* 
     71    * (non-Javadoc) 
     72    *  
     73    * @see de.ugoe.cs.quest.plugin.mfc.MessageHandler#onStartElement() 
     74    */ 
     75    @Override 
     76    public void onStartElement() { 
     77        windowName = ""; 
     78        hwnd = 0; 
     79    } 
    7880} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MFCLogParser.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
     
    89import java.security.InvalidParameterException; 
    910import java.util.Collection; 
     11import java.util.HashMap; 
    1012import java.util.LinkedList; 
    1113import java.util.List; 
     14import java.util.Map; 
    1215import java.util.SortedMap; 
    1316import java.util.TreeMap; 
     
    2427 
    2528import de.ugoe.cs.quest.eventcore.Event; 
    26 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
     29import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 
    2730import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage; 
     31import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; 
     32import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 
     33import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    2834import de.ugoe.cs.util.StringTools; 
    2935import de.ugoe.cs.util.console.Console; 
     
    3137/** 
    3238 * <p> 
    33  * This class provides functionality to parse XML log files generated by the 
    34  * MFCUsageMonitor of EventBench. The result of parsing a file is a collection 
    35  * of event sequences. It uses the {@link SequenceSplitter} and the 
    36  * {@link EventGenerator} as well as custom defined {@link MessageHandler} for 
    37  * the parsing. 
     39 * This class provides functionality to parse XML log files generated by the MFCUsageMonitor of 
     40 * EventBench. The result of parsing a file is a collection of event sequences. It uses the 
     41 * {@link SequenceSplitter} and the {@link EventGenerator} as well as custom defined 
     42 * {@link MessageHandler} for the parsing. 
    3843 * </p> 
    3944 *  
     
    4348public class MFCLogParser extends DefaultHandler { 
    4449 
    45         /** 
    46          * <p> 
    47          * If a custom message handler is used, this field contains its handle. 
    48          * Otherwise this field is {@code null}. 
    49          * </p> 
    50          */ 
    51         private MessageHandler currentHandler; 
    52  
    53         /** 
    54          * <p> 
    55          * Handle to the message that is currently parsed. 
    56          * </p> 
    57          */ 
    58         private WindowsMessage currentMessage; 
    59  
    60         /** 
    61          * <p> 
    62          * {@link SequenceSplitter} instance used by the {@link MFCLogParser}. 
    63          * </p> 
    64          */ 
    65         private SequenceSplitter sequenceSplitter; 
    66  
    67         /** 
    68          * <p> 
    69          * Collection of event sequences that is contained in the log file, which is 
    70          * parsed. 
    71          * </p> 
    72          */ 
    73         private Collection<List<Event>> sequences; 
    74  
    75         /** 
    76          * <p> 
    77          * Debugging variable that allows the analysis which message type occurs how 
    78          * often in the log file. Can be used to enhance the message filter. 
    79          * </p> 
    80          */ 
    81         private SortedMap<Integer, Integer> typeCounter; 
    82  
    83         /** 
    84          * <p> 
    85          * Debugging variable that enables the counting of the occurrences of each 
    86          * message. Used in combination with {@link #typeCounter}. 
    87          * </p> 
    88          */ 
    89         private boolean countMessageOccurences; 
    90  
    91         /** 
    92          * <p> 
    93          * Constructor. Creates a new LogParser that does not count message 
    94          * occurrences. 
    95          * </p> 
    96          */ 
    97         public MFCLogParser() { 
    98                 this(false); 
    99         } 
    100  
    101         /** 
    102          * <p> 
    103          * Constructor. Creates a new LogParser. 
    104          * </p> 
    105          *  
    106          * @param countMessageOccurences 
    107          *            if true, the occurrences of each message type in the log is 
    108          *            counted. 
    109          */ 
    110         public MFCLogParser(boolean countMessageOccurences) { 
    111                 sequenceSplitter = new SequenceSplitter(); 
    112                 sequences = new LinkedList<List<Event>>(); 
    113                 currentHandler = null; 
    114                 this.countMessageOccurences = countMessageOccurences; 
    115                 if (countMessageOccurences) { 
    116                         typeCounter = new TreeMap<Integer, Integer>(); 
    117                 } 
    118  
    119         } 
    120  
    121         /** 
    122          * <p> 
    123          * Returns the collection of event sequences that is obtained from parsing 
    124          * log files. 
    125          * </p> 
    126          *  
    127          * @return collection of event sequences 
    128          */ 
    129         public Collection<List<Event>> getSequences() { 
    130                 return sequences; 
    131         } 
    132  
    133         /* 
    134          * (non-Javadoc) 
    135          *  
    136          * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, 
    137          * java.lang.String, java.lang.String, org.xml.sax.Attributes) 
    138          */ 
    139         @Override 
    140         public void startElement(String uri, String localName, String qName, 
    141                         Attributes atts) throws SAXException { 
    142                 if (qName.equals("session")) { 
    143                         Console.traceln("start of session"); 
    144                         sequenceSplitter = new SequenceSplitter(); 
    145                 } else if (qName.equals("msg")) { 
    146                         String msgType = atts.getValue("type"); 
    147                         int msgInt = -1; 
    148                         try { 
    149                                 msgInt = Integer.parseInt(msgType); 
    150  
    151                                 if (countMessageOccurences) { 
    152                                         Integer currentCount = typeCounter.get(msgInt); 
    153                                         if (currentCount == null) { 
    154                                                 typeCounter.put(msgInt, 1); 
    155                                         } else { 
    156                                                 typeCounter.put(msgInt, currentCount + 1); 
    157                                         } 
    158                                 } 
    159  
    160                                 if (msgInt == MessageDefs.WM_CREATE) { 
    161                                         currentHandler = new HandlerCreate(); 
    162                                         currentHandler.onStartElement(); 
    163                                 } else if (msgInt == MessageDefs.WM_DESTROY) { 
    164                                         currentHandler = new HandlerDestroy(); 
    165                                         currentHandler.onStartElement(); 
    166                                 } else if (msgInt == MessageDefs.WM_SETTEXT) { 
    167                                         currentHandler = new HandlerSetText(); 
    168                                         currentHandler.onStartElement(); 
    169                                 } else { 
    170                                         currentMessage = new WindowsMessage(msgInt); 
    171                                 } 
    172                         } catch (NumberFormatException e) { 
    173                                 Console.printerrln("Invalid message type: type not a number"); 
    174                                 e.printStackTrace(); 
    175                         } 
    176                 } else if (qName.equals("param")) { 
    177                         if (currentHandler != null) { 
    178                                 currentHandler.onParameter(atts.getValue("name"), 
    179                                                 atts.getValue("value")); 
    180                         } else { 
    181                                 currentMessage.addParameter(atts.getValue("name"), 
    182                                                 atts.getValue("value")); 
    183                         } 
    184                 } 
    185         } 
    186  
    187         /* 
    188          * (non-Javadoc) 
    189          *  
    190          * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, 
    191          * java.lang.String, java.lang.String) 
    192          */ 
    193         @Override 
    194         public void endElement(String uri, String localName, String qName) 
    195                         throws SAXException { 
    196                 if (qName.equals("msg")) { 
    197                         if (currentHandler != null) { 
    198                                 currentHandler.onEndElement(); 
    199                                 currentHandler = null; 
    200                         } else { 
    201                                 try { 
    202                                         currentMessage.setTarget(WindowTree.getInstance()); 
    203                                         sequenceSplitter.addMessage(currentMessage); 
    204                                 } catch (InvalidParameterException e) { 
    205                                         Console.traceln(e.getMessage() + " WindowsMessage " 
    206                                                         + currentMessage + " ignored."); 
    207                                 } 
    208                         } 
    209                 } else if (qName.equals("session")) { 
    210                         sequenceSplitter.endSession(); 
    211                         List<Event> seq = sequenceSplitter.getSequence(); 
    212                         if( seq!=null && !seq.isEmpty() ) { 
    213                                 sequences.add(seq); 
    214                         } 
    215                         Console.traceln("end of session"); 
    216                 } 
    217         } 
    218  
    219         /** 
    220          * <p> 
    221          * Parses a given log file created by the MFCMonitor and adds its contents 
    222          * to the collection of event sequences. 
    223          * </p> 
    224          *  
    225          * @param filename 
    226          *            name and path of the log file 
    227          */ 
    228         public void parseFile(String filename) { 
    229                 if (filename == null) { 
    230                         throw new InvalidParameterException("filename must not be null"); 
    231                 } 
    232  
    233                 SAXParserFactory spf = SAXParserFactory.newInstance(); 
    234                 spf.setValidating(true); 
    235  
    236                 SAXParser saxParser = null; 
    237                 InputSource inputSource = null; 
    238                 try { 
    239                         saxParser = spf.newSAXParser(); 
    240                         inputSource = new InputSource(new InputStreamReader( 
    241                                         new FileInputStream(filename)));//, "UTF-8")); 
    242                 //} catch (UnsupportedEncodingException e) { 
    243                 //      e.printStackTrace(); 
    244                 } catch (ParserConfigurationException e) { 
    245                         e.printStackTrace(); 
    246                 } catch (SAXException e) { 
    247                         e.printStackTrace(); 
    248                 } catch (FileNotFoundException e) { 
    249                         e.printStackTrace(); 
    250                 } 
    251                 if (inputSource != null) { 
    252                         inputSource.setSystemId("file://" 
    253                                         + new File(filename).getAbsolutePath()); 
    254                         try { 
    255                                 if (saxParser == null) { 
    256                                         throw new RuntimeException("SAXParser creation failed"); 
    257                                 } 
    258                                 saxParser.parse(inputSource, this); 
    259                         } catch (SAXParseException e) { 
    260                                 Console.printerrln("Failure parsing file in line " 
    261                                                 + e.getLineNumber() + ", column " + e.getColumnNumber() 
    262                                                 + "."); 
    263                                 e.printStackTrace(); 
    264                         } catch (SAXException e) { 
    265                                 e.printStackTrace(); 
    266                         } catch (IOException e) { 
    267                                 e.printStackTrace(); 
    268                         } 
    269                 } 
    270                 if (countMessageOccurences) { 
    271                         Console.println("Message statistics:"); 
    272                         Console.println(typeCounter.toString() 
    273                                         .replace(" ", StringTools.ENDLINE) 
    274                                         .replaceAll("[\\{\\}]", "")); 
    275                 } 
    276         } 
     50    /** 
     51     * <p> 
     52     * If a custom message handler is used, this field contains its handle. Otherwise this field is 
     53     * {@code null}. 
     54     * </p> 
     55     */ 
     56    private MessageHandler currentHandler; 
     57 
     58    /** 
     59     * <p> 
     60     * internal handle to the current window tree 
     61     * </p> 
     62     */ 
     63    private WindowTree currentWindowTree; 
     64 
     65    /** 
     66     * <p> 
     67     * the type of the currently parsed message 
     68     * </p> 
     69     */ 
     70    private WindowsMessageType currentMessageType; 
     71     
     72    /** 
     73     * <p> 
     74     * the parameters of the currently parsed message 
     75     * </p> 
     76     */ 
     77    private Map<String, Object> currentMessageParameters = new HashMap<String, Object>(); 
     78     
     79    /** 
     80     * <p> 
     81     * {@link SequenceSplitter} instance used by the {@link MFCLogParser}. 
     82     * </p> 
     83     */ 
     84    private SequenceSplitter sequenceSplitter; 
     85 
     86    /** 
     87     * <p> 
     88     * Collection of message sequences that is contained in the log file, which is parsed. 
     89     * </p> 
     90     */ 
     91    private Collection<List<Event>> sequences; 
     92 
     93    /** 
     94     * <p> 
     95     * Debugging variable that allows the analysis which message type occurs how often in the log 
     96     * file. Can be used to enhance the message filter. 
     97     * </p> 
     98     */ 
     99    private SortedMap<WindowsMessageType, Integer> typeCounter; 
     100 
     101    /** 
     102     * <p> 
     103     * Debugging variable that enables the counting of the occurrences of each message. Used in 
     104     * combination with {@link #typeCounter}. 
     105     * </p> 
     106     */ 
     107    private boolean countMessageOccurences; 
     108 
     109    /** 
     110     * <p> 
     111     * Constructor. Creates a new LogParser that does not count message occurrences. 
     112     * </p> 
     113     */ 
     114    public MFCLogParser() { 
     115        this(false); 
     116    } 
     117 
     118    /** 
     119     * <p> 
     120     * Constructor. Creates a new LogParser. 
     121     * </p> 
     122     *  
     123     * @param countMessageOccurences 
     124     *            if true, the occurrences of each message type in the log is counted. 
     125     */ 
     126    public MFCLogParser(boolean countMessageOccurences) { 
     127        sequences = new LinkedList<List<Event>>(); 
     128        currentHandler = null; 
     129        this.countMessageOccurences = countMessageOccurences; 
     130        if (countMessageOccurences) { 
     131            typeCounter = new TreeMap<WindowsMessageType, Integer>(); 
     132        } 
     133    } 
     134 
     135    /** 
     136     * <p> 
     137     * Parses a log file written by the MFCMonitor and creates a collection of event sequences. 
     138     * </p> 
     139     *  
     140     * @param filename 
     141     *            name and path of the log file 
     142     */ 
     143    public void parseFile(String filename) { 
     144        if (filename == null) { 
     145            throw new InvalidParameterException("filename must not be null"); 
     146        } 
     147 
     148        parseFile(new File(filename)); 
     149    } 
     150 
     151    /** 
     152     * <p> 
     153     * Parses a log file written by the MFCMonitor and creates a collection of event sequences. 
     154     * </p> 
     155     *  
     156     * @param file 
     157     *            name and path of the log file 
     158     */ 
     159    public void parseFile(File file) { 
     160        if (file == null) { 
     161            throw new InvalidParameterException("file must not be null"); 
     162        } 
     163 
     164        SAXParserFactory spf = SAXParserFactory.newInstance(); 
     165        spf.setValidating(true); 
     166 
     167        SAXParser saxParser = null; 
     168        InputSource inputSource = null; 
     169        try { 
     170            saxParser = spf.newSAXParser(); 
     171            inputSource = new InputSource(new InputStreamReader(new FileInputStream(file)));// , 
     172                                                                                                // "UTF-8")); 
     173            // } catch (UnsupportedEncodingException e) { 
     174            // e.printStackTrace(); 
     175        } 
     176        catch (ParserConfigurationException e) { 
     177            // TODO handle Exception 
     178            e.printStackTrace(); 
     179        } 
     180        catch (SAXException e) { 
     181            // TODO handle Exception 
     182            e.printStackTrace(); 
     183        } 
     184        catch (FileNotFoundException e) { 
     185            // TODO handle Exception 
     186            e.printStackTrace(); 
     187        } 
     188         
     189        if (inputSource != null) { 
     190            inputSource.setSystemId("file://" + file.getAbsolutePath()); 
     191            try { 
     192                if (saxParser == null) { 
     193                    throw new RuntimeException("SAXParser creation failed"); 
     194                } 
     195                saxParser.parse(inputSource, this); 
     196            } 
     197            catch (SAXParseException e) { 
     198                Console.printerrln("Failure parsing file in line " + e.getLineNumber() + 
     199                                   ", column " + e.getColumnNumber() + "."); 
     200                e.printStackTrace(); 
     201            } 
     202            catch (SAXException e) { 
     203                // TODO handle Exception 
     204                e.printStackTrace(); 
     205            } 
     206            catch (IOException e) { 
     207                // TODO handle Exception 
     208                e.printStackTrace(); 
     209            } 
     210        } 
     211         
     212        if (countMessageOccurences) { 
     213            Console.println("Message statistics:"); 
     214            Console.println 
     215                (typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]", "")); 
     216        } 
     217    } 
     218     
     219    /** 
     220     * <p> 
     221     * Returns the collection of event sequences that is obtained from parsing log files. 
     222     * </p> 
     223     *  
     224     * @return collection of event sequences 
     225     */ 
     226    public Collection<List<Event>> getSequences() { 
     227        return sequences; 
     228    } 
     229 
     230    /** 
     231     * <p> 
     232     * Returns the gui model that is obtained from parsing log files. 
     233     * </p> 
     234     *  
     235     * @return collection of event sequences 
     236     */ 
     237    public GUIModel getGuiModel() { 
     238        return currentWindowTree.getGUIModel(); 
     239    } 
     240 
     241    /* 
     242     * (non-Javadoc) 
     243     *  
     244     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, 
     245     * java.lang.String, org.xml.sax.Attributes) 
     246     */ 
     247    @Override 
     248    public void startElement(String uri, String localName, String qName, Attributes atts) 
     249        throws SAXException 
     250    { 
     251        if (qName.equals("session")) { 
     252            Console.traceln("start of session"); 
     253            // in some logs, the session end may be marked in between the log. This is because 
     254            // of thread problems. So instead of creating a new GUI model, preserve it. 
     255            if (currentWindowTree == null) { 
     256                currentWindowTree = new WindowTree(); 
     257            } 
     258            sequenceSplitter = new SequenceSplitter(currentWindowTree); 
     259        } 
     260        else if (qName.equals("msg")) { 
     261            currentMessageType = WindowsMessageType.parseMessageType(atts.getValue("type")); 
     262 
     263            if (countMessageOccurences) { 
     264                Integer currentCount = typeCounter.get(currentMessageType); 
     265                if (currentCount == null) { 
     266                    typeCounter.put(currentMessageType, 1); 
     267                } 
     268                else { 
     269                    typeCounter.put(currentMessageType, currentCount + 1); 
     270                } 
     271            } 
     272 
     273            if (currentMessageType == WindowsMessageType.WM_CREATE) { 
     274                currentHandler = new HandlerCreate(currentWindowTree); 
     275                currentHandler.onStartElement(); 
     276            } 
     277            else if (currentMessageType == WindowsMessageType.WM_DESTROY) { 
     278                currentHandler = new HandlerDestroy(currentWindowTree); 
     279                currentHandler.onStartElement(); 
     280            } 
     281            else if (currentMessageType == WindowsMessageType.WM_SETTEXT) { 
     282                currentHandler = new HandlerSetText(currentWindowTree); 
     283                currentHandler.onStartElement(); 
     284            } 
     285        } 
     286        else if (qName.equals("param")) { 
     287            if (currentHandler != null) { 
     288                currentHandler.onParameter(atts.getValue("name"), atts.getValue("value")); 
     289            } 
     290            else { 
     291                // provide the parameters directly in the correct type 
     292                String paramName = atts.getValue("name"); 
     293                if (("window.hwnd".equals(paramName)) || 
     294                    ("source".equals(paramName)) || 
     295                    ("LPARAM".equals(paramName)) || 
     296                    ("WPARAM".equals(paramName)) || 
     297                    ("scrollPos".equals(paramName)) || 
     298                    ("scrollBarHandle".equals(paramName))) 
     299                { 
     300                    Long paramValue = Long.parseLong(atts.getValue("value")); 
     301                    currentMessageParameters.put(paramName, paramValue); 
     302                } 
     303                else { 
     304                    currentMessageParameters.put(paramName, atts.getValue("value")); 
     305                } 
     306            } 
     307        } 
     308    } 
     309 
     310    /* 
     311     * (non-Javadoc) 
     312     *  
     313     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, 
     314     * java.lang.String) 
     315     */ 
     316    @Override 
     317    public void endElement(String uri, String localName, String qName) throws SAXException { 
     318        if (qName.equals("msg")) { 
     319            if (currentHandler != null) { 
     320                currentHandler.onEndElement(); 
     321                currentHandler = null; 
     322            } 
     323            else { 
     324                try { 
     325                    long hwnd = (Long) currentMessageParameters.get("window.hwnd"); 
     326                    MFCGUIElement target = currentWindowTree.find(hwnd); 
     327                     
     328                    WindowsMessage message = new WindowsMessage 
     329                        (currentMessageType, target, currentMessageParameters); 
     330                     
     331                    sequenceSplitter.addMessage(message); 
     332                } 
     333                catch (InvalidParameterException e) { 
     334                    Console.traceln(e.getMessage() + " WindowsMessage " + currentMessageType + 
     335                                    " ignored."); 
     336                } 
     337            } 
     338        } 
     339        else if (qName.equals("session")) { 
     340            sequenceSplitter.endSession(); 
     341            List<Event> seq = sequenceSplitter.getSequence(); 
     342            if (seq != null && !seq.isEmpty()) { 
     343                sequences.add(seq); 
     344            } 
     345            Console.traceln("end of session"); 
     346        } 
     347    } 
     348 
    277349} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/MessageHandler.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
     3 
     4import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    25 
    36/** 
    47 * <p> 
    5  * Base class to define custom message handlers, for messages that shall be 
    6  * handled differently during the parsing of usage logs. It provides dummy 
    7  * implementations for all required methods, such that implementations can only 
    8  * overwrite the parts they actually require and ignore the rest. 
     8 * Base class to define custom message handlers, for messages that shall be handled differently 
     9 * during the parsing of usage logs. It provides dummy implementations for all required methods, 
     10 * such that implementations can only overwrite the parts they actually require and ignore the rest. 
    911 * </p> 
    1012 *  
     
    1416public class MessageHandler { 
    1517 
    16         /** 
    17          * <p> 
    18          * Constructor. Protected to prohibit initialization of the base class 
    19          * itself. 
    20          * </p> 
    21          */ 
    22         protected MessageHandler() { 
    23         } 
     18    /** 
     19     * <p> 
     20     * during parsing, a tree of GUI elements is created and adapted. 
     21     * This is the reference to it. 
     22     * </p> 
     23     */ 
     24    private WindowTree windowTree; 
    2425 
    25         /** 
    26          * <p> 
    27          * Called in the startElement() method of the {@link MFCLogParser} when a 
    28          * msg-node begins. 
    29          * </p> 
    30          */ 
    31         public void onStartElement() { 
    32         } 
     26    /** 
     27     * <p> 
     28     * Constructor. Protected to prohibit initialization of the base class itself. 
     29     * </p> 
     30     *  
     31     * @param windowTree the tree of GUI element specifications to be created and adapted during 
     32     *                   parsing 
     33     */ 
     34    protected MessageHandler(WindowTree windowTree) { 
     35        this.windowTree = windowTree; 
     36    } 
    3337 
    34         /** 
    35          * <p> 
    36          * Called by the {@link MFCLogParser} to handle param-nodes. 
    37          * </p> 
    38          *  
    39          * @param name 
    40          *            name (type) of the parameter 
    41          * @param value 
    42          *            value of the parameter 
    43          */ 
    44         public void onParameter(String name, String value) { 
    45         } 
     38    /** 
     39     * <p> 
     40     * Called in the startElement() method of the {@link MFCLogParser} when a msg-node begins. 
     41     * </p> 
     42     */ 
     43    public void onStartElement() {} 
    4644 
    47         /** 
    48          * <p> 
    49          * Called in the endElement() method of {@link MFCLogParser} when a msg-node 
    50          * ends. 
    51          * </p> 
    52          */ 
    53         public void onEndElement() { 
    54         } 
     45    /** 
     46     * <p> 
     47     * Called by the {@link MFCLogParser} to handle param-nodes. 
     48     * </p> 
     49     *  
     50     * @param name 
     51     *            name (type) of the parameter 
     52     * @param value 
     53     *            value of the parameter 
     54     */ 
     55    public void onParameter(String name, String value) {} 
     56 
     57    /** 
     58     * <p> 
     59     * Called in the endElement() method of {@link MFCLogParser} when a msg-node ends. 
     60     * </p> 
     61     */ 
     62    public void onEndElement() {} 
     63 
     64    /** 
     65     * @return the window tree created and adapted during parsing 
     66     */ 
     67    protected WindowTree getWindowTree() { 
     68        return windowTree; 
     69    } 
     70     
    5571} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/SequenceSplitter.java

    r581 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc; 
    23 
     
    67import de.ugoe.cs.quest.eventcore.Event; 
    78import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessage; 
     9import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; 
     10import de.ugoe.cs.quest.plugin.mfc.guimodel.WindowTree; 
    811import de.ugoe.cs.util.console.Console; 
    912 
    1013/** 
    1114 * <p> 
    12  * Responsible to split sequences into subsequences, such that each subsequences 
    13  * contains exactly one event. 
     15 * Responsible to split sequences into subsequences, such that each subsequences contains exactly 
     16 * one event. 
    1417 * </p> 
    1518 *  
     
    1922public class SequenceSplitter { 
    2023 
    21         /** 
    22         * <p> 
    23         * Contains the current subsequence. 
    24         * </p> 
    25         */ 
    26         private List<WindowsMessage> currentSequence; 
     24    /** 
     25    * <p> 
     26    * Contains the current subsequence. 
     27    * </p> 
     28    */ 
     29    private List<WindowsMessage> currentSequence; 
    2730 
    28         /** 
    29         * <p> 
    30          * Number of messages in the current sequences, that signal that a key or 
    31          * mouse button has been pressed down to which not yet a message has been 
    32          * found, that signals that the button has been released. 
    33         * </p> 
    34         */ 
    35         private int openDowns; 
     31    /** 
     32    * <p> 
     33     * Number of messages in the current sequences, that signal that a key or mouse button has been 
     34     * pressed down to which not yet a message has been found, that signals that the button has been 
     35     * released. 
     36    * </p> 
     37    */ 
     38    private int openDowns; 
    3639 
    37         /** 
    38          * <p> 
    39          * Internal flag that signals if {@link #currentSequence} needs to be 
    40          * initialized. 
    41          * </p> 
    42          */ 
    43         private boolean initMessages; 
     40    /** 
     41     * <p> 
     42     * Internal flag that signals if {@link #currentSequence} needs to be initialized. 
     43     * </p> 
     44     */ 
     45    private boolean initMessages; 
    4446 
    45         /** 
    46          * <p> 
    47          * The {@link EventGenerator} used to convert the subsequences into 
    48          * {@link Event}s 
    49          * </p> 
    50          */ 
    51         private EventGenerator tokenGenerator; 
     47    /** 
     48     * <p> 
     49     * The {@link EventGenerator} used to convert the subsequences into {@link Event}s 
     50     * </p> 
     51     */ 
     52    private EventGenerator tokenGenerator; 
    5253 
    53         /** 
    54         * <p> 
    55         * The event sequence generated. 
    56         * </p> 
    57         */ 
    58         private List<Event> actionSequence; 
     54    /** 
     55    * <p> 
     56    * The event sequence generated. 
     57    * </p> 
     58    */ 
     59    private List<Event> actionSequence; 
    5960 
    60         /** 
    61         * <p> 
    62         * Type of the previous message. 
    63         * </p> 
    64         */ 
    65         private int prevMsg = 0; 
     61    /** 
     62    * <p> 
     63    * Type of the previous message. 
     64    * </p> 
     65    */ 
     66    private WindowsMessageType prevMsg; 
    6667 
    67         /** 
    68         * <p> 
    69         * Constructor. Creates a new SequenceSplitter. 
    70         * </p> 
    71         */ 
    72         public SequenceSplitter() { 
    73                 currentSequence = new LinkedList<WindowsMessage>(); 
    74                 openDowns = 0; 
    75                 initMessages = true; 
    76                 tokenGenerator = new EventGenerator(); 
    77                 actionSequence = new LinkedList<Event>(); 
    78                 prevMsg = 0; 
    79         } 
     68    /** 
     69    * <p> 
     70    * Constructor. Creates a new SequenceSplitter. 
     71    * </p> 
     72    */ 
     73    public SequenceSplitter(WindowTree windowTree) { 
     74        currentSequence = new LinkedList<WindowsMessage>(); 
     75        openDowns = 0; 
     76        initMessages = true; 
     77        tokenGenerator = new EventGenerator(windowTree); 
     78        actionSequence = new LinkedList<Event>(); 
     79        prevMsg = null; 
     80    } 
    8081 
    81         /** 
    82          * <p> 
    83          * Called by the {@link MFCLogParser} every time a message is parsed. 
    84          * </p> 
    85          *  
    86          * @param msg 
    87          *            message to be added 
    88          */ 
    89         public void addMessage(WindowsMessage msg) { 
    90                 if (startOfSequence(msg)) { 
    91                         if (!initMessages) { 
    92                                 Event currentAction = tokenGenerator 
    93                                                 .generateEvent(currentSequence); 
    94                                 if (currentAction != null) { 
    95                                         actionSequence.add(currentAction); 
    96                                 } 
    97                                 if (isKeyMessage(msg.getType()) && openDowns > 0) { 
    98                                         Console.traceln("Key message found with open down mouse messages - will probabably result in a faulty sequence."); 
    99                                 } 
    100                         } else { 
    101                                 initMessages = false; 
    102                         } 
    103                         currentSequence = new LinkedList<WindowsMessage>(); 
    104                 } 
    105                 if (isUpMessage(msg.getType())) { 
    106                         if (openDowns > 0) { 
    107                                 openDowns--; 
    108                         } 
    109                 } 
     82    /** 
     83     * <p> 
     84     * Called by the {@link MFCLogParser} every time a message is parsed. 
     85     * </p> 
     86     *  
     87     * @param msg 
     88     *            message to be added 
     89     */ 
     90    public void addMessage(WindowsMessage msg) { 
     91        if (startOfSequence(msg)) { 
     92            if (!initMessages) { 
     93                Event currentAction = tokenGenerator.generateEvent(currentSequence); 
     94                if (currentAction != null) { 
     95                    actionSequence.add(currentAction); 
     96                } 
     97                if (msg.getType().isKeyMessage() && openDowns > 0) { 
     98                    Console 
     99                        .traceln("Key message found with open down mouse messages - will probabably result in a faulty sequence."); 
     100                } 
     101            } 
     102            else { 
     103                initMessages = false; 
     104            } 
     105            currentSequence = new LinkedList<WindowsMessage>(); 
     106        } 
     107        if (msg.getType().isUpMessage()) { 
     108            if (openDowns > 0) { 
     109                openDowns--; 
     110            } 
     111        } 
    110112 
    111                 // this fix checks if there are two consecutive mouse-down messages. 
    112                 // This sometimes occurs due to incorrect filtering in the monitoring 
    113                 // dll. 
    114                 if (!(prevMsg == MessageDefs.WM_LBUTTONDOWN && prevMsg == msg.getType())) { 
    115                         currentSequence.add(msg); 
    116                 } else { 
    117                         openDowns--; 
    118                 } 
    119                 prevMsg = msg.getType(); 
    120         } 
     113        // this fix checks if there are two consecutive mouse-down messages. 
     114        // This sometimes occurs due to incorrect filtering in the monitoring 
     115        // dll. 
     116        if (!(prevMsg == WindowsMessageType.WM_LBUTTONDOWN && prevMsg == msg.getType())) { 
     117            currentSequence.add(msg); 
     118        } 
     119        else { 
     120            openDowns--; 
     121        } 
     122        prevMsg = msg.getType(); 
     123    } 
    121124 
    122         /** 
    123          * <p> 
    124          * Returns the event sequence generated from the message that have been 
    125          * added. 
    126          * </p> 
    127          *  
    128          * @return generated event sequence 
    129          */ 
    130         public List<Event> getSequence() { 
    131                 return actionSequence; 
    132         } 
     125    /** 
     126     * <p> 
     127     * Returns the event sequence generated from the message that have been added. 
     128     * </p> 
     129     *  
     130     * @return generated event sequence 
     131     */ 
     132    public List<Event> getSequence() { 
     133        return actionSequence; 
     134    } 
    133135 
    134         /** 
    135          * <p> 
    136          * Called when a session in the log file is finished, i.e., a closing 
    137          * session-node is found. 
    138          * </p> 
    139          */ 
    140         public void endSession() { 
    141                 Event currentAction = tokenGenerator 
    142                                 .generateEvent(currentSequence); 
    143                 if (currentAction != null) { 
    144                         actionSequence.add(currentAction); 
    145                 } 
    146         } 
     136    /** 
     137     * <p> 
     138     * Called when a session in the log file is finished, i.e., a closing session-node is found. 
     139     * </p> 
     140     */ 
     141    public void endSession() { 
     142        Event currentAction = tokenGenerator.generateEvent(currentSequence); 
     143        if (currentAction != null) { 
     144            actionSequence.add(currentAction); 
     145        } 
     146    } 
    147147 
    148         /** 
    149          * <p> 
    150          * Checks if the message starts a new subsequence and returns the result. 
    151          * </p> 
    152          *  
    153          * @param msg 
    154          *            message that is checked 
    155          * @return true, if a new subsequence begins 
    156          */ 
    157         private boolean startOfSequence(WindowsMessage msg) { 
    158                 boolean isStart = false; 
    159                 int msgType = msg.getType(); 
    160                 if (isKeyMessage(msgType)) { 
    161                         isStart = true; 
    162                 } 
    163                 if (isDownMessage(msgType)) { 
    164                         openDowns++; 
    165                         if (openDowns == 1) { 
    166                                 isStart = true; 
    167                         } 
    168                 } 
    169                 if (isDblclkMessage(msgType)) { 
    170                         openDowns++; 
    171                 } 
    172                 return isStart; 
    173         } 
    174  
    175         /** 
    176          * <p> 
    177          * Checks if the type of a message is generated is a keyboard interaction. 
    178          * </p> 
    179          *  
    180          * @param msgType 
    181          *            type of the message 
    182          * @return true if it is a keyboard interaction; false otherwise 
    183          */ 
    184         private boolean isKeyMessage(int msgType) { 
    185                 boolean isKeyMsg = false; 
    186                 switch (msgType) { 
    187                 case MessageDefs.WM_KEYDOWN: 
    188                 case MessageDefs.WM_KEYUP: 
    189                 case MessageDefs.WM_SYSKEYDOWN: 
    190                 case MessageDefs.WM_SYSKEYUP: 
    191                         isKeyMsg = true; 
    192                         break; 
    193                 default: 
    194                         break; 
    195                 } 
    196                 return isKeyMsg; 
    197         } 
    198  
    199         /** 
    200          * <p> 
    201          * Checks if the type of a message indicates that the mouse has been pressed 
    202          * down. 
    203          * </p> 
    204          *  
    205          * @param msgType 
    206          *            type of the message 
    207          * @return true if it is mouse-down message; false otherwise 
    208          */ 
    209         private boolean isDownMessage(int msgType) { 
    210                 boolean isDownMsg = false; 
    211                 switch (msgType) { 
    212                 case MessageDefs.WM_LBUTTONDOWN: 
    213                 case MessageDefs.WM_RBUTTONDOWN: 
    214                 case MessageDefs.WM_MBUTTONDOWN: 
    215                 case MessageDefs.WM_XBUTTONDOWN: 
    216                 case MessageDefs.WM_NCLBUTTONDOWN: 
    217                 case MessageDefs.WM_NCRBUTTONDOWN: 
    218                 case MessageDefs.WM_NCMBUTTONDOWN: 
    219                 case MessageDefs.WM_NCXBUTTONDOWN: 
    220                         isDownMsg = true; 
    221                         break; 
    222                 default: 
    223                         break; 
    224                 } 
    225                 return isDownMsg; 
    226         } 
    227  
    228         /** 
    229          * <p> 
    230          * Checks if the type of a message indicates that a double click has been 
    231          * performed. 
    232          * </p> 
    233          *  
    234          * @param msgType 
    235          *            type of the message 
    236          * @return true if it is a double click message; false otherwise 
    237          */ 
    238         private boolean isDblclkMessage(int msgType) { 
    239                 boolean isDblclkMsg = false; 
    240                 switch (msgType) { 
    241                 case MessageDefs.WM_LBUTTONDBLCLK: 
    242                 case MessageDefs.WM_RBUTTONDBLCLK: 
    243                 case MessageDefs.WM_MBUTTONDBLCLK: 
    244                 case MessageDefs.WM_XBUTTONDBLCLK: 
    245                 case MessageDefs.WM_NCLBUTTONDBLCLK: 
    246                 case MessageDefs.WM_NCRBUTTONDBLCLK: 
    247                 case MessageDefs.WM_NCMBUTTONDBLCLK: 
    248                 case MessageDefs.WM_NCXBUTTONDBLCLK: 
    249                         isDblclkMsg = true; 
    250                         break; 
    251                 default: 
    252                         break; 
    253                 } 
    254                 return isDblclkMsg; 
    255         } 
    256  
    257         /** 
    258          * <p> 
    259          * Checks if the type of a message indicates that the mouse has been 
    260          * released. 
    261          * </p> 
    262          *  
    263          * @param msgType 
    264          *            type of the message 
    265          * @return true if it is mouse-up message; false otherwise 
    266          */ 
    267         private boolean isUpMessage(int msgType) { 
    268                 boolean isUpMsg = false; 
    269                 switch (msgType) { 
    270                 case MessageDefs.WM_LBUTTONUP: 
    271                 case MessageDefs.WM_RBUTTONUP: 
    272                 case MessageDefs.WM_MBUTTONUP: 
    273                 case MessageDefs.WM_XBUTTONUP: 
    274                 case MessageDefs.WM_NCLBUTTONUP: 
    275                 case MessageDefs.WM_NCRBUTTONUP: 
    276                 case MessageDefs.WM_NCMBUTTONUP: 
    277                 case MessageDefs.WM_NCXBUTTONUP: 
    278                         isUpMsg = true; 
    279                         break; 
    280                 default: 
    281                         break; 
    282                 } 
    283                 return isUpMsg; 
    284         } 
     148    /** 
     149     * <p> 
     150     * Checks if the message starts a new subsequence and returns the result. 
     151     * </p> 
     152     *  
     153     * @param msg 
     154     *            message that is checked 
     155     * @return true, if a new subsequence begins 
     156     */ 
     157    private boolean startOfSequence(WindowsMessage msg) { 
     158        boolean isStart = false; 
     159        WindowsMessageType msgType = msg.getType(); 
     160        if (msgType.isKeyMessage()) { 
     161            isStart = true; 
     162        } 
     163        if (msgType.isDownMessage()) { 
     164            openDowns++; 
     165            if (openDowns == 1) { 
     166                isStart = true; 
     167            } 
     168        } 
     169        if (msgType.isDblclkMessage()) { 
     170            openDowns++; 
     171        } 
     172        return isStart; 
     173    } 
    285174 
    286175} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/commands/CMDparseXML.java

    r566 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc.commands; 
    23 
     
    45import java.util.Collection; 
    56import java.util.List; 
    6 import java.util.SortedSet; 
    77 
    88import de.ugoe.cs.quest.CommandHelpers; 
    99import de.ugoe.cs.quest.eventcore.Event; 
     10import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 
    1011import de.ugoe.cs.quest.plugin.mfc.MFCLogParser; 
    11 import de.ugoe.cs.quest.plugin.mfc.eventcore.MFCTargetComparator; 
    12 import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowTree; 
    1312import de.ugoe.cs.quest.ui.GlobalDataContainer; 
    1413import de.ugoe.cs.util.console.Command; 
     
    1716/** 
    1817 * <p> 
    19  * Command to parse an XML file with sessions monitored by EventBench's 
    20  * MFCUsageMonitor. 
     18 * Command to parse an XML file with sessions monitored by EventBench's MFCUsageMonitor. 
    2119 * </p> 
    2220 *  
     
    2624public class CMDparseXML implements Command { 
    2725 
    28         /* 
    29         * (non-Javadoc) 
    30         *  
    31         * @see de.ugoe.cs.util.console.Command#help() 
    32         */ 
    33         @Override 
    34         public void help() { 
    35                 Console.println("Usage: parseXML <filename> {<sequencesName>} {<countMessageOccurences>}"); 
    36         } 
     26    /* 
     27    * (non-Javadoc) 
     28    *  
     29    * @see de.ugoe.cs.util.console.Command#help() 
     30    */ 
     31    @Override 
     32    public void help() { 
     33        Console.println("Usage: parseXML <filename> {<sequencesName>} {<countMessageOccurences>}"); 
     34    } 
    3735 
    38         /* 
    39         * (non-Javadoc) 
    40         *  
    41         * @see de.ugoe.cs.util.console.Command#run(java.util.List) 
    42         */ 
    43         @Override 
    44         public void run(List<Object> parameters) { 
    45                 String filename; 
    46                 String sequencesName = "sequences"; 
    47                 boolean countMessageOccurences = false; 
     36    /* 
     37    * (non-Javadoc) 
     38    *  
     39    * @see de.ugoe.cs.util.console.Command#run(java.util.List) 
     40    */ 
     41    @Override 
     42    public void run(List<Object> parameters) { 
     43        String filename; 
     44        String sequencesName = "sequences"; 
     45        boolean countMessageOccurences = false; 
    4846 
    49                 try { 
    50                         filename = (String) parameters.get(0); 
    51                         if (parameters.size() >= 2) { 
    52                                 sequencesName = (String) parameters.get(1); 
    53                         } 
    54                         if (parameters.size() >= 3) { 
    55                                 countMessageOccurences = Boolean 
    56                                                 .parseBoolean((String) parameters.get(2)); 
    57                         } 
    58                 } catch (Exception e) { 
    59                         throw new InvalidParameterException(); 
    60                 } 
     47        try { 
     48            filename = (String) parameters.get(0); 
     49            if (parameters.size() >= 2) { 
     50                sequencesName = (String) parameters.get(1); 
     51            } 
     52            if (parameters.size() >= 3) { 
     53                countMessageOccurences = Boolean.parseBoolean((String) parameters.get(2)); 
     54            } 
     55        } 
     56        catch (Exception e) { 
     57            throw new InvalidParameterException(); 
     58        } 
    6159 
    62                 MFCLogParser parser = new MFCLogParser(countMessageOccurences); 
    63                 parser.parseFile(filename); 
     60        MFCLogParser parser = new MFCLogParser(countMessageOccurences); 
     61        parser.parseFile(filename); 
    6462 
    65                 Collection<List<Event>> sequences = parser.getSequences(); 
    66                  
    67                 Console.traceln("Pre-computing event target equalities."); 
    68                 // compare all Events to a dummy event to make sure they are known by 
    69                 // the MFCTargetComparator 
    70                 Event dummyEvent = Event.STARTEVENT; 
    71                 for (List<Event> sequence : sequences) { 
    72                         for (Event event : sequence) { 
    73                                 event.equals(dummyEvent); 
    74                         } 
    75                 } 
    76                 MFCTargetComparator.setMutable(false); 
    77                  
    78                 SortedSet<String> targets = WindowTree.getInstance().getTargets(); 
     63        Collection<List<Event>> sequences = parser.getSequences(); 
    7964 
    80                 if (GlobalDataContainer.getInstance().addData(sequencesName, sequences)) { 
    81                         CommandHelpers.dataOverwritten(sequencesName); 
    82                 } 
    83                 if (GlobalDataContainer.getInstance().addData( 
    84                                 sequencesName + "_targets", targets)) { 
    85                         CommandHelpers.dataOverwritten(sequencesName + "_targets"); 
    86                 } 
    87         } 
     65        GUIModel targets = parser.getGuiModel(); 
     66 
     67        if (GlobalDataContainer.getInstance().addData(sequencesName, sequences)) { 
     68            CommandHelpers.dataOverwritten(sequencesName); 
     69        } 
     70        if (GlobalDataContainer.getInstance().addData(sequencesName + "_targets", targets)) { 
     71            CommandHelpers.dataOverwritten(sequencesName + "_targets"); 
     72        } 
     73    } 
    8874 
    8975} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/eventcore/MFCEvent.java

    r578 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc.eventcore; 
    23 
    3 import java.security.InvalidParameterException; 
    4 import java.util.HashMap; 
    5 import java.util.Map; 
    6  
    7 import de.ugoe.cs.quest.IReplayDecorator; 
    8 import de.ugoe.cs.quest.eventcore.IReplayable; 
    9 import de.ugoe.cs.quest.plugin.mfc.MFCReplayDecorator; 
    10 import de.ugoe.cs.util.StringTools; 
     4import de.ugoe.cs.quest.eventcore.Event; 
     5import de.ugoe.cs.quest.eventcore.IEventType; 
     6import de.ugoe.cs.quest.eventcore.guimodel.GUIModel; 
     7import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 
    118 
    129/** 
    1310 * <p> 
    14  * Contains all informations about a windows message, i.e., all parameters that 
    15  * are read when a windows message is parsed as well as its target, hwnd, etc. 
     11 * Contains all informations about a windows message, i.e., all parameters that are read when a 
     12 * windows message is parsed as well as its target, hwnd, etc. 
    1613 * </p> 
    1714 *  
     
    2017 *  
    2118 */ 
    22 public class WindowsMessage implements IReplayable { 
     19public class MFCEvent extends Event { 
    2320 
    24         /** 
    25         * <p> 
    26         * Id for object serialization. 
    27         * </p> 
    28         */ 
    29         private static final long serialVersionUID = 1L; 
     21    /** 
     22    * <p> 
     23    * Id for object serialization. 
     24    * </p> 
     25    */ 
     26    private static final long serialVersionUID = 1L; 
    3027 
    31         /** 
    32          * <p> 
    33          * Type of the message. 
    34          * </p> 
    35          */ 
    36         final int type; 
     28    /** 
     29     * <p> 
     30     * TODO: comment 
     31     * </p> 
     32     * 
     33     * @param eventType 
     34     * @param target 
     35     * @param currentMessageParameters 
     36     */ 
     37    public MFCEvent(IEventType    eventType, 
     38                    MFCGUIElement target, 
     39                    GUIModel      guiModel) 
     40    { 
     41        super(eventType); 
     42        super.setTarget(target); 
     43    } 
    3744 
    38         /** 
    39          * <p> 
    40          * Window class of the message target. Default: "" 
    41          * </p> 
    42          */ 
    43         private String windowClass = ""; 
    44  
    45         /** 
    46          * <p> 
    47          * Resource Id of the message target. Default: 0 
    48          * </p> 
    49          */ 
    50         private int resourceId = 0; 
    51  
    52         /** 
    53          * <p> 
    54          * XML representation of the message target. 
    55          * </p> 
    56          */ 
    57         private String xmlWindowDescription = ""; 
    58  
    59         /** 
    60          * <p> 
    61          * String that contains the names of all parent widgets and itself, separated by dots, 
    62          * e.g., "GrandParent.Parent.self". 
    63          * </p> 
    64          */ 
    65         private String parentNames = null; 
    66  
    67         /** 
    68          * <p> 
    69          * String that contains the window class of the parent widget. 
    70          * </p> 
    71          */ 
    72         private String parentClass = null; 
    73  
    74         /** 
    75          * <p> 
    76          * LPARAM of the message. Default: 0 
    77          * </p> 
    78          */ 
    79         private long LPARAM = 0; 
    80  
    81         /** 
    82          * <p> 
    83          * WPARAM of the message. Default: 0 
    84          * </p> 
    85          */ 
    86         private long WPARAM = 0; 
    87  
    88         /** 
    89          * <p> 
    90          * If the LPARAM contains a HWND, this string stores the target of the HWND. 
    91          * </p> 
    92          */ 
    93         private String LPARAMasWindowDesc = null; 
    94  
    95         /** 
    96          * <p> 
    97          * If the WPARAM contains a HWND, this string stores the target of the HWND. 
    98          * </p> 
    99          */ 
    100         private String WPARAMasWindowDesc = null; 
    101  
    102         /** 
    103          * <p> 
    104          * Delay after sending the messages during a replay. Default: 0 
    105          * </p> 
    106          */ 
    107         private int delay = 0; 
    108  
    109         /** 
    110          * <p> 
    111          * A map of all parameters, associated with the message, created during the 
    112          * parsing of messages from the logs {@code param}-nodes. 
    113          * </p> 
    114          */ 
    115         private Map<String, String> params = new HashMap<String, String>(); 
    116  
    117         /** 
    118          * <p> 
    119          * Constructor. Creates a new message with a given message type. 
    120          * </p> 
    121          *  
    122          * @param type 
    123          *            type of the message 
    124          */ 
    125         public WindowsMessage(int type) { 
    126                 this.type = type; 
    127         } 
    128  
    129         /** 
    130          * <p> 
    131          * Adds a parameter to the message. 
    132          * </p> 
    133          *  
    134          * @param type 
    135          *            type descriptor of the parameter 
    136          * @param value 
    137          *            value of the parameter 
    138          */ 
    139         public void addParameter(String type, String value) { 
    140                 params.put(type, value); 
    141                 if (type.equals("LPARAM")) { 
    142                         LPARAM = Long.parseLong(value); 
    143                 } else if (type.equals("WPARAM")) { 
    144                         WPARAM = Long.parseLong(value); 
    145                 } 
    146         } 
    147  
    148         /** 
    149          * <p> 
    150          * Returns the type of the message. 
    151          * </p> 
    152          *  
    153          * @return type of the message 
    154          */ 
    155         public int getType() { 
    156                 return type; 
    157         } 
    158  
    159         /** 
    160          * <p> 
    161          * Returns the value of a parameter, given its type. If the parameter is not 
    162          * found, {@code null} is returned. 
    163          * </p> 
    164          *  
    165          * @param type 
    166          *            type of the parameter 
    167          * @return value of the parameter 
    168          */ 
    169         public String getParameter(String type) { 
    170                 return params.get(type); 
    171         } 
    172  
    173         /** 
    174          * <p> 
    175          * Returns the window class of the message target. 
    176          * </p> 
    177          *  
    178          * @return window class of the message target 
    179          */ 
    180         public String getWindowClass() { 
    181                 return windowClass; 
    182         } 
    183  
    184         /** 
    185          * <p> 
    186          * Returns the HWND the message is addressed to. 
    187          * </p> 
    188          *  
    189          * @return HWND the message is addressed to 
    190          */ 
    191         public int getHwnd() { 
    192                 int hwnd = -1; 
    193                 String hwndString = getParameter("window.hwnd"); // possible, as 
    194                                                                                                                         // "window.hwnd" is 
    195                                                                                                                         // mandatory 
    196                 if (hwndString != null) { 
    197                         hwnd = Integer.parseInt(hwndString); 
    198                 } 
    199                 return hwnd; 
    200         } 
    201  
    202         /** 
    203          * <p> 
    204          * Returns the resource Id of the message target. 
    205          * </p> 
    206          *  
    207          * @return resource Id of the message target 
    208          */ 
    209         public int getWindowResourceId() { 
    210                 return resourceId; 
    211         } 
    212  
    213         /** 
    214          * <p> 
    215          * Two {@link WindowsMessage} are equal, if their {@link #type}, 
    216          * {@link #xmlWindowDescription}, and {@link #params} are equal. 
    217          * </p> 
    218          *  
    219          * @see java.lang.Object#equals(java.lang.Object) 
    220          */ 
    221         @Override 
    222         public boolean equals(Object other) { 
    223                 if (other == this) { 
    224                         return true; 
    225                 } 
    226                 boolean isEqual = false; 
    227                 if (other instanceof WindowsMessage) { 
    228                         isEqual = ((WindowsMessage) other).type == this.type 
    229                                         && ((WindowsMessage) other).xmlWindowDescription 
    230                                                         .equals(this.xmlWindowDescription) 
    231                                         && ((WindowsMessage) other).params.equals(this.params); 
    232                 } 
    233                 return isEqual; 
    234         } 
    235  
    236         /* 
    237          * (non-Javadoc) 
    238          *  
    239          * @see java.lang.Object#hashCode() 
    240          */ 
    241         @Override 
    242         public int hashCode() { 
    243                 int multiplier = 17; 
    244                 int hash = 42; 
    245  
    246                 hash = multiplier * hash + type; 
    247                 hash = multiplier * hash + xmlWindowDescription.hashCode(); 
    248                 hash = multiplier * hash + params.hashCode(); 
    249  
    250                 return hash; 
    251         } 
    252  
    253         /** 
    254          * <p> 
    255          * Returns a string representation of the message of the form 
    256          * "msg[target=HWND;type=TYPE]". 
    257          * </p> 
    258          *  
    259          * @see java.lang.Object#toString() 
    260          */ 
    261         @Override 
    262         public String toString() { 
    263                 return "msg[target=" + getParameter("window.hwnd") + ";type=" + type 
    264                                 + "]"; 
    265         } 
    266  
    267         /** 
    268          * <p> 
    269          * Retrieves the target string of a message from a given {@link WindowTree} 
    270          * through looking up the HWND the message is addressed to in the window 
    271          * tree. 
    272          * </p> 
    273          *  
    274          * @param windowTree 
    275          *            {@link WindowTree} from which the target is extracted 
    276          * @throws InvalidParameterException 
    277          *             thrown if HWND is not contained in windowTree 
    278          */ 
    279         public void setTarget(WindowTree windowTree) 
    280                         throws InvalidParameterException { 
    281                 int hwnd = Integer.parseInt(getParameter("window.hwnd")); 
    282                 WindowTreeNode node = windowTree.find(hwnd); 
    283                 if (node == null) { 
    284                         throw new InvalidParameterException("No window with HWND " + hwnd 
    285                                         + " found in window tree!"); 
    286                 } else { 
    287                         windowClass = node.getClassName(); 
    288                         resourceId = node.getResourceId(); 
    289                         xmlWindowDescription = node.xmlRepresentation(); 
    290                         parentNames = node.getParentNames(); 
    291                         WindowTreeNode parent = node.getParent(); 
    292                         if (parent == null) { 
    293                                 parentClass = ""; 
    294                         } else { 
    295                                 parentClass = parent.getClassName(); 
    296                         } 
    297                 } 
    298         } 
    299  
    300         /** 
    301          * <p> 
    302          * Sets the LPARAM of a message. 
    303          * </p> 
    304          *  
    305          * @param paramValue 
    306          *            value of the LPARAM 
    307          */ 
    308         public void setLPARAM(long paramValue) { 
    309                 LPARAM = paramValue; 
    310         } 
    311  
    312         /** 
    313          * <p> 
    314          * Sets the WPARAM of a message. 
    315          * </p> 
    316          *  
    317          * @param paramValue 
    318          *            value of the WPARAM 
    319          */ 
    320         public void setWPARAM(long paramValue) { 
    321                 WPARAM = paramValue; 
    322         } 
    323  
    324         /** 
    325          * <p> 
    326          * Returns the LPARAM of a message. 
    327          * </p> 
    328          *  
    329          * @return LPARAM of the message 
    330          */ 
    331         public long getLPARAM() { 
    332                 return LPARAM; 
    333         } 
    334  
    335         /** 
    336          * <p> 
    337          * Returns the WPARAM of a message. 
    338          * </p> 
    339          *  
    340          * @return WPARAM of the message 
    341          */ 
    342         public long getWPARAM() { 
    343                 return WPARAM; 
    344         } 
    345  
    346         /** 
    347          * <p> 
    348          * If the LPARAM contains a HWND, this function can be used to set a target 
    349          * string to identify the HWND at run-time. 
    350          * </p> 
    351          *  
    352          * @param windowDesc 
    353          *            target string 
    354          */ 
    355         public void setLPARAMasWindowDesc(String windowDesc) { 
    356                 LPARAMasWindowDesc = windowDesc; 
    357         } 
    358  
    359         /** 
    360          * <p> 
    361          * If the WPARAM contains a HWND, this function can be used to set a target 
    362          * string to identify the HWND at run-time. 
    363          * </p> 
    364          *  
    365          * @param windowDesc 
    366          *            target string 
    367          */ 
    368         public void setWPARAMasWindowDesc(String windowDesc) { 
    369                 WPARAMasWindowDesc = windowDesc; 
    370         } 
    371  
    372         /** 
    373          * <p> 
    374          * If the LPARAM contains a HWND and the target string for the HWND is set, 
    375          * this function returns the target string. Otherwise, {@code null} is 
    376          * returned. 
    377          * </p> 
    378          *  
    379          * @return target string if available; {@code null} otherwise 
    380          */ 
    381         public String getLPARAMasWindowDesc() { 
    382                 return LPARAMasWindowDesc; 
    383         } 
    384  
    385         /** 
    386          * <p> 
    387          * If the WPARAM contains a HWND and the target string for the HWND is set, 
    388          * this function returns the target string. Otherwise, {@code null} is 
    389          * returned. 
    390          * </p> 
    391          *  
    392          * @return target string if available; {@code null} otherwise 
    393          */ 
    394         public String getWPARAMasWindowDesc() { 
    395                 return WPARAMasWindowDesc; 
    396         } 
    397  
    398         /** 
    399          * <p> 
    400          * Returns the target string of the message. 
    401          * </p> 
    402          *  
    403          * @return target string of the message 
    404          */ 
    405         public String getXmlWindowDescription() { 
    406                 return xmlWindowDescription; 
    407         } 
    408  
    409         /** 
    410          * <p> 
    411          * Sets the target string manually. 
    412          * </p> 
    413          *  
    414          * @param xmlWindowDescription 
    415          *            target string 
    416          */ 
    417         public void setXmlWindowDescription(String xmlWindowDescription) { 
    418                 this.xmlWindowDescription = xmlWindowDescription; 
    419         } 
    420  
    421         /** 
    422          * <p> 
    423          * Returns the delay after this message during replays. 
    424          * </p> 
    425          *  
    426          * @return delay after this message 
    427          */ 
    428         public int getDelay() { 
    429                 return delay; 
    430         } 
    431  
    432         /** 
    433          * <p> 
    434          * Sets the delay after this message during replays. 
    435          * </p> 
    436          *  
    437          * @param delay 
    438          *            delay after this message 
    439          */ 
    440         public void setDelay(int delay) { 
    441                 this.delay = delay; 
    442         } 
    443  
    444         /** 
    445          * <p> 
    446          * Returns the parent names separated by dots, e.g., "GrandParent.Parent". 
    447          * </p> 
    448          *  
    449          * @return names of the parents 
    450          */ 
    451         public String getParentNames() { 
    452                 return parentNames; 
    453         } 
    454  
    455         /** 
    456          * <p> 
    457          * Returns the window class of the parent. 
    458          * </p> 
    459          *  
    460          * @return window classes of the parents 
    461          */ 
    462         public String getParentClass() { 
    463                 return parentClass; 
    464         } 
    465  
    466         /** 
    467          * <p> 
    468          * Returns the number of parameters stored together with this message. 
    469          * </p> 
    470          *  
    471          * @return number of parameters stored with this message 
    472          */ 
    473         public int getNumParams() { 
    474                 return params.size(); 
    475         } 
    476  
    477         /* 
    478          * (non-Javadoc) 
    479          *  
    480          * @see de.ugoe.cs.quest.eventcore.IReplayable#getReplay() 
    481          */ 
    482         @Override 
    483         public String getReplay() { 
    484                 StringBuilder currentMsgStr = new StringBuilder(400); 
    485                 currentMsgStr.append("  <msg type=\"" + type + "\" "); 
    486                 currentMsgStr.append("LPARAM=\"" + LPARAM + "\" "); 
    487                 currentMsgStr.append("WPARAM=\"" + WPARAM + "\" "); 
    488                 currentMsgStr.append("delay=\"" + delay + "\">"); 
    489                 if (LPARAMasWindowDesc != null) { 
    490                         currentMsgStr.append(StringTools.ENDLINE); 
    491                         currentMsgStr.append("   <LPARAM>"); 
    492                         currentMsgStr.append(StringTools.ENDLINE); 
    493                         currentMsgStr.append(LPARAMasWindowDesc); 
    494                         currentMsgStr.append(StringTools.ENDLINE); 
    495                         currentMsgStr.append("</LPARAM>"); 
    496                 } 
    497                 if (WPARAMasWindowDesc != null) { 
    498                         currentMsgStr.append(StringTools.ENDLINE); 
    499                         currentMsgStr.append("   <WPARAM>"); 
    500                         currentMsgStr.append(StringTools.ENDLINE); 
    501                         currentMsgStr.append(WPARAMasWindowDesc); 
    502                         currentMsgStr.append(StringTools.ENDLINE); 
    503                         currentMsgStr.append("   </WPARAM>"); 
    504                 } 
    505                 currentMsgStr.append(StringTools.ENDLINE); 
    506                 currentMsgStr.append(xmlWindowDescription); 
    507                 currentMsgStr.append(StringTools.ENDLINE); 
    508                 currentMsgStr.append("  </msg>"); 
    509                 currentMsgStr.append(StringTools.ENDLINE); 
    510                 return currentMsgStr.toString(); 
    511         } 
    512  
    513     /* (non-Javadoc) 
    514      * @see de.ugoe.cs.quest.eventcore.IReplayable#getDecorator() 
     45    /** 
     46     * <p> 
     47     * Two {@link WindowsMessage} are equal, if their {@link #type}, {@link #xmlWindowDescription}, 
     48     * and {@link #params} are equal. 
     49     * </p> 
     50     *  
     51     * @see java.lang.Object#equals(java.lang.Object) 
    51552     */ 
    51653    @Override 
    517     public IReplayDecorator getDecorator() { 
    518         return MFCReplayDecorator.getInstance(); 
     54    public boolean equals(Object other) { 
     55        if (other == this) { 
     56            return true; 
     57        } 
     58        boolean isEqual = false; 
     59        if (other instanceof MFCEvent) { 
     60            isEqual = 
     61                ((MFCEvent) other).type == this.type && 
     62                ((MFCEvent) other).target.equals(this.target); 
     63        } 
     64        return isEqual; 
    51965    } 
     66 
     67    /* 
     68     * (non-Javadoc) 
     69     *  
     70     * @see java.lang.Object#hashCode() 
     71     */ 
     72    @Override 
     73    public int hashCode() { 
     74        int multiplier = 17; 
     75        int hash = 42; 
     76 
     77        hash = multiplier * hash + type.hashCode(); 
     78        hash = multiplier * hash + target.hashCode(); 
     79 
     80        return hash; 
     81    } 
     82 
    52083} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/eventcore/MFCEventType.java

    r566 r619  
    1  
     1// Module    : $RCSfile: MFCEventType.java,v $ 
     2// Version   : $Revision: 0.0 $  $Author: pharms $  $Date: 21.08.2012 $ 
     3// Project   : quest-plugin-mfc 
     4// Creation  : 2012 by pharms 
     5// Copyright : Patrick Harms, 2012 
    26package de.ugoe.cs.quest.plugin.mfc.eventcore; 
    37 
     
    913 * </p> 
    1014 *  
    11  * @version $Revision: $ $Date: Aug 17, 2012$ 
    12  * @author 2012, last modified by $Author: sherbold$ 
     15 * @version $Revision: $ $Date: 21.08.2012$ 
     16 * @author 2012, last modified by $Author: pharms$ 
    1317 */ 
    1418public class MFCEventType implements IEventType { 
    1519 
    16     /**  */ 
     20    /** */ 
    1721    private static final long serialVersionUID = 1L; 
     22     
     23    /** */ 
     24    private WindowsMessageType messageType; 
    1825 
    19     private final String typeString; 
    20      
    21     private String info = null; 
    22  
    23     public MFCEventType(String typeString) { 
    24         this.typeString = typeString; 
    25     } 
    26      
    27     public void setInfo(String info) { 
    28         this.info = info; 
     26    /** 
     27     * <p> 
     28     * TODO: comment 
     29     * </p> 
     30     * 
     31     * @param currentMessageType 
     32     */ 
     33    public MFCEventType(WindowsMessageType messageType) { 
     34        this.messageType = messageType; 
    2935    } 
    3036 
    31     /* 
    32      * (non-Javadoc) 
    33      *  
     37    /* (non-Javadoc) 
    3438     * @see de.ugoe.cs.quest.eventcore.IEventType#getName() 
    3539     */ 
    3640    @Override 
    3741    public String getName() { 
    38         return "MFCEventType"; 
    39     } 
    40  
    41     /* 
    42      * (non-Javadoc) 
    43      *  
    44      * @see java.lang.Object#toString() 
    45      */ 
    46     @Override 
    47     public String toString() { 
    48         String str = typeString; 
    49         if( info!=null ) { 
    50             str += "." + info; 
    51         } 
    52         return str; 
     42        return messageType.name(); 
    5343    } 
    5444 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/eventcore/WindowsMessage.java

    r566 r619  
     1 
    12package de.ugoe.cs.quest.plugin.mfc.eventcore; 
    23 
    3 import java.security.InvalidParameterException; 
    44import java.util.HashMap; 
    55import java.util.Map; 
    66 
    7 import de.ugoe.cs.quest.IReplayDecorator; 
    8 import de.ugoe.cs.quest.eventcore.IReplayable; 
    9 import de.ugoe.cs.quest.plugin.mfc.MFCReplayDecorator; 
    10 import de.ugoe.cs.util.StringTools; 
     7import de.ugoe.cs.quest.plugin.mfc.guimodel.MFCGUIElement; 
    118 
    129/** 
    1310 * <p> 
    14  * Contains all informations about a windows message, i.e., all parameters that 
    15  * are read when a windows message is parsed as well as its target, hwnd, etc. 
     11 * Contains all informations about a windows message, i.e., all parameters that are read when a 
     12 * windows message is parsed as well as its target, hwnd, etc. 
    1613 * </p> 
    1714 *  
     
    2017 *  
    2118 */ 
    22 public class WindowsMessage implements IReplayable { 
    23  
    24         /** 
    25          * <p> 
    26          * Id for object serialization. 
    27          * </p> 
    28          */ 
    29         private static final long serialVersionUID = 1L; 
    30  
    31         /** 
    32          * <p> 
    33          * Type of the message. 
    34          * </p> 
    35          */ 
    36         final int type; 
    37  
    38         /** 
    39          * <p> 
    40          * Window class of the message target. Default: "" 
    41          * </p> 
    42          */ 
    43         private String windowClass = ""; 
    44  
    45         /** 
    46          * <p> 
    47          * Resource Id of the message target. Default: 0 
    48          * </p> 
    49          */ 
    50         private int resourceId = 0; 
    51  
    52         /** 
    53          * <p> 
    54          * XML representation of the message target. 
    55          * </p> 
    56          */ 
    57         private String xmlWindowDescription = ""; 
    58  
    59         /** 
    60          * <p> 
    61          * String that contains the names of all parent widgets and itself, separated by dots, 
    62          * e.g., "GrandParent.Parent.self". 
    63          * </p> 
    64          */ 
    65         private String parentNames = null; 
    66  
    67         /** 
    68          * <p> 
    69          * String that contains the window class of the parent widget. 
    70          * </p> 
    71          */ 
    72         private String parentClass = null; 
    73  
    74         /** 
    75          * <p> 
    76          * LPARAM of the message. Default: 0 
    77          * </p> 
    78          */ 
    79         private long LPARAM = 0; 
    80  
    81         /** 
    82          * <p> 
    83          * WPARAM of the message. Default: 0 
    84          * </p> 
    85          */ 
    86         private long WPARAM = 0; 
    87  
    88         /** 
    89          * <p> 
    90          * If the LPARAM contains a HWND, this string stores the target of the HWND. 
    91          * </p> 
    92          */ 
    93         private String LPARAMasWindowDesc = null; 
    94  
    95         /** 
    96          * <p> 
    97          * If the WPARAM contains a HWND, this string stores the target of the HWND. 
    98          * </p> 
    99          */ 
    100         private String WPARAMasWindowDesc = null; 
    101  
    102         /** 
    103          * <p> 
    104          * Delay after sending the messages during a replay. Default: 0 
    105          * </p> 
    106          */ 
    107         private int delay = 0; 
    108  
    109         /** 
    110          * <p> 
    111          * A map of all parameters, associated with the message, created during the 
    112          * parsing of messages from the logs {@code param}-nodes. 
    113          * </p> 
    114          */ 
    115         private Map<String, String> params = new HashMap<String, String>(); 
    116  
    117         /** 
    118          * <p> 
    119          * Constructor. Creates a new message with a given message type. 
    120          * </p> 
    121          *  
    122          * @param type 
    123          *            type of the message 
    124          */ 
    125         public WindowsMessage(int type) { 
    126                 this.type = type; 
    127         } 
    128  
    129         /** 
    130          * <p> 
    131          * Adds a parameter to the message. 
    132          * </p> 
    133          *  
    134          * @param type 
    135          *            type descriptor of the parameter 
    136          * @param value 
    137          *            value of the parameter 
    138          */ 
    139         public void addParameter(String type, String value) { 
    140                 params.put(type, value); 
    141                 if (type.equals("LPARAM")) { 
    142                         LPARAM = Long.parseLong(value); 
    143                 } else if (type.equals("WPARAM")) { 
    144                         WPARAM = Long.parseLong(value); 
    145                 } 
    146         } 
    147  
    148         /** 
    149          * <p> 
    150          * Returns the type of the message. 
    151          * </p> 
    152          *  
    153          * @return type of the message 
    154          */ 
    155         public int getType() { 
    156                 return type; 
    157         } 
    158  
    159         /** 
    160          * <p> 
    161          * Returns the value of a parameter, given its type. If the parameter is not 
    162          * found, {@code null} is returned. 
    163          * </p> 
    164          *  
    165          * @param type 
    166          *            type of the parameter 
    167          * @return value of the parameter 
    168          */ 
    169         public String getParameter(String type) { 
    170                 return params.get(type); 
    171         } 
    172  
    173         /** 
    174          * <p> 
    175          * Returns the window class of the message target. 
    176          * </p> 
    177          *  
    178          * @return window class of the message target 
    179          */ 
    180         public String getWindowClass() { 
    181                 return windowClass; 
    182         } 
    183  
    184         /** 
    185          * <p> 
    186          * Returns the HWND the message is addressed to. 
    187          * </p> 
    188          *  
    189          * @return HWND the message is addressed to 
    190          */ 
    191         public int getHwnd() { 
    192                 int hwnd = -1; 
    193                 String hwndString = getParameter("window.hwnd"); // possible, as 
    194                                                                                                                         // "window.hwnd" is 
    195                                                                                                                         // mandatory 
    196                 if (hwndString != null) { 
    197                         hwnd = Integer.parseInt(hwndString); 
    198                 } 
    199                 return hwnd; 
    200         } 
    201  
    202         /** 
    203          * <p> 
    204          * Returns the resource Id of the message target. 
    205          * </p> 
    206          *  
    207          * @return resource Id of the message target 
    208          */ 
    209         public int getWindowResourceId() { 
    210                 return resourceId; 
    211         } 
    212  
    213         /** 
    214          * <p> 
    215          * Two {@link WindowsMessage} are equal, if their {@link #type}, 
    216          * {@link #xmlWindowDescription}, and {@link #params} are equal. 
    217          * </p> 
    218          *  
    219          * @see java.lang.Object#equals(java.lang.Object) 
    220          */ 
    221         @Override 
    222         public boolean equals(Object other) { 
    223                 if (other == this) { 
    224                         return true; 
    225                 } 
    226                 boolean isEqual = false; 
    227                 if (other instanceof WindowsMessage) { 
    228                         isEqual = ((WindowsMessage) other).type == this.type 
    229                                         && ((WindowsMessage) other).xmlWindowDescription 
    230                                                         .equals(this.xmlWindowDescription) 
    231                                         && ((WindowsMessage) other).params.equals(this.params); 
    232                 } 
    233                 return isEqual; 
    234         } 
    235  
    236         /* 
    237          * (non-Javadoc) 
    238          *  
    239          * @see java.lang.Object#hashCode() 
    240          */ 
    241         @Override 
    242         public int hashCode() { 
    243                 int multiplier = 17; 
    244                 int hash = 42; 
    245  
    246                 hash = multiplier * hash + type; 
    247                 hash = multiplier * hash + xmlWindowDescription.hashCode(); 
    248                 hash = multiplier * hash + params.hashCode(); 
    249  
    250                 return hash; 
    251         } 
    252  
    253         /** 
    254          * <p> 
    255          * Returns a string representation of the message of the form 
    256          * "msg[target=HWND;type=TYPE]". 
    257          * </p> 
    258          *  
    259          * @see java.lang.Object#toString() 
    260          */ 
    261         @Override 
    262         public String toString() { 
    263                 return "msg[target=" + getParameter("window.hwnd") + ";type=" + type 
    264                                 + "]"; 
    265         } 
    266  
    267         /** 
    268          * <p> 
    269          * Retrieves the target string of a message from a given {@link WindowTree} 
    270          * through looking up the HWND the message is addressed to in the window 
    271          * tree. 
    272          * </p> 
    273          *  
    274          * @param windowTree 
    275          *            {@link WindowTree} from which the target is extracted 
    276          * @throws InvalidParameterException 
    277          *             thrown if HWND is not contained in windowTree 
    278          */ 
    279         public void setTarget(WindowTree windowTree) 
    280                         throws InvalidParameterException { 
    281                 int hwnd = Integer.parseInt(getParameter("window.hwnd")); 
    282                 WindowTreeNode node = windowTree.find(hwnd); 
    283                 if (node == null) { 
    284                         throw new InvalidParameterException("No window with HWND " + hwnd 
    285                                         + " found in window tree!"); 
    286                 } else { 
    287                         windowClass = node.getClassName(); 
    288                         resourceId = node.getResourceId(); 
    289                         xmlWindowDescription = node.xmlRepresentation(); 
    290                         parentNames = node.getParentNames(); 
    291                         WindowTreeNode parent = node.getParent(); 
    292                         if (parent == null) { 
    293                                 parentClass = ""; 
    294                         } else { 
    295                                 parentClass = parent.getClassName(); 
    296                         } 
    297                 } 
    298         } 
    299  
    300         /** 
    301          * <p> 
    302          * Sets the LPARAM of a message. 
    303          * </p> 
    304          *  
    305          * @param paramValue 
    306          *            value of the LPARAM 
    307          */ 
    308         public void setLPARAM(long paramValue) { 
    309                 LPARAM = paramValue; 
    310         } 
    311  
    312         /** 
    313          * <p> 
    314          * Sets the WPARAM of a message. 
    315          * </p> 
    316          *  
    317          * @param paramValue 
    318          *            value of the WPARAM 
    319          */ 
    320         public void setWPARAM(long paramValue) { 
    321                 WPARAM = paramValue; 
    322         } 
    323  
    324         /** 
    325          * <p> 
    326          * Returns the LPARAM of a message. 
    327          * </p> 
    328          *  
    329          * @return LPARAM of the message 
    330          */ 
    331         public long getLPARAM() { 
    332                 return LPARAM; 
    333         } 
    334  
    335         /** 
    336          * <p> 
    337          * Returns the WPARAM of a message. 
    338          * </p> 
    339          *  
    340          * @return WPARAM of the message 
    341          */ 
    342         public long getWPARAM() { 
    343                 return WPARAM; 
    344         } 
    345  
    346         /** 
    347          * <p> 
    348          * If the LPARAM contains a HWND, this function can be used to set a target 
    349          * string to identify the HWND at run-time. 
    350          * </p> 
    351          *  
    352          * @param windowDesc 
    353          *            target string 
    354          */ 
    355         public void setLPARAMasWindowDesc(String windowDesc) { 
    356                 LPARAMasWindowDesc = windowDesc; 
    357         } 
    358  
    359         /** 
    360          * <p> 
    361          * If the WPARAM contains a HWND, this function can be used to set a target 
    362          * string to identify the HWND at run-time. 
    363          * </p> 
    364          *  
    365          * @param windowDesc 
    366          *            target string 
    367          */ 
    368         public void setWPARAMasWindowDesc(String windowDesc) { 
    369                 WPARAMasWindowDesc = windowDesc; 
    370         } 
    371  
    372         /** 
    373          * <p> 
    374          * If the LPARAM contains a HWND and the target string for the HWND is set, 
    375          * this function returns the target string. Otherwise, {@code null} is 
    376          * returned. 
    377          * </p> 
    378          *  
    379          * @return target string if available; {@code null} otherwise 
    380          */ 
    381         public String getLPARAMasWindowDesc() { 
    382                 return LPARAMasWindowDesc; 
    383         } 
    384  
    385         /** 
    386          * <p> 
    387          * If the WPARAM contains a HWND and the target string for the HWND is set, 
    388          * this function returns the target string. Otherwise, {@code null} is 
    389          * returned. 
    390          * </p> 
    391          *  
    392          * @return target string if available; {@code null} otherwise 
    393          */ 
    394         public String getWPARAMasWindowDesc() { 
    395                 return WPARAMasWindowDesc; 
    396         } 
    397  
    398         /** 
    399          * <p> 
    400          * Returns the target string of the message. 
    401          * </p> 
    402          *  
    403          * @return target string of the message 
    404          */ 
    405         public String getXmlWindowDescription() { 
    406                 return xmlWindowDescription; 
    407         } 
    408  
    409         /** 
    410          * <p> 
    411          * Sets the target string manually. 
    412          * </p> 
    413          *  
    414          * @param xmlWindowDescription 
    415          *            target string 
    416          */ 
    417         public void setXmlWindowDescription(String xmlWindowDescription) { 
    418                 this.xmlWindowDescription = xmlWindowDescription; 
    419         } 
    420  
    421         /** 
    422          * <p> 
    423          * Returns the delay after this message during replays. 
    424          * </p> 
    425          *  
    426          * @return delay after this message 
    427          */ 
    428         public int getDelay() { 
    429                 return delay; 
    430         } 
    431  
    432         /** 
    433          * <p> 
    434          * Sets the delay after this message during replays. 
    435          * </p> 
    436          *  
    437          * @param delay 
    438          *            delay after this message 
    439          */ 
    440         public void setDelay(int delay) { 
    441                 this.delay = delay; 
    442         } 
    443  
    444         /** 
    445          * <p> 
    446          * Returns the parent names separated by dots, e.g., "GrandParent.Parent". 
    447          * </p> 
    448          *  
    449          * @return names of the parents 
    450          */ 
    451         public String getParentNames() { 
    452                 return parentNames; 
    453         } 
    454  
    455         /** 
    456          * <p> 
    457          * Returns the window class of the parent. 
    458          * </p> 
    459          *  
    460          * @return window classes of the parents 
    461          */ 
    462         public String getParentClass() { 
    463                 return parentClass; 
    464         } 
    465  
    466         /** 
    467          * <p> 
    468          * Returns the number of parameters stored together with this message. 
    469          * </p> 
    470          *  
    471          * @return number of parameters stored with this message 
    472          */ 
    473         public int getNumParams() { 
    474                 return params.size(); 
    475         } 
    476  
    477         /* 
    478          * (non-Javadoc) 
    479          *  
    480          * @see de.ugoe.cs.quest.eventcore.IReplayable#getReplay() 
    481          */ 
    482         @Override 
    483         public String getReplay() { 
    484                 StringBuilder currentMsgStr = new StringBuilder(400); 
    485                 currentMsgStr.append("  <msg type=\"" + type + "\" "); 
    486                 currentMsgStr.append("LPARAM=\"" + LPARAM + "\" "); 
    487                 currentMsgStr.append("WPARAM=\"" + WPARAM + "\" "); 
    488                 currentMsgStr.append("delay=\"" + delay + "\">"); 
    489                 if (LPARAMasWindowDesc != null) { 
    490                         currentMsgStr.append(StringTools.ENDLINE); 
    491                         currentMsgStr.append("   <LPARAM>"); 
    492                         currentMsgStr.append(StringTools.ENDLINE); 
    493                         currentMsgStr.append(LPARAMasWindowDesc); 
    494                         currentMsgStr.append(StringTools.ENDLINE); 
    495                         currentMsgStr.append("</LPARAM>"); 
    496                 } 
    497                 if (WPARAMasWindowDesc != null) { 
    498                         currentMsgStr.append(StringTools.ENDLINE); 
    499                         currentMsgStr.append("   <WPARAM>"); 
    500                         currentMsgStr.append(StringTools.ENDLINE); 
    501                         currentMsgStr.append(WPARAMasWindowDesc); 
    502                         currentMsgStr.append(StringTools.ENDLINE); 
    503                         currentMsgStr.append("   </WPARAM>"); 
    504                 } 
    505                 currentMsgStr.append(StringTools.ENDLINE); 
    506                 currentMsgStr.append(xmlWindowDescription); 
    507                 currentMsgStr.append(StringTools.ENDLINE); 
    508                 currentMsgStr.append("  </msg>"); 
    509                 currentMsgStr.append(StringTools.ENDLINE); 
    510                 return currentMsgStr.toString(); 
    511         } 
    512  
    513     /* (non-Javadoc) 
    514      * @see de.ugoe.cs.quest.eventcore.IReplayable#getDecorator() 
     19public class WindowsMessage { 
     20 
     21    /** 
     22     * <p> 
     23     * Type of the message. 
     24     * </p> 
     25     */ 
     26    final WindowsMessageType type; 
     27 
     28    /** 
     29     * <p> 
     30     * LPARAM of the message. Default: 0 
     31     * </p> 
     32     */ 
     33    private long LPARAM = 0; 
     34 
     35    /** 
     36     * <p> 
     37     * WPARAM of the message. Default: 0 
     38     * </p> 
     39     */ 
     40    private long WPARAM = 0; 
     41 
     42    /** 
     43     * <p> 
     44     * A map of all parameters, associated with the message, created during the parsing of messages 
     45     * from the logs {@code param}-nodes. 
     46     * </p> 
     47     */ 
     48    private Map<String, Object> params = new HashMap<String, Object>(); 
     49 
     50    /** 
     51     * <p> 
     52     * the target GUI element to which the message was sent 
     53     * </p> 
     54     */ 
     55    private MFCGUIElement target; 
     56 
     57    /** 
     58     * <p> 
     59     * an XML representation of the target to preserve it as it was when this message was created 
     60     * </p> 
     61     */ 
     62    protected String targetXML; 
     63 
     64    /** 
     65     * <p> 
     66     * Constructor. Creates a new message with a given message type. 
     67     * </p> 
     68     *  
     69     * @param type 
     70     *            type of the message 
     71     * @param currentMessageParameters  
     72     * @param target  
     73     */ 
     74    public WindowsMessage(WindowsMessageType  type, 
     75                          MFCGUIElement       target, 
     76                          Map<String, Object> messageParameters) 
     77    { 
     78        this.type = type; 
     79        setTarget(target); 
     80         
     81        for (Map.Entry<String, Object> entry : messageParameters.entrySet()) { 
     82            addParameter(entry.getKey(), entry.getValue()); 
     83        } 
     84    } 
     85 
     86    /** 
     87     * <p> 
     88     * Constructor. Creates a new message with a given message type. 
     89     * </p> 
     90     *  
     91     * @param type 
     92     *            type of the message 
     93     */ 
     94    public WindowsMessage(WindowsMessageType type) 
     95    { 
     96        this.type = type; 
     97    } 
     98 
     99    /** 
     100     * <p> 
     101     * Adds a parameter to the message. 
     102     * </p> 
     103     *  
     104     * @param type 
     105     *            type descriptor of the parameter 
     106     * @param value 
     107     *            value of the parameter 
     108     */ 
     109    public void addParameter(String type, Object value) { 
     110        params.put(type, value); 
     111        if (type.equals("LPARAM")) { 
     112            LPARAM = (Long) value; 
     113        } 
     114        else if (type.equals("WPARAM")) { 
     115            WPARAM = (Long) value; 
     116        } 
     117    } 
     118 
     119    /** 
     120     * <p> 
     121     * Returns the type of the message. 
     122     * </p> 
     123     *  
     124     * @return type of the message 
     125     */ 
     126    public WindowsMessageType getType() { 
     127        return type; 
     128    } 
     129 
     130    /** 
     131     * <p> 
     132     * TODO: comment 
     133     * </p> 
     134     * 
     135     * @param target2 
     136     */ 
     137    public void setTarget(MFCGUIElement target) { 
     138        this.target = target; 
     139        this.targetXML = target.toXML(); 
     140    } 
     141 
     142    /** 
     143     * <p> 
     144     * TODO: comment 
     145     * </p> 
     146     * 
     147     * @return 
     148     */ 
     149    public MFCGUIElement getTarget() { 
     150        return target; 
     151    } 
     152     
     153    /** 
     154     * <p> 
     155     * Returns the value of a parameter, given its type. If the parameter is not found, {@code null} 
     156     * is returned. 
     157     * </p> 
     158     *  
     159     * @param type 
     160     *            type of the parameter 
     161     * @return value of the parameter 
     162     */ 
     163    public Object getParameter(String type) { 
     164        return params.get(type); 
     165    } 
     166 
     167    /** 
     168     * <p> 
     169     * Two {@link WindowsMessage} are equal, if their {@link #type}, {@link #xmlWindowDescription}, 
     170     * and {@link #params} are equal. 
     171     * </p> 
     172     *  
     173     * @see java.lang.Object#equals(java.lang.Object) 
    515174     */ 
    516175    @Override 
    517     public IReplayDecorator getDecorator() { 
    518         return MFCReplayDecorator.getInstance(); 
    519     } 
     176    public boolean equals(Object other) { 
     177        if (other == this) { 
     178            return true; 
     179        } 
     180        boolean isEqual = false; 
     181        if (other instanceof WindowsMessage) { 
     182            isEqual = 
     183                ((WindowsMessage) other).type == this.type && 
     184                ((WindowsMessage) other).target.equals(this.target) && 
     185                ((WindowsMessage) other).params.equals(this.params); 
     186        } 
     187        return isEqual; 
     188    } 
     189 
     190    /* 
     191     * (non-Javadoc) 
     192     *  
     193     * @see java.lang.Object#hashCode() 
     194     */ 
     195    @Override 
     196    public int hashCode() { 
     197        int multiplier = 17; 
     198        int hash = 42; 
     199 
     200        hash = multiplier * hash + type.hashCode(); 
     201        hash = multiplier * hash + target.hashCode(); 
     202        hash = multiplier * hash + params.hashCode(); 
     203 
     204        return hash; 
     205    } 
     206 
     207    /** 
     208     * <p> 
     209     * Returns a string representation of the message of the form "msg[target=HWND;type=TYPE]". 
     210     * </p> 
     211     *  
     212     * @see java.lang.Object#toString() 
     213     */ 
     214    @Override 
     215    public String toString() { 
     216        return "msg[target=" + getParameter("window.hwnd") + ";type=" + type + "]"; 
     217    } 
     218 
     219    /** 
     220     * <p> 
     221     * Returns the LPARAM of a message. 
     222     * </p> 
     223     *  
     224     * @return LPARAM of the message 
     225     */ 
     226    public long getLPARAM() { 
     227        return LPARAM; 
     228    } 
     229 
     230    /** 
     231     * <p> 
     232     * Returns the WPARAM of a message. 
     233     * </p> 
     234     *  
     235     * @return WPARAM of the message 
     236     */ 
     237    public long getWPARAM() { 
     238        return WPARAM; 
     239    } 
     240 
     241    /** 
     242     * <p> 
     243     * Returns the number of parameters stored together with this message. 
     244     * </p> 
     245     *  
     246     * @return number of parameters stored with this message 
     247     */ 
     248    public int getNumParams() { 
     249        return params.size(); 
     250    } 
     251 
     252    /** 
     253     * <p> 
     254     * TODO: comment 
     255     * </p> 
     256     * 
     257     * @return 
     258     */ 
     259    protected Map<String, Object> getParameters() { 
     260        return params; 
     261    } 
     262 
     263    /** 
     264     * <p> 
     265     * TODO: comment 
     266     * </p> 
     267     * 
     268     * @return 
     269     */ 
     270    public String getTargetXML() { 
     271        return targetXML; 
     272    } 
     273 
    520274} 
  • trunk/quest-plugin-mfc/src/main/java/de/ugoe/cs/quest/plugin/mfc/eventcore/WindowsMessageType.java

    r578 r619  
     1// Module    : $RCSfile: MessageType.java,v $ 
     2// Version   : $Revision: 0.0 $  $Author: Patrick $  $Date: 26.11.2011 14:36:45 $ 
     3// Project   : TaskTreePerformanceTest 
     4// Creation  : 2011 by Patrick 
     5// Copyright : Patrick Harms, 2011 
    16 
    27package de.ugoe.cs.quest.plugin.mfc.eventcore; 
    38 
    4 import de.ugoe.cs.quest.eventcore.IEventType; 
    5  
    69/** 
    7  * <p> 
    810 * TODO comment 
    9  * </p> 
    1011 *  
    11  * @version $Revision: $ $Date: Aug 17, 2012$ 
    12  * @author 2012, last modified by $Author: sherbold$ 
     12 * @version $Revision: $ $Date: $ 
     13 * @author 2011, last modified by $Author: $ 
    1314 */ 
    14 public class MFCEventType implements IEventType { 
    15  
    16     /**  */ 
    17     private static final long serialVersionUID = 1L; 
    18  
    19     private final String typeString; 
     15public enum WindowsMessageType { 
    2016     
    21     private String info = null; 
    22  
    23     public MFCEventType(String typeString) { 
    24         this.typeString = typeString; 
    25     } 
    26      
    27     public void setInfo(String info) { 
    28         this.info = info; 
    29     } 
    30  
    31     /* 
    32      * (non-Javadoc) 
     17    WM_NULL(0), 
     18    WM_CREATE(1), 
     19    WM_DESTROY(2), 
     20    WM_MOVE(3), 
     21    WM_SIZE(5), 
     22    WM_ACTIVATE(6), 
     23    WM_SETFOCUS(7), 
     24    WM_KILLFOCUS(8), 
     25    WM_ENABLE(10), 
     26    WM_SETREDRAW(11), 
     27    WM_SETTEXT(12), 
     28    WM_GETTEXT(13), 
     29    WM_GETTEXTLENGTH(14), 
     30    WM_PAINT(15), 
     31    WM_CLOSE(16), 
     32    WM_QUERYENDSESSION(17), 
     33    WM_QUIT(18), 
     34    WM_QUERYOPEN(19), 
     35    WM_ERASEBKGND(20), 
     36    WM_SYSCOLORCHANGE(21), 
     37    WM_ENDSESSION(22), 
     38    WM_SHOWWINDOW(24), 
     39    WM_CTLCOLOR(25), 
     40    WM_WININICHANGE(26), 
     41    WM_DEVMODECHANGE(27), 
     42    WM_ACTIVATEAPP(28), 
     43    WM_FONTCHANGE(29), 
     44    WM_TIMECHANGE(30), 
     45    WM_CANCELMODE(31), 
     46    WM_SETCURSOR(32), 
     47    WM_MOUSEACTIVATE(33), 
     48    WM_CHILDACTIVATE(34), 
     49    WM_QUEUESYNC(35), 
     50    WM_GETMINMAXINFO(36), 
     51    WM_PAINTICON(38), 
     52    WM_ICONERASEBKGND(39), 
     53    WM_NEXTDLGCTL(40), 
     54    WM_SPOOLERSTATUS(42), 
     55    WM_DRAWITEM(43), 
     56    WM_MEASUREITEM(44), 
     57    WM_DELETEITEM(45), 
     58    WM_VKEYTOITEM(46), 
     59    WM_CHARTOITEM(47), 
     60    WM_SETFONT(48), 
     61    WM_GETFONT(49), 
     62    WM_SETHOTKEY(50), 
     63    WM_GETHOTKEY(51), 
     64    WM_QUERYDRAGICON(55), 
     65    WM_COMPAREITEM(57), 
     66    WM_GETOBJECT(61), 
     67    WM_COMPACTING(65), 
     68    WM_COMMNOTIFY(68), 
     69    WM_WINDOWPOSCHANGING(70), 
     70    WM_WINDOWPOSCHANGED(71), 
     71    WM_POWER(72), 
     72    WM_COPYDATA(74), 
     73    WM_CANCELJOURNAL(75), 
     74    WM_NOTIFY(78), 
     75    WM_INPUTLANGCHANGEREQUEST(80), 
     76    WM_INPUTLANGCHANGE(81), 
     77    WM_TCARD(82), 
     78    WM_HELP(83), 
     79    WM_USERCHANGED(84), 
     80    WM_NOTIFYFORMAT(85), 
     81    WM_CONTEXTMENU(123), 
     82    WM_STYLECHANGING(124), 
     83    WM_STYLECHANGED(125), 
     84    WM_DISPLAYCHANGE(126), 
     85    WM_GETICON(127), 
     86    WM_SETICON(128), 
     87    WM_NCCREATE(129), 
     88    WM_NCDESTROY(130), 
     89    WM_NCCALCSIZE(131), 
     90    WM_NCHITTEST(132), 
     91    WM_NCPAINT(133), 
     92    WM_NCACTIVATE(134), 
     93    WM_GETDLGCODE(135), 
     94    WM_SYNCPAINT(136), 
     95    WM_NCMOUSEMOVE(160), 
     96    WM_NCLBUTTONDOWN(161), 
     97    WM_NCLBUTTONUP(162), 
     98    WM_NCLBUTTONDBLCLK(163), 
     99    WM_NCRBUTTONDOWN(164), 
     100    WM_NCRBUTTONUP(165), 
     101    WM_NCRBUTTONDBLCLK(166), 
     102    WM_NCMBUTTONDOWN(167), 
     103    WM_NCMBUTTONUP(168), 
     104    WM_NCMBUTTONDBLCLK(169), 
     105    WM_NCXBUTTONDOWN(171), 
     106    WM_NCXBUTTONUP(172), 
     107    WM_NCXBUTTONDBLCLK(173), 
     108    SBM_SETPOS(224), 
     109    BM_CLICK(245), 
     110    WM_INPUT(255), 
     111    WM_KEYDOWN(256), 
     112    WM_KEYFIRST(256), 
     113    WM_KEYUP(257), 
     114    WM_CHAR(258), 
     115    WM_DEADCHAR(259), 
     116    WM_SYSKEYDOWN(260), 
     117    WM_SYSKEYUP(261), 
     118    WM_SYSCHAR(262), 
     119    WM_SYSDEADCHAR(263), 
     120    WM_KEYLAST(264), 
     121    WM_WNT_CONVERTREQUESTEX(265), 
     122    WM_CONVERTREQUEST(266), 
     123    WM_CONVERTRESULT(267), 
     124    WM_INTERIM(268), 
     125    WM_IME_STARTCOMPOSITION(269), 
     126    WM_IME_ENDCOMPOSITION(270), 
     127    WM_IME_COMPOSITION(271), 
     128    WM_IME_KEYLAST(271), 
     129    WM_INITDIALOG(272), 
     130    WM_COMMAND(273), 
     131    WM_SYSCOMMAND(274), 
     132    WM_TIMER(275), 
     133    WM_HSCROLL(276), 
     134    WM_VSCROLL(277), 
     135    WM_INITMENU(278), 
     136    WM_INITMENUPOPUP(279), 
     137    WM_MENUSELECT(287), 
     138    WM_MENUCHAR(288), 
     139    WM_ENTERIDLE(289), 
     140    WM_MENURBUTTONUP(290), 
     141    WM_MENUDRAG(291), 
     142    WM_MENUGETOBJECT(292), 
     143    WM_UNINTMENUPOPUP(293), 
     144    WM_MENUCOMMAND(294), 
     145    WM_CHANGEUISTATE(295), 
     146    WM_UPDATEUISTATE(296), 
     147    WM_QUERYUISTATE(297), 
     148    WM_CTLCOLORMSGBOX(306), 
     149    WM_CTLCOLOREDIT(307), 
     150    WM_CTLCOLORLISTBOX(308), 
     151    WM_CTLCOLORBTN(309), 
     152    WM_CTLCOLORDLG(310), 
     153    WM_CTLCOLORSCROLLBAR(311), 
     154    WM_CTLCOLORSTATIC(312), 
     155    CB_SHOWDROPDOWN(335), 
     156    LB_SETCURSEL(390), 
     157    WM_MOUSEFIRST(512), 
     158    WM_MOUSEMOVE(512), 
     159    WM_LBUTTONDOWN(513), 
     160    WM_LBUTTONUP(514), 
     161    WM_LBUTTONDBLCLK(515), 
     162    WM_RBUTTONDOWN(516), 
     163    WM_RBUTTONUP(517), 
     164    WM_RBUTTONDBLCLK(518), 
     165    WM_MBUTTONDOWN(519), 
     166    WM_MBUTTONUP(520), 
     167    WM_MBUTTONDBLCLK(521), 
     168    WM_MOUSELAST(521), 
     169    WM_MOUSEWHEEL(522), 
     170    WM_XBUTTONDOWN(523), 
     171    WM_XBUTTONUP(524), 
     172    WM_XBUTTONDBLCLK(525), 
     173    WM_USER(1024), 
     174    CB_SETCURSEL(334), 
     175    TBM_SETPOS(1029), 
     176    UDM_SETRANGE(1125), 
     177    TCM_SETCURSEL(4876); 
     178 
     179    /** the numerical representation of the message type */ 
     180    private int mNumber; 
     181 
     182    /** 
     183     * @param number 
     184     */ 
     185    WindowsMessageType(int number) { 
     186        mNumber = number; 
     187    } 
     188 
     189    /** 
     190     * @return Returns the number. 
     191     */ 
     192    public int getNumber() { 
     193        return mNumber; 
     194    } 
     195 
     196    /** 
     197     * <p> 
     198     * Checks if the type of a message generated is a keyboard interaction. 
     199     * </p> 
    33200     *  
    34      * @see de.ugoe.cs.quest.eventcore.IEventType#getName() 
    35      */ 
    36     @Override 
    37     public String getName() { 
    38         return "MFCEventType"; 
    39     } 
    40  
    41     /* 
    42      * (non-Javadoc) 
     201     * @param msgType 
     202     *            type of the message 
     203     * @return true if it is a keyboard interaction; false otherwise 
     204     */ 
     205    public boolean isKeyMessage() { 
     206        boolean isKeyMsg = false; 
     207        switch (this) 
     208        { 
     209            case WM_KEYDOWN: 
     210            case WM_KEYUP: 
     211            case WM_SYSKEYDOWN: 
     212            case WM_SYSKEYUP: 
     213                isKeyMsg = true; 
     214                break; 
     215            default: 
     216                break; 
     217        } 
     218        return isKeyMsg; 
     219    } 
     220 
     221    /** 
     222     * <p> 
     223     * Checks if the type of a message indicates that the mouse has been pressed down. 
     224     * </p> 
    43225     *  
    44      * @see java.lang.Object#toString() 
    45      */ 
    46     @Override 
    47     public String toString() { 
    48         String str = typeString; 
    49         if( info!=null ) { 
    50             str += "." + info; 
    51         } 
    52         return str; 
    53     } 
    54  
     226     * @param msgType 
     227     *            type of the message 
     228     * @return true if it is mouse-down message; false otherwise 
     229     */ 
     230    public boolean isDownMessage() { 
     231        boolean isDownMsg = false; 
     232        switch (this) 
     233        { 
     234            case WM_LBUTTONDOWN: 
     235            case WM_RBUTTONDOWN: 
     236            case WM_MBUTTONDOWN: 
     237            case WM_XBUTTONDOWN: 
     238            case WM_NCLBUTTONDOWN: 
     239            case WM_NCRBUTTONDOWN: 
     240            case WM_NCMBUTTONDOWN: 
     241            case WM_NCXBUTTONDOWN: 
     242                isDownMsg = true; 
     243                break; 
     244            default: 
     245                break; 
     246        } 
     247        return isDownMsg; 
     248    } 
     249 
     250    /** 
     251     * <p> 
     252     * Checks if the type of a message indicates that a double click has been performed. 
     253     * </p> 
     254     *  
     255     * @param msgType 
     256     *            type of the message 
     257     * @return true if it is a double click message; false otherwise 
     258     */ 
     259    public boolean isDblclkMessage() { 
     260        boolean isDblclkMsg = false; 
     261        switch (this) 
     262        { 
     263            case WM_LBUTTONDBLCLK: 
     264            case WM_RBUTTONDBLCLK: 
     265            case WM_MBUTTONDBLCLK: 
     266            case WM_XBUTTONDBLCLK: 
     267            case WM_NCLBUTTONDBLCLK: 
     268            case WM_NCRBUTTONDBLCLK: 
     269            case WM_NCMBUTTONDBLCLK: 
     270            case WM_NCXBUTTONDBLCLK: 
     271                isDblclkMsg = true; 
     272                break; 
     273            default: 
     274                break; 
     275        } 
     276        return isDblclkMsg; 
     277    } 
     278 
     279    /** 
     280     * <p> 
     281     * Checks if the type of a message indicates that the mouse has been released. 
     282     * </p> 
     283     *  
     284     * @param msgType 
     285     *            type of the message 
     286     * @return true if it is mouse-up message; false otherwise 
     287     */ 
     288    public boolean isUpMessage() { 
     289        boolean isUpMsg = false; 
     290        switch (this) 
     291        { 
     292            case WM_LBUTTONUP: 
     293            case WM_RBUTTONUP: 
     294            case WM_MBUTTONUP: 
     295            case WM_XBUTTONUP: 
     296            case WM_NCLBUTTONUP: 
     297            case WM_NCRBUTTONUP: 
     298            case WM_NCMBUTTONUP: 
     299            case WM_NCXBUTTONUP: 
     300                isUpMsg = true; 
     301                break; 
     302            default: 
     303                break; 
     304        } 
     305        return isUpMsg; 
     306    } 
     307 
     308    /** 
     309     * 
     310     */ 
     311    public static WindowsMessageType parseMessageType(String numberString) { 
     312        try { 
     313            int number = Integer.parseInt(numberString); 
     314            return valueOf(number); 
     315        } 
     316        catch (NumberFormatException e) { 
     317            return WindowsMessageType.valueOf(WindowsMessageType.class, numberString); 
     318        } 
     319    } 
     320 
     321    /** 
     322     * 
     323     */ 
     324    public static WindowsMessageType valueOf(int number) { 
     325        for (WindowsMessageType type : WindowsMessageType.values()) { 
     326            if (type.mNumber == number) { 
     327                return type; 
     328            } 
     329        } 
     330 
     331        throw new IllegalArgumentException("there is no message type with number " + number); 
     332    } 
    55333} 
  • 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.