Ignore:
Timestamp:
2018-12-14T22:23:47+13:00 (5 years 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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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)
Note: See TracChangeset for help on using the changeset viewer.