001 /*
002 * Created on Mar 4, 2008
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 *
014 * Copyright @2008-2010 the original author or authors.
015 */
016 package org.fest.swing.core;
017
018 import java.awt.Component;
019 import java.awt.Container;
020 import java.util.Collection;
021
022 import javax.swing.JLabel;
023
024 import org.fest.swing.annotation.RunsInEDT;
025 import org.fest.swing.exception.ComponentLookupException;
026
027 /**
028 * Understands GUI <code>{@link java.awt.Component}</code> lookup.
029 *
030 * @author Alex Ruiz
031 */
032 @RunsInEDT
033 public interface ComponentFinder {
034
035 /**
036 * Returns the <code>{@link ComponentPrinter}</code> in this finder.
037 * @return the <code>ComponentPrinter</code> in this finder.
038 */
039 ComponentPrinter printer();
040
041 /**
042 * Finds a <code>{@link Component}</code> by type. If this finder is attached to a <code>{@link Robot}</code>, it will
043 * use the component lookup scope in the <code>Robot</code>'s <code>{@link Settings}</code> to determine whether the
044 * component to find should be showing or not. If this finder is <em>not</em> attached to any <code>Robot</code>, the
045 * component to find does not have to be showing.
046 * <p>
047 * Example:
048 * <pre>
049 * JTextField textbox = finder.findByType(JTextField.class);
050 * </pre>
051 * </p>
052 * @param <T> the parameterized type of the component to find.
053 * @param type the type of the component to find.
054 * @return the found component.
055 * @throws ComponentLookupException if a matching component could not be found.
056 * @throws ComponentLookupException if more than one matching component is found.
057 * @see Robot#settings()
058 * @see Settings#componentLookupScope()
059 * @see ComponentLookupScope
060 */
061 <T extends Component> T findByType(Class<T> type);
062
063 /**
064 * Finds a <code>{@link Component}</code> by type. For example:
065 * @param <T> the parameterized type of the component to find.
066 * @param type the type of the component to find.
067 * @param showing indicates whether the component to find should be visible (or showing) or not.
068 * @return the found component.
069 * @throws ComponentLookupException if a matching component could not be found.
070 * @throws ComponentLookupException if more than one matching component is found.
071 * @see #findByType(Class)
072 */
073 <T extends Component> T findByType(Class<T> type, boolean showing);
074
075 /**
076 * <p>
077 * Finds a <code>{@link Component}</code> by type in the hierarchy under the given root. If this finder is attached to
078 * a <code>{@link Robot}</code>, it will use the component lookup scope in the <code>Robot</code>'s
079 * <code>{@link Settings}</code> to determine whether the component to find should be showing or not. If this finder
080 * is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be showing.
081 * </p>
082 * <p>
083 * Let's assume we have the following <code>{@link javax.swing.JFrame}</code> containing a
084 * <code>{@link javax.swing.JTextField}</code>:
085 *
086 * <pre>
087 * JFrame myFrame = new JFrame();
088 * myFrame.add(new JTextField());
089 * </pre>
090 *
091 * </p>
092 * <p>
093 * If we want to get a reference to the <code>{@link javax.swing.JTextField}</code> in that particular
094 * <code>{@link javax.swing.JFrame}</code> without going through the whole AWT component hierarchy, we could simply
095 * specify:
096 *
097 * <pre>
098 * JTextField textbox = finder.findByType(myFrame, JTextField.class);
099 * </pre>
100 *
101 * </p>
102 * @param <T> the parameterized type of the component to find.
103 * @param root the root used as the starting point of the search.
104 * @param type the type of the component to find.
105 * @return the found component.
106 * @throws ComponentLookupException if a matching component could not be found.
107 * @throws ComponentLookupException if more than one matching component is found.
108 * @see Robot#settings()
109 * @see Settings#componentLookupScope()
110 * @see ComponentLookupScope
111 */
112 <T extends Component> T findByType(Container root, Class<T> type);
113
114 /**
115 * Finds a <code>{@link Component}</code> by type in the hierarchy under the given root.
116 * @param <T> the parameterized type of the component to find.
117 * @param root the root used as the starting point of the search.
118 * @param showing indicates whether the component to find should be visible (or showing) or not.
119 * @param type the type of the component to find.
120 * @return the found component.
121 * @throws ComponentLookupException if a matching component could not be found.
122 * @throws ComponentLookupException if more than one matching component is found.
123 * @see #findByType(Container, Class)
124 */
125 <T extends Component> T findByType(Container root, Class<T> type, boolean showing);
126
127 /**
128 * <p>
129 * Finds a <code>{@link Component}</code> by by the text of its associated <code>{@link JLabel}</code>. If this finder
130 * is attached to a <code>{@link Robot}</code>, it will use the component lookup scope in the <code>Robot</code>'s
131 * <code>{@link Settings}</code> to determine whether the component to find should be showing or not. If this finder
132 * is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be showing.
133 * </p>
134 * <p>
135 * Let's assume we have the <code>{@link javax.swing.JTextField}</code> with a <code>{@link JLabel}</code> with text
136 * "Name";
137 *
138 * <pre>
139 * JLabel label = new JLabel("Name");
140 * JTextField textbox = new JTextField();
141 * label.setLabelFor(textBox);
142 * </pre>
143 *
144 * </p>
145 * <p>
146 * To get a reference to this <code>{@link javax.swing.JTextField}</code> by the text of its associated
147 * <code>JLabel</code>, we can specify:
148 *
149 * <pre>
150 * JTextField textBox = (JTextField) finder.findByLabel("Name");
151 * </pre>
152 *
153 * </p>
154 * <p>
155 * Please note that you need to cast the result of the lookup to the right type. To avoid casting, please use one of
156 * following:
157 * <ol>
158 * <li><code>{@link #findByLabel(String, Class)}</code></li>
159 * <li><code>{@link #findByLabel(String, Class, boolean)}</code></li>
160 * <li><code>{@link #findByLabel(Container, String, Class)}</code></li>
161 * <li><code>{@link #findByLabel(Container, String, Class, boolean)}</code></li>
162 * </ol>
163 * </p>
164 * @param label the text of the <code>JLabel</code> associated to the component to find.
165 * @return the found component.
166 * @throws ComponentLookupException if a matching component could not be found.
167 * @throws ComponentLookupException if more than one matching component is found.
168 * @see JLabel#getLabelFor()
169 * @see JLabel#setLabelFor(Component)
170 * @see Robot#settings()
171 * @see Settings#componentLookupScope()
172 * @see ComponentLookupScope
173 */
174 Component findByLabel(String label);
175
176 /**
177 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code> and type. If this
178 * finder is attached to a <code>{@link Robot}</code>, it will use the component lookup scope in the
179 * <code>Robot</code>'s <code>{@link Settings}</code> to determine whether the component to find should be showing or
180 * not. If this finder is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be
181 * showing.
182 * @param <T> the parameterized type of the component to find.
183 * @param label the text of the <code>JLabel</code> associated to the component to find.
184 * @param type the type of the component to find.
185 * @return the found component.
186 * @throws ComponentLookupException if a matching component could not be found.
187 * @throws ComponentLookupException if more than one matching component is found.
188 * @see #findByLabel(String)
189 * @see JLabel#getLabelFor()
190 * @see JLabel#setLabelFor(Component)
191 * @see Robot#settings()
192 * @see Settings#componentLookupScope()
193 * @see ComponentLookupScope
194 */
195 <T extends Component> T findByLabel(String label, Class<T> type);
196
197 /**
198 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code> and type.
199 * @param <T> the parameterized type of the component to find.
200 * @param label the text of the <code>JLabel</code> associated to the component to find.
201 * @param type the type of the component to find.
202 * @param showing indicates whether the component to find should be visible (or showing) or not.
203 * @return the found component.
204 * @throws ComponentLookupException if a matching component could not be found.
205 * @throws ComponentLookupException if more than one matching component is found.
206 * @see #findByLabel(String)
207 * @see JLabel#getLabelFor()
208 * @see JLabel#setLabelFor(Component)
209 */
210 <T extends Component> T findByLabel(String label, Class<T> type, boolean showing);
211
212 /**
213 * Finds a <code>{@link Component}</code> by by the text of its associated <code>{@link JLabel}</code>.
214 * @param label the text of the <code>JLabel</code> associated to the component to find.
215 * @param showing indicates whether the component to find should be visible (or showing) or not.
216 * @return the found component.
217 * @throws ComponentLookupException if a matching component could not be found.
218 * @throws ComponentLookupException if more than one matching component is found.
219 * @see #findByLabel(String)
220 * @see JLabel#getLabelFor()
221 * @see JLabel#setLabelFor(Component)
222 */
223 Component findByLabel(String label, boolean showing);
224
225 /**
226 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code>, in the hierarchy
227 * under the given root. If this finder is attached to a <code>{@link Robot}</code>, it will use the component lookup
228 * scope in the <code>Robot</code>'s <code>{@link Settings}</code> to determine whether the component to find should
229 * be showing or not. If this finder is <em>not</em> attached to any <code>Robot</code>, the component to find does
230 * not have to be showing.
231 * @param root the root used as the starting point of the search.
232 * @param label the text of the <code>JLabel</code> associated to the component to find.
233 * @return the found component.
234 * @throws ComponentLookupException if a matching component could not be found.
235 * @throws ComponentLookupException if more than one matching component is found.
236 * @see #findByLabel(String)
237 * @see JLabel#getLabelFor()
238 * @see JLabel#setLabelFor(Component)
239 * @see Robot#settings()
240 * @see Settings#componentLookupScope()
241 * @see ComponentLookupScope
242 */
243 Component findByLabel(Container root, String label);
244
245 /**
246 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code>, in the hierarchy
247 * under the given root.
248 * @param root the root used as the starting point of the search.
249 * @param label the text of the <code>JLabel</code> associated to the component to find.
250 * @param showing indicates whether the component to find should be visible (or showing) or not.
251 * @return the found component.
252 * @throws ComponentLookupException if a matching component could not be found.
253 * @throws ComponentLookupException if more than one matching component is found.
254 * @see #findByLabel(String)
255 * @see JLabel#getLabelFor()
256 * @see JLabel#setLabelFor(Component)
257 */
258 Component findByLabel(Container root, String label, boolean showing);
259
260 /**
261 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code> and type, in the
262 * hierarchy under the given root. If this finder is attached to a <code>{@link Robot}</code>, it will use the
263 * component lookup scope in the <code>Robot</code>'s <code>{@link Settings}</code> to determine whether the component
264 * to find should be showing or not. If this finder is <em>not</em> attached to any <code>Robot</code>, the component
265 * to find does not have to be showing.
266 * @param <T> the parameterized type of the component to find.
267 * @param root the root used as the starting point of the search.
268 * @param label the text of the <code>JLabel</code> associated to the component to find.
269 * @param type the type of the component to find.
270 * @return the found component.
271 * @throws ComponentLookupException if a matching component could not be found.
272 * @throws ComponentLookupException if more than one matching component is found.
273 * @see #findByLabel(String)
274 * @see JLabel#getLabelFor()
275 * @see JLabel#setLabelFor(Component)
276 * @see Robot#settings()
277 * @see Settings#componentLookupScope()
278 * @see ComponentLookupScope
279 */
280 <T extends Component> T findByLabel(Container root, String label, Class<T> type);
281
282 /**
283 * Finds a <code>{@link Component}</code> by the text of its associated <code>{@link JLabel}</code> and type, in the
284 * hierarchy under the given root.
285 * @param <T> the parameterized type of the component to find.
286 * @param root the root used as the starting point of the search.
287 * @param label the text of the <code>JLabel</code> associated to the component to find.
288 * @param type the type of the component to find.
289 * @param showing indicates whether the component to find should be visible (or showing) or not.
290 * @return the found component.
291 * @throws ComponentLookupException if a matching component could not be found.
292 * @throws ComponentLookupException if more than one matching component is found.
293 * @see #findByLabel(String)
294 * @see JLabel#getLabelFor()
295 * @see JLabel#setLabelFor(Component)
296 */
297 <T extends Component> T findByLabel(Container root, String label, Class<T> type, boolean showing);
298
299 /**
300 * <p>
301 * Finds a <code>{@link Component}</code> by name. If this finder is attached to a <code>{@link Robot}</code>, it
302 * will use the component lookup scope in the <code>Robot</code>'s <code>{@link Settings}</code> to determine whether
303 * the component to find should be showing or not. If this finder is <em>not</em> attached to any <code>Robot</code>,
304 * the component to find does not have to be showing.
305 * </p>
306 * <p>
307 * Let's assume we have the <code>{@link javax.swing.JTextField}</code> with name "myTextBox";
308 *
309 * <pre>
310 * JTextField textbox = new JTextField();
311 * textBox.setName("myTextBox");
312 * </pre>
313 *
314 * </p>
315 * <p>
316 * To get a reference to this <code>{@link javax.swing.JTextField}</code> by its name, we can specify:
317 *
318 * <pre>
319 * JTextField textBox = (JTextField) finder.findByName("myTextBox");
320 * </pre>
321 *
322 * </p>
323 * <p>
324 * Please note that you need to cast the result of the lookup to the right type. To avoid casting, please use one of
325 * following:
326 * <ol>
327 * <li><code>{@link #findByName(String, Class)}</code></li>
328 * <li><code>{@link #findByName(String, Class, boolean)}</code></li>
329 * <li><code>{@link #findByName(Container, String, Class)}</code></li>
330 * <li><code>{@link #findByName(Container, String, Class, boolean)}</code></li>
331 * </ol>
332 * </p>
333 * @param name the name of the component to find.
334 * @return the found component.
335 * @throws ComponentLookupException if a matching component could not be found.
336 * @throws ComponentLookupException if more than one matching component is found.
337 * @see Robot#settings()
338 * @see Settings#componentLookupScope()
339 * @see ComponentLookupScope
340 */
341 Component findByName(String name);
342
343 /**
344 * Finds a <code>{@link Component}</code> by name and type. If this finder is attached to a
345 * <code>{@link Robot}</code>, it will use the component lookup scope in the <code>Robot</code>'s
346 * <code>{@link Settings}</code> to determine whether the component to find should be showing or not. If this finder
347 * is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be showing.
348 * @param <T> the parameterized type of the component to find.
349 * @param name the name of the component to find.
350 * @param type the type of the component to find.
351 * @return the found component.
352 * @throws ComponentLookupException if a matching component could not be found.
353 * @throws ComponentLookupException if more than one matching component is found.
354 * @see Robot#settings()
355 * @see Settings#componentLookupScope()
356 * @see ComponentLookupScope
357 * @see #findByName(String)
358 */
359 <T extends Component> T findByName(String name, Class<T> type);
360
361 /**
362 * Finds a <code>{@link Component}</code> by name and type.
363 * @param <T> the parameterized type of the component to find.
364 * @param name the name of the component to find.
365 * @param type the type of the component to find.
366 * @param showing indicates whether the component to find should be visible (or showing) or not.
367 * @return the found component.
368 * @throws ComponentLookupException if a matching component could not be found.
369 * @throws ComponentLookupException if more than one matching component is found.
370 * @see #findByName(String)
371 */
372 <T extends Component> T findByName(String name, Class<T> type, boolean showing);
373
374 /**
375 * Finds a <code>{@link Component}</code> by name.
376 * @param name the name of the component to find.
377 * @param showing indicates whether the component to find should be visible (or showing) or not.
378 * @return the found component.
379 * @throws ComponentLookupException if a matching component could not be found.
380 * @throws ComponentLookupException if more than one matching component is found.
381 * @see #findByName(String)
382 */
383 Component findByName(String name, boolean showing);
384
385 /**
386 * Finds a <code>{@link Component}</code> by name, in the hierarchy under the given root. If this finder is attached
387 * to a <code>{@link Robot}</code>, it will use the component lookup scope in the <code>Robot</code>'s
388 * <code>{@link Settings}</code> to determine whether the component to find should be showing or not. If this finder
389 * is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be showing.
390 * @param root the root used as the starting point of the search.
391 * @param name the name of the component to find.
392 * @return the found component.
393 * @throws ComponentLookupException if a matching component could not be found.
394 * @throws ComponentLookupException if more than one matching component is found.
395 * @see Robot#settings()
396 * @see Settings#componentLookupScope()
397 * @see ComponentLookupScope
398 * @see #findByName(String)
399 */
400 Component findByName(Container root, String name);
401
402 /**
403 * Finds a <code>{@link Component}</code> by name, in the hierarchy under the given root.
404 * @param root the root used as the starting point of the search.
405 * @param name the name of the component to find.
406 * @param showing indicates whether the component to find should be visible (or showing) or not.
407 * @return the found component.
408 * @throws ComponentLookupException if a matching component could not be found.
409 * @throws ComponentLookupException if more than one matching component is found.
410 * @see #findByName(String)
411 */
412 Component findByName(Container root, String name, boolean showing);
413
414 /**
415 * Finds a <code>{@link Component}</code> by name and type, in the hierarchy under the given root. If this finder is
416 * attached to a <code>{@link Robot}</code>, it will use the component lookup scope in the <code>Robot</code>'s
417 * <code>{@link Settings}</code> to determine whether the component to find should be showing or not. If this finder
418 * is <em>not</em> attached to any <code>Robot</code>, the component to find does not have to be showing.
419 * @param <T> the parameterized type of the component to find.
420 * @param root the root used as the starting point of the search.
421 * @param name the name of the component to find.
422 * @param type the type of the component to find.
423 * @return the found component.
424 * @throws ComponentLookupException if a matching component could not be found.
425 * @throws ComponentLookupException if more than one matching component is found.
426 * @see Robot#settings()
427 * @see Settings#componentLookupScope()
428 * @see ComponentLookupScope
429 * @see #findByName(String)
430 */
431 <T extends Component> T findByName(Container root, String name, Class<T> type);
432
433 /**
434 * Finds a <code>{@link Component}</code> by name and type, in the hierarchy under the given root.
435 * @param <T> the parameterized type of the component to find.
436 * @param root the root used as the starting point of the search.
437 * @param name the name of the component to find.
438 * @param type the type of the component to find.
439 * @param showing indicates whether the component to find should be visible (or showing) or not.
440 * @return the found component.
441 * @throws ComponentLookupException if a matching component could not be found.
442 * @throws ComponentLookupException if more than one matching component is found.
443 * @see #findByName(String)
444 */
445 <T extends Component> T findByName(Container root, String name, Class<T> type, boolean showing);
446
447 /**
448 * Finds a <code>{@link Component}</code> using the given <code>{@link ComponentMatcher}</code>. The given matcher
449 * will be evaluated in the event dispatch thread. Implementations of <code>ComponentMatcher</code> do not need to
450 * be concerned about the event dispatch thread.
451 * @param m the matcher to use to find the component of interest.
452 * @return the found component.
453 * @throws ComponentLookupException if a matching component could not be found.
454 * @throws ComponentLookupException if more than one matching component is found.
455 */
456 Component find(ComponentMatcher m);
457
458 /**
459 * Finds a <code>{@link Component}</code> using the given <code>{@link GenericTypeMatcher}</code>. The given matcher
460 * will be evaluated in the event dispatch thread. Implementations of <code>GenericTypeMatcher</code> do not need to
461 * be concerned about the event dispatch thread.
462 * @param <T> the type of component the given matcher can handle.
463 * @param m the matcher to use to find the component of interest.
464 * @return the found component.
465 * @throws ComponentLookupException if a matching component could not be found.
466 * @throws ComponentLookupException if more than one matching component is found.
467 */
468 <T extends Component> T find(GenericTypeMatcher<T> m);
469
470 /**
471 * Finds a <code>{@link Component}</code> using the given <code>{@link GenericTypeMatcher}</code> in the hierarchy
472 * under the given root. The given matcher will be evaluated in the event dispatch thread. Implementations of
473 * <code>GenericTypeMatcher</code> do not need to be concerned about the event dispatch thread.
474 * @param <T> the type of component the given matcher can handle.
475 * @param root the root used as the starting point of the search.
476 * @param m the matcher to use to find the component.
477 * @return the found component.
478 * @throws ComponentLookupException if a matching component could not be found.
479 * @throws ComponentLookupException if more than one matching component is found.
480 */
481 <T extends Component> T find(Container root, GenericTypeMatcher<T> m);
482
483 /**
484 * Finds a <code>{@link Component}</code> using the given <code>{@link ComponentMatcher}</code> in the hierarchy
485 * under the given root. The given matcher will be evaluated in the event dispatch thread. Implementations of
486 * <code>ComponentMatcher</code> do not need to be concerned about the event dispatch thread.
487 * @param root the root used as the starting point of the search.
488 * @param m the matcher to use to find the component.
489 * @return the found component.
490 * @throws ComponentLookupException if a matching component could not be found.
491 * @throws ComponentLookupException if more than one matching component is found.
492 */
493 Component find(Container root, ComponentMatcher m);
494
495 /**
496 * Returns all the <code>{@link Component}</code>s that match the search criteria specified in the given
497 * <code>{@link ComponentMatcher}</code>.
498 * @param m the matcher to use to find the component.
499 * @return all the <code>Component</code>s that match the search criteria specified in the given
500 * <code>ComponentMatcher</code>; or an empty collection, if there are no matching components.
501 */
502 Collection<Component> findAll(ComponentMatcher m);
503
504 /**
505 * Returns all the <code>{@link Component}</code>s under the given root that match the search criteria specified in
506 * the given <code>{@link ComponentMatcher}</code>.
507 * @param root the root used as the starting point of the search.
508 * @param m the matcher to use to find the component.
509 * @return all the <code>Component</code>s under the given root that match the search criteria specified in the given
510 * <code>ComponentMatcher</code>; or an empty collection, if there are no matching components.
511 */
512 Collection<Component> findAll(Container root, ComponentMatcher m);
513
514 /**
515 * Returns all the <code>{@link Component}</code>s that match the search criteria specified in the given
516 * <code>{@link GenericTypeMatcher}</code>.
517 * @param <T> the generic type of component that this search supports.
518 * @param m the matcher to use to find the component.
519 * @return all the <code>Component</code>s that match the search criteria specified in the given
520 * <code>GenericTypeMatcher</code>; or an empty collection, if there are no matching components.
521 */
522 <T extends Component> Collection<T> findAll(GenericTypeMatcher<T> m);
523
524 /**
525 * Returns all the <code>{@link Component}</code>s under the given root that match the search criteria specified in
526 * the given <code>{@link GenericTypeMatcher}</code>.
527 * @param <T> the generic type of component that this search supports.
528 * @param root the root used as the starting point of the search.
529 * @param m the matcher to use to find the component.
530 * @return all the <code>Component</code>s under the given root that match the search criteria specified in the given
531 * <code>GenericTypeMatcher</code>; or an empty collection, if there are no matching components.
532 */
533 <T extends Component> Collection<T> findAll(Container root, GenericTypeMatcher<T> m);
534
535 /**
536 * Returns whether the message in a <code>{@link ComponentLookupException}</code> should include the current component
537 * hierarchy. The default value is <code>true</code>.
538 * @return <code>true</code> if the component hierarchy is included as part of the
539 * <code>ComponentLookupException</code> message, <code>false</code> otherwise.
540 */
541 boolean includeHierarchyIfComponentNotFound();
542
543 /**
544 * Updates whether the message in a <code>{@link ComponentLookupException}</code> should include the current component
545 * hierarchy. The default value is <code>true</code>.
546 * @param newValue the new value to set.
547 */
548 void includeHierarchyIfComponentNotFound(boolean newValue);
549 }