Changeset 32686

Show
Ignore:
Timestamp:
14.12.2018 22:23:47 (5 weeks ago)
Author:
ak19
Message:

For GUI testing, it's far and away easier if only GUI components had names. Else it's a real pain to access components from the AssertJ Swing API. Introducing setNamesRecursively, a new method (run on the Event Dispatch Thread EDT as is required by the code) that uses reflection to automate setting the names of hopefully all if not all the most important for testing GUI components of GLI. It's called from Gatherer's openGUI which is performed on the EDT, so no need to call invokeLater() to force this method to take place on the Event Dispatch Thread. There are 2 caveats: not sure all the components are named and not all of them appear to have a unique name, so I may expand the code hereafter to add numbering after checking against a hash map for uniqueness if I find this to be necessary

Location:
main/trunk/gli/src/org/greenstone/gatherer
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/gli/src/org/greenstone/gatherer/Gatherer.java

    r32050 r32686  
    755755        } 
    756756    }*/ 
    757  
     757        g_man.setName("GUIManager"); // g_man has a name "frame0" assigned automatically 
     758        // setNamesRecursively won't assign a name if one is already set 
     759        // Setting explicitly since GUIManager is preferred for its name 
     760        GUIManager.setNamesRecursively("", g_man); 
     761        GUIManager.printComponentNames(g_man, ""); 
     762         
    758763        // If there was a collection left open last time, reopen it  
    759764        if (open_collection_file_path == null || new File(Gatherer.open_collection_file_path).isDirectory()) { 
  • main/trunk/gli/src/org/greenstone/gatherer/gui/GUIManager.java

    r30705 r32686  
    4242import java.io.File; 
    4343import java.lang.*; 
     44import java.lang.reflect.*; 
    4445import java.net.*; 
    4546import java.util.*; 
     
    6768import org.greenstone.gatherer.util.Utility; 
    6869 
     70      
    6971/** The GUIManager is in charge of creating the Gatherer window frame then filling it with the goodness of the view panes. GUIManager not only creates these panes, but allows some messaging between them. Furthermore GUIManager includes functionality from menu driven choices, simply as it was easier to put it here once and have it accessible from all pane children. */ 
    7072public class GUIManager 
     
    142144    } 
    143145 
     146    /* 
     147      For GUI swing testing of GLI, it's very handy for components to have names 
     148      I use the GLI classname as name or if it's not a GLI class, then: 
     149       - if a member var of a GLI class, then GLIclassName.memberVarName 
     150       - else GLIClassName.swingComponentName 
     151      Google: "Java swing automatically setName" 
     152      -> https://stackoverflow.com/questions/3628218/strategy-for-naming-swing-components 
     153         https://stackoverflow.com/questions/1782598/with-java-reflection-how-to-instantiate-a-new-object-then-call-a-method-on-it 
     154      - https://stackoverflow.com/questions/4163500/how-to-automatic-set-name-attr-of-gui-components/4164479#4164479 
     155      - https://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.wb.swing.doc.user%2Fhtml%2Fwizards%2Fswing%2Fautomatic_databinding.html 
     156      - https://stackoverflow.com/questions/28639294/in-java-how-to-get-name-of-component-which-is-clicked 
     157    */ 
     158    public static void setNamesRecursively(String prefix, Component root) { 
     159     
     160    // root starts off as GLI's JFrame, so we know that all its GUI children are specifically JComponents 
     161     
     162    // https://docs.oracle.com/javase/7/docs/api/index.html?java/lang/reflect/package-summary.html 
     163    String className = root.getClass().getSimpleName(); 
     164     
     165    String packageName = root.getClass().getPackage().getName(); 
     166    if(!packageName.contains("org.greenstone.gatherer.gui")) { 
     167        if(root.getName() == null || root.getName().equals("")) { // if name not already set 
     168        if(!prefix.equals("")){ 
     169            // TODO: fix this 
     170            root.setName(prefix + "." + className); 
     171        } 
     172        else { 
     173            root.setName(className); 
     174        } 
     175        } // else swing Component name already set 
     176         
     177    } else { // root is in GLI GUI package, use its classname for name 
     178         
     179        if(root.getName() == null || root.getName().equals("")) { 
     180        root.setName(className); 
     181        } 
     182        prefix = className; 
     183         
     184        // check member vars 
     185        Field[] memberVars = root.getClass().getDeclaredFields(); // private to public member vars, but not inherited ones       
     186        for(int i = 0; i < memberVars.length; i++) { 
     187        memberVars[i].setAccessible(true); // make private/protected etc fields accessible 
     188         
     189        // https://www.tutorialspoint.com/java/lang/class_isinstance.htm 
     190        Class jCompClass = Container.class; 
     191        Class memberVarClass = memberVars[i].getType(); 
     192 
     193        // memberVarClass is a JComponen (subclass) 
     194        if(jCompClass.isAssignableFrom(memberVarClass)) { 
     195             
     196            // get the actual member variable denoted by memberVars[i] 
     197            // on the current JComponent instance 'root'. 
     198            // We now know this member var to be a JComponent 
     199            // Having the actual member variable of the instantiated instance, 
     200            // we can call setName on it 
     201            try { 
     202            Container memberComponent = (Container)memberVars[i].get(root); 
     203             
     204            if(memberComponent != null) { 
     205 
     206                // member var is a JComponent but not of GLI package, so locally instantiated 
     207                if(!memberVarClass.getPackage().getName().contains("org.greenstone.gatherer.gui")) { 
     208                String memberprefix = prefix + "." + memberVars[i].getName(); // append member var name 
     209                // now can call setName() on the actual member variable 
     210                memberComponent.setName(memberprefix); 
     211                setNamesRecursively(memberprefix, memberComponent); 
     212                } 
     213 
     214                //else  the member variable is a GLI GUI class, use its className as prefix for child components 
     215                // Skip this step to avoid circular references to our own member vars 
     216                /*else { // member variable is a GLI GUI class, use its className as prefix for child components 
     217                String memberprefix = memberVarClass.getSimpleName(); 
     218                memberComponent.setName(memberprefix); 
     219                setNamesRecursively(memberprefix, memberComponent); 
     220                }*/ 
     221             
     222                 
     223            } 
     224            } catch(Exception e) { 
     225            e.printStackTrace(); 
     226            } 
     227        } 
     228        // else not a JComponent, skip 
     229        }        
     230    } 
     231 
     232     
     233    // https://stackoverflow.com/questions/33927349/could-someone-please-explain-note-this-method-should-be-called-under-awt-tree 
     234    // No worries about AWT tree lock: setNamesRecursively is called by openGUI 
     235    // which is specifically called by GathererProg on the Event Dispatch Thread (EDT) 
     236    Component[] children = ((Container)root).getComponents(); 
     237    for(int i = 0; i < children.length; i++) { 
     238        // if we haven't already set a name for any child JComponents with the above, 
     239        // then the following will do so now 
     240        setNamesRecursively(className, children[i]); 
     241    } 
     242     
     243    } 
     244 
     245    public static void printComponentNames(Component root, String tabbing) { 
     246    System.err.println(tabbing + root.getName()); 
     247    Component[] children = ((Container)root).getComponents(); 
     248    // recursive call 
     249    for(int i = 0; i < children.length; i++) { 
     250        printComponentNames(children[i], tabbing + "  "); 
     251    } 
     252    } 
    144253 
    145254    public void windowGainedFocus(WindowEvent e)