/** * See if the provided object reference has any children that may help satisfy the recognition * string. This is essentially how this Iterator is "reentrant". Objects matching pieces of our * ObjectVector are added to the statically shared matches collection until the final Object * satisfying the entire ObjectVector is found. * * <p>Throughout the process we must maintain an accurate count of each class and its associated * object type in each child branch. In this way, we keep track of when we have found the nth * Index of a class or an associated object type in the branch. Thus, for each object encountered, * we must increment both the class count, and t he object type count for that class in this * branch. * * <p>Note, as we go down an object hierarchy branch, the counts increment. However, when we reset * back up to a higher level in the object hierarchy to go down a new branch, the counts must be * reset to those counts that were valid on entry at that level. * * <p>This function is only called internally. * * <p> * * @param achild the Object to process for children. * <p> * @param agovVector the currently active GuiObjectVector. * <p> * @param agovLevel the hierarchy level in the GuiObjectVector we are trying to satisfy. * <p> * @param aobjLevel the level in the actual object hierarchy we are searching. * <p> * @param classindices the storage of current class counts. * <p> * @param typeindices the storage of current object type counts. * @author Carl Nagle, SEP 02, 2004 modified processChildren to skip checking children of * Comboboxes */ protected void processChildren( Object achild, GuiObjectVector agovVector, int agovLevel, int aobjLevel, Hashtable classindices, Hashtable typeindices, String typeclass) { GuiObjectRecognition agor = agovVector.getParentGuiObjectRecognition(); String classname = agor.getObjectClassName(achild); // CANAGL -- do not seek children in comboboxes. messes pushbutton counts! try { if (GuiClassData.classtypeContainsClassType(typeclass, "ComboBox")) { Log.debug("GCI: No children sought for ComboBoxes"); return; } // if Domain = HTML and typeclass = PushButton if ((classname.toLowerCase().startsWith("html")) && (GuiClassData.classtypeContainsClassType(typeclass, "PushButton"))) { Log.debug("GCI: No children sought for HTML PushButtons"); return; } } catch (Exception x) {; } // may be cached keys to proxies during EXTERNAL_PROCESSING Object[] childsChildren = agovVector.getChildObjects(achild); if ((childsChildren instanceof Object) && (childsChildren.length > 0)) { Log.info("GCI: " + childsChildren.length + " children in " + classname); Log.info("..........Child:" + classname + ", typeclass: " + typeclass); GuiChildIterator it = agovVector.createGuiChildIterator(gather); boolean isTab = (GuiClassData.classtypeContainsClassType(typeclass, "TabControl")) || (GuiClassData.classtypeContainsClassType(classname, "Html.HtmlBrowser")); // childsChildren may be cached keys during EXTERNAL_PROCESSING it.processNextLevel( childsChildren, agovVector, agovLevel, aobjLevel, classindices, typeindices, isTab); } else { Log.debug("GCI: No children found for " + classname); } }
/** * @param child * @param govVector * @param objLevel * @param govLevel * @param classindices * @param typeindices * @param classname * @return NULL if error occurs relating to gorInfo creation, or NULL if object is NOT to be * processed. Otherwise, return a valid ClassTypeInfo object with all appropriate settings. */ protected ClassTypeInfo incrementClassTypeIndices( Object child, GuiObjectVector govVector, int govLevel, int objLevel, Hashtable classindices, Hashtable typeindices, String classname) { Log.info("GCI: getting child GOR info. GOV level:" + govLevel); ClassTypeInfo cti = new ClassTypeInfo(); final String TOOLTIP_SUFFIX = "TOOLTIP"; cti.classname = classname; try { cti.gorInfo = govVector.getChildGuiObjectRecognition(govLevel); } catch (ArrayIndexOutOfBoundsException x) { Log.debug( "GCI: sought govLevel:" + govLevel + ", exceeds 0-based recognition path information:" + govVector.getPathVector()); return null; } GuiClassData classdata = govVector.getGuiClassData(); cti.typeclass = classdata.getMappedClassType(classname, child); // bypass panels that harbor tooltip(s) Object tooltip = null; String tooltipclass = null; String tooltipmapped = null; String gortypeclass = cti.gorInfo.getClassValue(); // only perform check if we are NOT looking for a tooltip if ((gortypeclass == null) || (gortypeclass != null && !gortypeclass.toUpperCase().endsWith(TOOLTIP_SUFFIX))) { try { Log.info("GCI.incrementClassTypeIndices evaluating possible TOOLTIP container..."); if (classdata.isToolTipContainerType(cti.typeclass)) { Object[] childsChildren = govVector.getChildObjects(child); if (childsChildren != null && childsChildren.length > 0) { tooltip = childsChildren[0]; tooltipclass = cti.gorInfo.getObjectClassName(tooltip); try { if (tooltipclass.toUpperCase().endsWith(TOOLTIP_SUFFIX)) { Log.info("GCI.incrementClassTypeIndices bypassing active TOOLTIP class!"); return null; // skip panel with tooltip } tooltipmapped = classdata.getMappedClassType(tooltipclass, tooltip); if (tooltipmapped.toUpperCase().endsWith(TOOLTIP_SUFFIX)) { Log.info("GCI.incrementClassTypeIndices bypassing active TOOLTIP type!"); return null; // skip panel with tooltip } } catch (Exception x) { Log.debug( "GCI.incrementClassTypeIndices ToolTip test IGNORING " + x.getClass().getSimpleName()); } } } Log.info("GCI.incrementClassTypeIndices container NOT a TOOLTIP container."); } catch (Exception x) { Log.debug( "GCI.incrementClassTypeIndices ToolTip Container test IGNORING " + x.getClass().getSimpleName()); } } // increment class index counters for the retrieved class? Log.info("GCI: incrementing class indices for:" + classname); Integer classindex = (Integer) classindices.get(classname); classindex = (classindex == null) ? new Integer(1) : new Integer(classindex.intValue() + 1); classindices.put(classname, classindex); cti.classindex = classindex.intValue(); Log.info("GCI: classindices.put(" + classname + ", " + classindex + ")"); Integer absclassindex = (Integer) absindices.get(classname); absclassindex = (absclassindex == null) ? new Integer(1) : new Integer(absclassindex.intValue() + 1); absindices.put(classname, absclassindex); cti.absoluteclassindex = absclassindex.intValue(); Log.info("GCI: absindices.put(" + classname + ", " + absclassindex + ")"); // also increment the Type index counter if it is equivalent to a known type String gorClassType = cti.gorInfo.getClassValue(); Log.info("GCI: " + classname + " mappedClassType: " + cti.typeclass); Integer typeindex = new Integer(0); Integer abstypeindex = new Integer(0); if (cti.typeclass instanceof String) { StringTokenizer toker = new StringTokenizer(cti.typeclass, classdata.DEFAULT_TYPE_SEPARATOR); String atoken = null; Integer tmptypeindex = null; Integer tmpabstypeindex = null; while (toker.hasMoreTokens()) { atoken = toker.nextToken().toUpperCase().trim(); tmptypeindex = (Integer) typeindices.get(atoken); Log.info("GCI: getting: " + atoken + ", " + tmptypeindex); tmptypeindex = (tmptypeindex == null) ? new Integer(1) : new Integer(tmptypeindex.intValue() + 1); Log.index( "GCI: ... " + StringUtils.getSpaces(new Integer(objLevel)) + atoken + ":" + tmptypeindex); typeindices.put(atoken, tmptypeindex); tmpabstypeindex = (Integer) absindices.get(atoken); tmpabstypeindex = (tmpabstypeindex == null) ? new Integer(1) : new Integer(tmpabstypeindex.intValue() + 1); absindices.put(atoken, tmpabstypeindex); Log.info("TYPE:absindices.put(" + atoken + ", " + tmpabstypeindex + ")"); // use the correct typeindex for the classtype that matches recognition string if (atoken.equalsIgnoreCase(gorClassType)) { typeindex = tmptypeindex; cti.typeindex = typeindex.intValue(); abstypeindex = tmpabstypeindex; cti.absolutetypeindex = abstypeindex.intValue(); } } } return cti; }
/** * Called only once by some external routine kicking off a TestObject search. The govLevel and * objLevel in the ObjectVector will be assumed to be 0. The routine will install an initial class * and type indices for the provided parent. * * <p>If we can deduce that the parent actually exists in the path vector then that govLevel of * the vector will be matched and skipped. If we find that the parent info is NOT in the provided * vector then we will not skip the govLevel. * * <p>We can assume the parent info is in the path if the path begins with "\;". The next item in * the path is assumed to be the topmost parent. * * <p>We can ignore the first path info if it instead begins with ".\;". The next item would be * considered to be the first child of the parent. * * <p> * * @param aparent the topmost parent to search. * <p> * @param agovVector the govVector (recognition string) to satisfy with the search. * <p> * @param gather, List containing names matched, if null, then match first name */ public GuiChildIterator(Object aparent, GuiObjectVector agovVector, java.util.List gather) { this(gather); if (agovVector.isFullPathSearchMode()) { setSearchMode(FULLPATH_SEARCH_MODE); } else { setSearchMode(CLASSIC_SEARCH_MODE); } Hashtable classindices = new Hashtable(8); Hashtable typeindices = new Hashtable(8); matches = new Vector(10, 3); notFound = true; hasFinalMatch = false; // class (ex: JFrame) and Type (ex: Window) counters are complimentary // for each class that is a known type BOTH counters get incremented. // always initialize class index counters for the retrieved class // it is possible this "parent" info is actually info for the first child govLevel 0 GuiObjectRecognition gorParent = agovVector.getParentGuiObjectRecognition(); GuiClassData classdata = agovVector.getGuiClassData(); String classname = gorParent.getObjectClassName(aparent); Log.info("GCI: processing children of parent:" + classname); classindices.put(classname, new Integer(1)); // always initialize the Type index counter if it is equivalent to a known type String typeclass = classdata.getMappedClassType(classname, aparent); Log.info("GCI: processing parent of type:" + typeclass); if (typeclass instanceof String) { StringTokenizer toker = new StringTokenizer(typeclass, classdata.DEFAULT_TYPE_SEPARATOR); String atoken = null; while (toker.hasMoreTokens()) { atoken = toker.nextToken().trim(); typeindices.put(atoken, new Integer(1)); } } // add our entry govVector and parent object as the first match // CANAGL - modifying to only store finalMatches // MatchData adata = new MatchData(agovVector, 0, 0, aparent); // matches.addElement(adata); int agovDepth = agovVector.getRecognitionDepth(); Log.info( "GCI: processing GOV with depth of:" + agovDepth + ", path=" + agovVector.getPathVector()); // begin the reentrant search for the matching child int startlevel = (agovDepth > 1) ? 1 : 0; if ((gorParent.getGovLevel() == 0) && (!(gorParent.pathInfo.equals(GuiObjectVector.ACTIVE_WINDOW_REFERENCE)))) { // Robot Java recognition strings often contain a JavaWindow reference // to the parent window that needs to be skipped. Same with Flex recognition strings(JunwuMa). if (!gorParent.getClassRecognition().equalsIgnoreCase("Type=JavaWindow") && !gorParent.getClassRecognition().equalsIgnoreCase("Type=FlexWindow")) { startlevel = 0; } else { Log.info( "GCI: bypassing govLevel=0 for child 'Type=JavaWindow'. Assuming duplicate parent info."); } } // Try to match the parent for some popupmenu Hashtable save_classindices = (Hashtable) classindices.clone(); Hashtable save_typeindices = (Hashtable) typeindices.clone(); processParent(aparent, agovVector, startlevel, 1, classindices, typeindices, typeclass); Object matchedObject = this.getMatchedGuiObject(); if (matchedObject == null) { if (SEARCH_MODE != FULLPATH_SEARCH_MODE) { Log.info("GCI: CLASSIC_SEARCH_MODE calling processChildren..."); processChildren(aparent, agovVector, startlevel, 1, classindices, typeindices, typeclass); } else { Log.info("GCI: FULLPATH_SEARCH_MODE calling processChildren..."); processChildren( aparent, agovVector, startlevel, 1, save_classindices, save_typeindices, typeclass); } } }