Ignore:
Timestamp:
01/24/14 13:49:01 (11 years ago)
Author:
pharms
Message:
  • introduced common groups when condensing an HTML GUI model
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java

    r1286 r1334  
    1515package de.ugoe.cs.autoquest.plugin.html.commands; 
    1616 
     17import java.io.PrintStream; 
    1718import java.util.Arrays; 
    1819import java.util.Comparator; 
     
    7374 *         \-- html 
    7475 *               \-- body 
    75  *                     |-- div (id = menu) 
    76  *                     |     \-- ... 
     76 *                     |-- group (common) 
     77 *                     |     |-- div (id = menu) 
     78 *                     |     |     \-- ... 
     79 *                     |     \-- div (id = footer) 
     80 *                     |           \-- ... 
    7781 *                     |-- group (document1) 
    7882 *                     |     \-- div (id = textcontent) 
     
    8185 *                     |     \-- div (id = imagecontent) 
    8286 *                     |           \-- ... 
    83  *                     \-- div (id = footer) 
    84  *                           \-- ... 
    8587 * </pre> 
    8688 * This now allows the menu and the footer to be treated as identical over several pages. 
     
    146148        GUIElementsCluster rootCluster = getSimilarElementClusterHierarchy(server, model); 
    147149 
    148         //rootCluster.dump(System.out, ""); 
    149              
    150         Console.traceln(Level.FINE, "merging GUI elements in same clusters and creating groups"); 
    151         mergeGUIElementsAccordingToClusters(rootCluster, model, ""); 
     150        rootCluster.dump(System.out, ""); 
     151             
     152        Console.traceln(Level.FINE, "grouping GUI elements according to clusters"); 
     153        groupGUIElementsAccordingToClusters(rootCluster, model, ""); 
    152154             
    153155        //model.dump(System.out, "UTF-8"); 
     
    157159    /** 
    158160     * <p> 
    159      * determines clusters of similar GUI elements being children of the provided parent. For this, 
    160      * the method creates a cluster containing all children of the provided parent as similar 
    161      * GUI elements. Usually, these are all documents on the same server. It then initiates 
    162      * creating the cluster hierarchy by calling the recursive method 
     161     * determines clusters of similar GUI elements being children of the provided server. For this, 
     162     * the method creates a cluster containing all children of the provided server as similar 
     163     * GUI elements. Usually, these are all documents on the server. It then initiates creating 
     164     * the cluster hierarchy by calling the recursive method 
    163165     * {@link #addChildClusters(GUIElementsCluster, GUIModel, String)}. 
    164166     * </p> 
    165167     * 
    166      * @param parent the parent GUI element for which the clusters of similar children shall be 
    167      *               determined (usually an HTML server) 
     168     * @param server the server for which the clusters of similar children shall be determined 
    168169     * @param model  the GUI model required for identifying children and sub children 
    169170     *  
    170      * @return a list of GUI element clusters of the children. 
    171      */ 
    172     private GUIElementsCluster getSimilarElementClusterHierarchy(IGUIElement parent, GUIModel model) 
     171     * @return a GUI element cluster representing the server. 
     172     */ 
     173    private GUIElementsCluster getSimilarElementClusterHierarchy(HTMLServer server, GUIModel model) 
    173174    { 
    174175        GUIElementsCluster cluster = new GUIElementsCluster(); 
    175176         
    176         List<IGUIElement> children = model.getChildren(parent); 
     177        List<IGUIElement> children = model.getChildren(server); 
    177178         
    178179        SimilarGUIElements similarGuiElements = new SimilarGUIElements(); 
    179180         
    180181        for (IGUIElement child : children) { 
    181             // when starting with the root, the cluster parent is the child itself 
     182            // when starting with the root, the cluster parent is the child itself, i.e. the 
     183            // document. We expect all documents to be similar. 
    182184            similarGuiElements.add(new SimilarGUIElement(child, child)); 
    183185        } 
    184186         
    185187        cluster.addSimilarGUIElements(similarGuiElements); 
     188         
     189        // create the cluster structure 
    186190        addChildClusters(cluster, model, ""); 
    187191         
     
    209213        } 
    210214         
    211         createClusterHierachies(cluster.childClusters); 
     215        createClusterHierachies(cluster); 
    212216    } 
    213217     
     
    216220     * for a set of similar GUI elements, it identifies similar children and clusters them. For 
    217221     * each identified cluster, it adds a new child cluster to the provided parent cluster. GUI 
    218      * elements having no further children are added to a default cluster. 
     222     * elements having no further children are ignored. 
    219223     * </p> 
    220224     * 
     
    235239                for (IGUIElement child : children) { 
    236240                    addToClusterOfSimilarElements 
    237                         (child, similarGuiElement.mainClusterParent, parentCluster.childClusters, 
     241                        (child, similarGuiElement.mainClusterParent, parentCluster, 
    238242                         similarGuiElements, model); 
    239243                } 
    240244            } 
    241             else { 
    242                 // search for a default cluster to add all elements to, which have no children 
    243                 GUIElementsCluster defaultCluster = null; 
    244                  
    245                 for (GUIElementsCluster candidate : parentCluster.childClusters) { 
    246                     if (candidate.similarChildrenGUIElements.size() == 0) { 
    247                         defaultCluster = candidate; 
    248                         break; 
    249                     } 
    250                 } 
    251                  
    252                 if (defaultCluster == null) { 
    253                     defaultCluster = new GUIElementsCluster(); 
    254                     parentCluster.addChildCluster(defaultCluster); 
    255                 } 
    256                  
    257                 defaultCluster.clusteredGUIElements.add(similarGuiElement); 
    258             } 
    259         } 
    260     } 
    261  
    262     /** 
    263      * <p> 
    264      * for a given GUI element, searches the list of known clusters and adds the GUI element to 
    265      * the cluster, if the cluster already contains a similar GUI element. If not, a new cluster is 
    266      * created and added to the list of known clusters. 
     245        } 
     246    } 
     247 
     248    /** 
     249     * <p> 
     250     * for a given GUI element, searches the list of child clusters of the parent cluster and adds 
     251     * the GUI element to the cluster, if the cluster already contains a similar GUI element. If 
     252     * not, a new cluster is created and added to the list of known clusters. 
    267253     * </p> 
    268254     * 
    269      * @param child         the child for which the cluster is to be determined 
    270      * @param clusterParent the GUI element for  
    271      * @param parents 
    272      * @param model 
    273      */ 
    274     private void addToClusterOfSimilarElements(IGUIElement              child, 
    275                                                IGUIElement              clusterParent, 
    276                                                List<GUIElementsCluster> knownClusters, 
    277                                                SimilarGUIElements       similarGuiElements, 
    278                                                GUIModel                 model) 
     255     * @param child              the child for which the cluster is to be determined 
     256     * @param clusterParent      the root GUI element of the parent cluster 
     257     * @param parentCluster      the parent cluster whose child clusters shall be filled 
     258     * @param similarGuiElements the similar GUI elements currently matched to each other 
     259     * @param model              the GUI model required to determine children of GUI elements 
     260     */ 
     261    private void addToClusterOfSimilarElements(IGUIElement        child, 
     262                                               IGUIElement        clusterParent, 
     263                                               GUIElementsCluster parentCluster, 
     264                                               SimilarGUIElements similarGuiElements, 
     265                                               GUIModel           model) 
    279266    { 
    280267        SimilarGUIElements matchingParents = new SimilarGUIElements(); 
     
    294281        GUIElementsCluster cluster = null; 
    295282         
    296         for (GUIElementsCluster clusterCandidate : knownClusters) { 
     283        for (GUIElementsCluster clusterCandidate : parentCluster.childClusters) { 
    297284            if (clusterCandidate.isClusterOf(matchingParents)) { 
    298285                cluster = clusterCandidate; 
     
    303290        if (cluster == null) { 
    304291            cluster = new GUIElementsCluster(); 
    305             knownClusters.add(cluster); 
     292            parentCluster.addChildCluster(cluster); 
    306293            cluster.setClusteredGUIElements(matchingParents); 
    307294        } 
     
    315302     * each other. This is, e.g., the case if one cluster contains all elements being part of 
    316303     * document1 and document2 and a further cluster contains all elements of document 1 only. In 
    317      * this case, the cluster of document1 is added as a child to the other cluster. 
     304     * this case, the cluster of document1 is added as a child to the other cluster. In this case 
     305     * it is furthermore required, that a common cluster as child of the document1/document2 cluster 
     306     * is created carrying the common GUI elements for both clusters. 
    318307     * </p> 
    319308     * 
    320      * @param clusters the clusters, for which the child hierarchies shall be created 
    321      *                 (in-out parameter, as it is changed) 
    322      */ 
    323     private void createClusterHierachies(List<GUIElementsCluster> clusters) { 
    324         GUIElementsCluster[] clustersCopy = 
    325             clusters.toArray(new GUIElementsCluster[clusters.size()]); 
     309     * @param parentCluster the parent cluster for whose children the child hierarchies shall be 
     310     *                      created (in-out parameter, as it is changed) 
     311     */ 
     312    private void createClusterHierachies(GUIElementsCluster parentCluster) { 
     313        GUIElementsCluster[] clustersCopy = parentCluster.childClusters.toArray 
     314            (new GUIElementsCluster[parentCluster.childClusters.size()]); 
    326315         
    327316        // sort the array starting with the shortest cluster and ending with the longest 
     
    333322        }); 
    334323         
    335         List<GUIElementsCluster> subClustersToHandle = new LinkedList<GUIElementsCluster>(); 
     324        Set<GUIElementsCluster> subClustersToHandle = new HashSet<GUIElementsCluster>(); 
    336325         
    337326        // now add smaller clusters to larger ones, if they are parents 
     
    346335                    subClustersToHandle.add(clustersCopy[j]); 
    347336                     
    348                     for (int k = 0; k < clusters.size(); k++) { 
    349                         if (clusters.get(k) == potentialChild) { 
    350                             clusters.remove(k); 
     337                    for (int k = 0; k < parentCluster.childClusters.size(); k++) { 
     338                        if (parentCluster.childClusters.get(k) == potentialChild) { 
     339                            parentCluster.childClusters.remove(k); 
    351340                            break; 
    352341                        } 
     
    358347        } 
    359348         
    360         // finally, for all subclusters that were changed, ensure the creation of their internal 
    361         // hierarchy as well 
    362         for (GUIElementsCluster subClusterToHandle : subClustersToHandle) { 
    363             createClusterHierachies(subClusterToHandle.childClusters); 
    364         } 
    365     } 
    366  
    367     /** 
    368      * <p> 
    369      * called for each cluster to merge similar GUI elements depending on the clusters and to 
    370      * create GUI element groups if required. Calls itself recursively to be also applied on 
    371      * child clusters. 
    372      * </p> 
    373      * 
    374      * @param cluster the cluster of which the similar children shall be merged 
    375      * @param model   the model to be adapted through the merge 
    376      */ 
    377     private void mergeGUIElementsAccordingToClusters(GUIElementsCluster cluster, 
    378                                                      GUIModel           model, 
    379                                                      String             indent) 
    380     { 
    381         //System.out.println(indent + "handling " + cluster); 
    382          
    383         for (SimilarGUIElements similarGUIElements : cluster.similarChildrenGUIElements) { 
    384             mergeGUIElements(similarGUIElements, model, indent + "  "); 
    385         } 
    386          
    387         if (cluster.childClusters.size() > 0) { 
    388             //System.out.println(indent + "  handling child clusters"); 
    389              
    390             for (GUIElementsCluster childCluster : cluster.childClusters) { 
    391                 if (cluster.isDefault() || cluster.clusterParentsMatch(childCluster)) { 
    392                     // for default cluster or children not creating subgroups, just traverse the 
    393                     // cluster hierarchy 
    394                     mergeGUIElementsAccordingToClusters(childCluster, model, indent + "    "); 
    395                 } 
    396                 else { 
    397                     createClusterGroup(childCluster, model, indent + "    "); 
    398                 } 
     349        if (subClustersToHandle.size() > 0) { 
     350            // finally, for all subclusters that were changed, ensure the creation of their internal 
     351            // hierarchy as well 
     352            for (GUIElementsCluster subClusterToHandle : subClustersToHandle) { 
     353                // we need a dedicated common cluster --> add it 
     354                createClusterHierachies(subClusterToHandle); 
     355                 
     356                GUIElementsCluster commonCluster = new GUIElementsCluster(); 
     357                //commonCluster.setClusteredGUIElements(subClusterToHandle.clusteredGUIElements); 
     358                commonCluster.similarChildrenGUIElements.addAll 
     359                    (subClusterToHandle.similarChildrenGUIElements); 
     360                 
     361                subClusterToHandle.similarChildrenGUIElements.clear(); 
     362                subClusterToHandle.childClusters.add(0, commonCluster); 
    399363            } 
    400364        } 
     
    416380 
    417381        while (similarGUIElements.size() > 1) { 
    418             //System.out.println(indent + "merging " + mergeResult + " and " + 
    419             //                   similarGUIElements.get(1).similarGUIElement); 
     382            System.out.println(indent + "merging " + mergeResult + " and " + 
     383                               similarGUIElements.get(1).similarGUIElement); 
    420384            mergeResult = model.mergeGUIElements 
    421385                (mergeResult, similarGUIElements.remove(1).similarGUIElement, false); 
     
    432396     * @param model   the model to be used for creating the groups 
    433397    */ 
    434     private void createClusterGroup(GUIElementsCluster cluster, GUIModel model, String indent) { 
    435         //System.out.println(indent + "creating group for " + cluster); 
    436  
     398    private void groupGUIElementsAccordingToClusters(GUIElementsCluster cluster, 
     399                                                     GUIModel           model, 
     400                                                     String             indent) 
     401    { 
     402        System.out.println(indent + "handling " + cluster); 
     403         
    437404        List<IGUIElement> guiElementsToGroup = new LinkedList<IGUIElement>(); 
    438405         
     
    442409        } 
    443410         
    444         //System.out.println(indent + "  iterating child clusters of " + cluster); 
     411        List<IGUIElement> subgroups = new LinkedList<IGUIElement>(); 
     412 
     413         
     414        System.out.println(indent + "iterating child clusters of " + cluster); 
    445415        for (GUIElementsCluster childCluster : cluster.childClusters) { 
    446             if (cluster.isDefault() || cluster.clusterParentsMatch(childCluster)) { 
    447                 // for default cluster or children not creating subgroups, just traverse the 
    448                 // cluster hierarchy 
    449                 mergeGUIElementsAccordingToClusters(childCluster, model, indent + "  "); 
    450             } 
    451             else { 
    452                 createClusterGroup(childCluster, model, indent + "  "); 
    453             } 
    454              
    455             if (childCluster.getGroup() != null) { 
    456                 if (cluster.isSubCluster(childCluster)) { 
    457                     guiElementsToGroup.add(childCluster.getGroup()); 
    458                 } 
    459                 else { 
    460                     guiElementsToGroup.add(childCluster.getGroup().getParent()); 
    461                 } 
    462             } 
    463         } 
    464          
    465         //System.out.println(indent + "grouping: " + guiElementsToGroup); 
    466         IGUIElement group = model.groupGUIElements(guiElementsToGroup, getGroupName(cluster)); 
    467         //System.out.println(indent + "  created group for " + cluster + ": " + group); 
    468          
    469         cluster.setGroup(group); 
     416            groupGUIElementsAccordingToClusters(childCluster, model, indent + "  "); 
     417             
     418            if (cluster.childClusters.size() > 1) { 
     419                List<IGUIElement> childGuiElemsToGroup = new LinkedList<IGUIElement>(); 
     420                 
     421                for (SimilarGUIElements similarGUIElems : childCluster.similarChildrenGUIElements) { 
     422                    childGuiElemsToGroup.addAll(similarGUIElems.toGUIElementList()); 
     423                } 
     424                 
     425                for (GUIElementsCluster subsubcluster : childCluster.childClusters) { 
     426                    if (subsubcluster.getGroup() != null) { 
     427                        childGuiElemsToGroup.add(subsubcluster.getGroup()); 
     428                    } 
     429                } 
     430                 
     431                if (childGuiElemsToGroup.size() > 0) { 
     432                    System.out.println(indent + "  grouping: " + childGuiElemsToGroup); 
     433                    IGUIElement group = model.groupGUIElements 
     434                        (childGuiElemsToGroup, getGroupName(childCluster)); 
     435                    System.out.println 
     436                        (indent + "    created group for " + childCluster + ": " + group); 
     437 
     438                    if (group != null) { 
     439                        childCluster.setGroup(group); 
     440                        if (cluster.isSubCluster(childCluster)) { 
     441                            subgroups.add(childCluster.getGroup()); 
     442                        } 
     443                        else { 
     444                            subgroups.add(childCluster.getGroup().getParent()); 
     445                        } 
     446                    } 
     447                } 
     448            } 
     449             
     450            System.out.println(); 
     451        } 
     452         
    470453    } 
    471454 
     
    484467        name.append("group_"); 
    485468         
    486         for (SimilarGUIElement guiElement : cluster.clusteredGUIElements) { 
    487             if (guiElement.mainClusterParent instanceof HTMLDocument) { 
    488                 name.append(((HTMLDocument) guiElement.mainClusterParent).getPath()); 
    489             } 
    490             else { 
    491                 name.append(guiElement.mainClusterParent.getStringIdentifier()); 
    492             } 
     469        if (cluster.clusteredGUIElements.size() > 0) { 
     470            for (SimilarGUIElement guiElement : cluster.clusteredGUIElements) { 
     471                if (guiElement.mainClusterParent instanceof HTMLDocument) { 
     472                    name.append(((HTMLDocument) guiElement.mainClusterParent).getPath()); 
     473                } 
     474                else { 
     475                    name.append(guiElement.mainClusterParent.getStringIdentifier()); 
     476                } 
     477            } 
     478        } 
     479        else { 
     480            name.append("common"); 
    493481        } 
    494482         
     
    557545        /** 
    558546         * <p> 
    559          * checks, if the main cluster parents, i.e., the documents of this and the provided cluster 
    560          * match 
    561          * </p> 
    562          * 
    563          * @param other the other cluster of which the main cluster parents shall be compared to 
    564          *              this 
    565          *               
    566          * @return true if they match, false else 
    567          */ 
    568         private boolean clusterParentsMatch(GUIElementsCluster other) { 
    569             // cluster parent may already be merged and therefore equals --> use system identity 
    570             // hash code for uniqueness 
    571             Set<Integer> mainClusterParents1 = new HashSet<Integer>(); 
    572             for (SimilarGUIElement clusteredElem1 : clusteredGUIElements) { 
    573                 mainClusterParents1.add(System.identityHashCode(clusteredElem1.mainClusterParent)); 
    574             } 
    575              
    576             Set<Integer> mainClusterParents2 = new HashSet<Integer>(); 
    577             for (SimilarGUIElement clusteredElem2 : other.clusteredGUIElements) { 
    578                 mainClusterParents2.add(System.identityHashCode(clusteredElem2.mainClusterParent)); 
    579             } 
    580              
    581             return mainClusterParents1.equals(mainClusterParents2); 
    582         } 
    583  
    584         /** 
    585          * <p> 
    586          * returns true, if this cluster is a default cluster 
    587          * </p> 
    588          * 
    589          * @return 
    590          */ 
    591         public boolean isDefault() { 
    592             return clusteredGUIElements.size() <= 0; 
    593         } 
    594  
    595         /** 
    596          * <p> 
    597547         * sets the GUI element group created for this cluster 
    598548         * </p> 
     
    710660             
    711661            if (clusteredGUIElements.size() > 0) { 
     662                ret.append(clusteredGUIElements.get(0).similarGUIElement); 
     663                ret.append(" ["); 
     664                 
     665                int length = ret.length(); 
    712666                for (SimilarGUIElement similarGUIElement : clusteredGUIElements) { 
    713                     if (ret.length() > "cluster(".length()) { 
     667                    if (ret.length() > length) { 
    714668                        ret.append(", "); 
    715669                    } 
    716670 
    717                     ret.append(similarGUIElement); 
    718                 } 
     671                    ret.append(similarGUIElement.mainClusterParent); 
     672                } 
     673                 
     674                ret.append(']'); 
    719675            } 
    720676            else { 
     
    732688         * </p> 
    733689         */ 
    734 //        private void dump(PrintStream out, String indent) { 
    735 //            out.print(indent); 
    736 //            out.print(getName()); 
    737 //            out.print(" { "); 
    738 //             
    739 //            if (similarChildrenGUIElements.size() > 0) { 
    740 //                out.println(); 
    741 //                out.print(indent); 
    742 //                out.println("  similar children {"); 
    743 // 
    744 //                for (SimilarGUIElements similarGuiElements : similarChildrenGUIElements) { 
    745 //                    similarGuiElements.dump(out, indent + "    "); 
    746 //                } 
    747 // 
    748 //                out.print(indent); 
    749 //                out.println("  }"); 
    750 // 
    751 //                if (childClusters.size() > 0) { 
    752 //                    out.print(indent); 
    753 //                    out.println("  child clusters {"); 
    754 // 
    755 //                    for (GUIElementsCluster childCluster : childClusters) { 
    756 //                        childCluster.dump(out, indent + "    "); 
    757 //                    } 
    758 // 
    759 //                    out.print(indent); 
    760 //                    out.println("  }"); 
    761 //                } 
    762 // 
    763 //                out.print(indent); 
    764 //            } 
    765 //            else if (clusteredGUIElements.size() > 0) { 
    766 //                out.println(); 
    767 //                out.print(indent); 
    768 //                out.println("  clustered GUIElements {"); 
    769 // 
    770 //                for (SimilarGUIElement clusteredGUIElement : clusteredGUIElements) { 
    771 //                    clusteredGUIElement.dump(out, indent + "    "); 
    772 //                } 
    773 // 
    774 //                out.print(indent); 
    775 //                out.println("  }"); 
    776 //                out.print(indent); 
    777 //            } 
    778 //             
    779 //            out.println("}"); 
    780 //        } 
     690        private void dump(PrintStream out, String indent) { 
     691            out.print(indent); 
     692            out.print(getName()); 
     693            out.println(" { "); 
     694             
     695            if (clusteredGUIElements.size() > 0) { 
     696                out.print(indent); 
     697                out.println("  clustered GUIElements {"); 
     698 
     699                for (SimilarGUIElement clusteredGUIElement : clusteredGUIElements) { 
     700                    clusteredGUIElement.dump(out, indent + "    "); 
     701                } 
     702 
     703                out.print(indent); 
     704                out.println("  }"); 
     705            } 
     706 
     707            if (similarChildrenGUIElements.size() > 0) { 
     708                out.print(indent); 
     709                out.println("  similar children {"); 
     710 
     711                for (SimilarGUIElements similarGuiElements : similarChildrenGUIElements) { 
     712                    similarGuiElements.dump(out, indent + "    "); 
     713                } 
     714 
     715                out.print(indent); 
     716                out.println("  }"); 
     717            } 
     718 
     719            if (childClusters.size() > 0) { 
     720                out.print(indent); 
     721                out.println("  child clusters {"); 
     722 
     723                for (GUIElementsCluster childCluster : childClusters) { 
     724                    childCluster.dump(out, indent + "    "); 
     725                } 
     726 
     727                out.print(indent); 
     728                out.println("  }"); 
     729            } 
     730             
     731            out.print(indent); 
     732            out.println("}"); 
     733        } 
    781734 
    782735    } 
     
    834787         * </p> 
    835788         */ 
    836 //        private void dump(PrintStream out, String indent) { 
    837 //            out.print(indent); 
    838 //            out.print("{ "); 
    839 //             
    840 //            for (int i = 0; i < super.size(); i++) { 
    841 //                if (i > 0) { 
    842 //                    out.print(", "); 
    843 //                } 
    844 //                out.print(super.get(i)); 
    845 //            } 
    846 //             
    847 //            out.println(" }"); 
    848 //        } 
     789        private void dump(PrintStream out, String indent) { 
     790            out.print(indent); 
     791            out.print("{ "); 
     792             
     793            for (int i = 0; i < super.size(); i++) { 
     794                if (i > 0) { 
     795                    out.print(", "); 
     796                } 
     797                out.print(super.get(i)); 
     798            } 
     799             
     800            out.println(" }"); 
     801        } 
    849802    } 
    850803     
     
    886839         * </p> 
    887840         */ 
    888 //        private void dump(PrintStream out, String indent) { 
    889 //            out.print(indent); 
    890 //            out.println(this); 
    891 //        } 
     841        private void dump(PrintStream out, String indent) { 
     842            out.print(indent); 
     843            out.println(this); 
     844        } 
    892845 
    893846        /* (non-Javadoc) 
Note: See TracChangeset for help on using the changeset viewer.