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(&quot;Name&quot;);
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(&quot;myTextBox&quot;);
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(&quot;myTextBox&quot;);
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    }