1/* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.netbeans.jemmy; 24 25import java.awt.Component; 26import java.awt.Container; 27import java.util.Vector; 28 29/** 30 * 31 * Contains methods to search for components below a a given 32 * {@code java.awt.Container} in the display containment hierarchy. Uses a 33 * {@code ComponentChooser} interface implementation to find a component. 34 * 35 * @see ComponentChooser 36 * 37 * @author Alexandre Iline (alexandre.iline@oracle.com) 38 */ 39public class ComponentSearcher implements Outputable { 40 41 private int ordinalIndex; 42 private Container container; 43 private TestOut out; 44 private QueueTool queueTool; 45 private String containerToString; 46 47 /** 48 * Contructor. The search is constrained so that only components that lie 49 * below the given container in the containment hierarchy are considered. 50 * 51 * @param c Container to find components in. 52 */ 53 public ComponentSearcher(Container c) { 54 super(); 55 container = c; 56 setOutput(JemmyProperties.getProperties().getOutput()); 57 queueTool = new QueueTool(); 58 } 59 60 /** 61 * Creates {@code ComponentChooser} implementation whose 62 * {@code checkComponent(Component)} method returns {@code true} 63 * for any component. 64 * 65 * @param description Component description. 66 * @return ComponentChooser instance. 67 */ 68 public static ComponentChooser getTrueChooser(String description) { 69 class TrueChooser implements ComponentChooser { 70 71 private String description; 72 73 public TrueChooser(String desc) { 74 description = desc; 75 } 76 77 @Override 78 public boolean checkComponent(Component comp) { 79 return true; 80 } 81 82 @Override 83 public String getDescription() { 84 return description; 85 } 86 87 @Override 88 public String toString() { 89 return "TrueChooser{" + "description=" + description + '}'; 90 } 91 } 92 return new TrueChooser(description); 93 } 94 95 /** 96 * Defines print output streams or writers. 97 * 98 * @param output ?out? Identify the streams or writers used for print 99 * output. 100 * @see org.netbeans.jemmy.TestOut 101 * @see org.netbeans.jemmy.Outputable 102 * @see #getOutput 103 */ 104 @Override 105 public void setOutput(TestOut output) { 106 out = output; 107 } 108 109 /** 110 * Returns print output streams or writers. 111 * 112 * @return an object that contains references to objects for printing to 113 * output and err streams. 114 * @see org.netbeans.jemmy.TestOut 115 * @see org.netbeans.jemmy.Outputable 116 * @see #setOutput 117 */ 118 @Override 119 public TestOut getOutput() { 120 return out; 121 } 122 123 /** 124 * Returns container.toString(). It is called in dispatch thread. 125 * 126 * @return container.toString() 127 */ 128 private String containerToString() { 129 if (containerToString == null) { 130 containerToString = container == null ? "null" 131 : queueTool.invokeSmoothly( 132 new QueueTool.QueueAction<String>("container.toString()") { 133 @Override 134 public String launch() { 135 return container.toString(); 136 } 137 } 138 ); 139 } 140 return containerToString; 141 } 142 143 /** 144 * Searches for a component. The search for the component proceeds 145 * recursively in the component hierarchy rooted in this 146 * {@code ComponentChooser}'s container. 147 * 148 * @param chooser ComponentChooser instance, defining and applying the 149 * search criteria. 150 * @param index Ordinal component index. Indices start at 0. 151 * @return the {@code index}'th component from among those components 152 * for which the chooser's {@code checkComponent(Component)} method 153 * returns {@code true}. A {@code null} reference is returned if 154 * there are fewer than {@code index-1} components meeting the search 155 * criteria exist in the component hierarchy rooted in this 156 * {@code ComponentChooser}'s container. 157 */ 158 public Component findComponent(ComponentChooser chooser, int index) { 159 ordinalIndex = 0; 160 final Component result = findComponentInContainer(container, chooser, index, null); 161 if (result != null) { 162 // get result.toString() - run in dispatch thread 163 String resultToString = queueTool.invokeSmoothly( 164 new QueueTool.QueueAction<String>("result.toString()") { 165 @Override 166 public String launch() { 167 return result.toString(); 168 } 169 } 170 ); 171 out.printTrace("Component " + chooser.getDescription() 172 + "\n was found in container " + containerToString() 173 + "\n " + resultToString); 174 out.printGolden("Component \"" + chooser.getDescription() + "\" was found"); 175 } else { 176 out.printTrace("Component " + chooser.getDescription() 177 + "\n was not found in container " + containerToString()); 178 out.printGolden("Component \"" + chooser.getDescription() + "\" was not found"); 179 } 180 return result; 181 } 182 183 /** 184 * Searches for a component. The search for the component proceeds 185 * recursively in the component hierarchy rooted in this 186 * {@code ComponentChooser}'s container. 187 * 188 * @param chooser ComponentChooser instance, defining and applying the 189 * search criteria. 190 * @return the first component for which the chooser's 191 * {@code checkComponent(Component)} method returns {@code true}. 192 * A {@code null} reference is returned if no component meeting the 193 * search criteria exist in the component hierarchy rooted in this 194 * {@code ComponentChooser}'s container. 195 */ 196 public Component findComponent(ComponentChooser chooser) { 197 return findComponent(chooser, 0); 198 } 199 200 /** 201 * Searches for all components. The search for the components proceeds 202 * recursively in the component hierarchy rooted in this 203 * {@code ComponentChooser}'s container. 204 * 205 * @param chooser ComponentChooser instance, defining and applying the 206 * search criteria. 207 * @return the components for which the chooser's 208 * {@code checkComponent(Component)} method returns {@code true}. 209 * An empty array is returned if no component meeting the search criteria 210 * exists in the component hierarchy rooted in this 211 * {@code ComponentChooser}'s container. 212 */ 213 public Component[] findComponents(ComponentChooser chooser) { 214 Vector<Component> allSeen = new Vector<>(); 215 findComponentInContainer(container, chooser, 0, allSeen); 216 Component[] result = new Component[allSeen.size()]; 217 for (int i = 0, n = allSeen.size(); i < n; i++) { 218 result[i] = allSeen.get(i); 219 } 220 return result; 221 } 222 223 private Component findComponentInContainer(final Container cont, final ComponentChooser chooser, final int index, 224 final Vector<Component> allSeen) { 225 return queueTool.invokeSmoothly(new QueueTool.QueueAction<Component>("findComponentInContainer with " + chooser.getDescription()) { 226 227 @Override 228 public Component launch() throws Exception { 229 Component[] components = cont.getComponents(); 230 Component target; 231 for (Component component : components) { 232 if (component != null) { 233 if (chooser.checkComponent(component)) { 234 if (allSeen != null) { 235 allSeen.add(component); 236 } else if (ordinalIndex == index) { 237 return component; 238 } else { 239 ordinalIndex++; 240 } 241 } 242 if (component instanceof Container) { 243 if ((target = findComponentInContainer((Container) component, 244 chooser, index, allSeen)) != null) { 245 return target; 246 } 247 } 248 } 249 } 250 return null; 251 } 252 }); 253 } 254 255} 256