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. Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package org.netbeans.jemmy.operators;
26 
27 import java.awt.Component;
28 import java.awt.Container;
29 import java.awt.TextComponent;
30 import java.awt.event.TextListener;
31 import java.util.Hashtable;
32 
33 import org.netbeans.jemmy.Action;
34 import org.netbeans.jemmy.ComponentChooser;
35 import org.netbeans.jemmy.Outputable;
36 import org.netbeans.jemmy.TestOut;
37 import org.netbeans.jemmy.Timeoutable;
38 import org.netbeans.jemmy.Timeouts;
39 import org.netbeans.jemmy.drivers.DriverManager;
40 import org.netbeans.jemmy.drivers.TextDriver;
41 
42 /**
43  * This operator type covers java.awt.TextArea component.
44  *
45  *
46  * @see org.netbeans.jemmy.Timeouts
47  *
48  * @author Alexandre Iline (alexandre.iline@oracle.com)
49  *
50  */
51 public class TextComponentOperator extends ComponentOperator
52         implements Timeoutable, Outputable {
53 
54     /**
55      * Identifier for a "text" property.
56      *
57      * @see #getDump
58      */
59     public static final String TEXT_DPROP = "Text";
60 
61     private final static long PUSH_KEY_TIMEOUT = 0;
62     private final static long BETWEEN_KEYS_TIMEOUT = 0;
63     private final static long CHANGE_CARET_POSITION_TIMEOUT = 60000;
64     private final static long TYPE_TEXT_TIMEOUT = 60000;
65 
66     private Timeouts timeouts;
67     private TestOut output;
68 
69     private TextDriver driver;
70 
71     /**
72      * Constructor.
73      *
74      * @param b The {@code java.awt.TextComponent} managed by this
75      * instance.
76      */
TextComponentOperator(TextComponent b)77     public TextComponentOperator(TextComponent b) {
78         super(b);
79         driver = DriverManager.getTextDriver(getClass());
80     }
81 
82     /**
83      * Constructs a TextComponentOperator object.
84      *
85      * @param cont a container
86      * @param chooser a component chooser specifying searching criteria.
87      * @param index an index between appropriate ones.
88      */
TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index)89     public TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index) {
90         this((TextComponent) cont.
91                 waitSubComponent(new TextComponentFinder(chooser),
92                         index));
93         copyEnvironment(cont);
94     }
95 
96     /**
97      * Constructs a TextComponentOperator object.
98      *
99      * @param cont a container
100      * @param chooser a component chooser specifying searching criteria.
101      */
TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser)102     public TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser) {
103         this(cont, chooser, 0);
104     }
105 
106     /**
107      * Constructor. Waits for a component in a container to show. The component
108      * is identified as the {@code index+1}'th
109      * {@code java.awt.TextComponent} that shows, lies below the container
110      * in the display containment hierarchy, and that has the desired text. Uses
111      * cont's timeout and output for waiting and to init this operator.
112      *
113      * @param cont The operator for a container containing the sought for
114      * textComponent.
115      * @param text TextComponent text.
116      * @param index Ordinal component index. The first component has
117      * {@code index} 0.
118      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
119      */
TextComponentOperator(ContainerOperator<?> cont, String text, int index)120     public TextComponentOperator(ContainerOperator<?> cont, String text, int index) {
121         this((TextComponent) waitComponent(cont,
122                 new TextComponentByTextFinder(text,
123                         cont.getComparator()),
124                 index));
125         copyEnvironment(cont);
126     }
127 
128     /**
129      * Constructor. Waits for a component in a container to show. The component
130      * is identified as the first {@code java.awt.TextComponent} that
131      * shows, lies below the container in the display containment hierarchy, and
132      * that has the desired text. Uses cont's timeout and output for waiting and
133      * to init this operator.
134      *
135      * @param cont The operator for a container containing the sought for
136      * textComponent.
137      * @param text TextComponent text.
138      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
139      */
TextComponentOperator(ContainerOperator<?> cont, String text)140     public TextComponentOperator(ContainerOperator<?> cont, String text) {
141         this(cont, text, 0);
142     }
143 
144     /**
145      * Constructor. Waits component in container first. Uses cont's timeout and
146      * output for waiting and to init operator.
147      *
148      * @param cont The operator for a container containing the sought for
149      * textComponent.
150      * @param index Ordinal component index.
151      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
152      */
TextComponentOperator(ContainerOperator<?> cont, int index)153     public TextComponentOperator(ContainerOperator<?> cont, int index) {
154         this((TextComponent) waitComponent(cont,
155                 new TextComponentFinder(),
156                 index));
157         copyEnvironment(cont);
158     }
159 
160     /**
161      * Constructor. Waits component in container first. Uses cont's timeout and
162      * output for waiting and to init operator.
163      *
164      * @param cont The operator for a container containing the sought for
165      * textComponent.
166      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
167      */
TextComponentOperator(ContainerOperator<?> cont)168     public TextComponentOperator(ContainerOperator<?> cont) {
169         this(cont, 0);
170     }
171 
172     /**
173      * Searches TextComponent in a container.
174      *
175      * @param cont Container in which to search for the component. The container
176      * lies above the component in the display containment hierarchy. The
177      * containment need not be direct.
178      * @param chooser org.netbeans.jemmy.ComponentChooser implementation,
179      * defining and applying search criteria.
180      * @param index Ordinal component index. The first {@code index} is 0.
181      * @return TextComponent instance or null if component was not found.
182      */
findTextComponent(Container cont, ComponentChooser chooser, int index)183     public static TextComponent findTextComponent(Container cont, ComponentChooser chooser, int index) {
184         return (TextComponent) findComponent(cont, new TextComponentFinder(chooser), index);
185     }
186 
187     /**
188      * Searches for the first TextComponent in a container.
189      *
190      * @param cont Container in which to search for the component. The container
191      * lies above the component in the display containment hierarchy. The
192      * containment need not be direct.
193      * @param chooser org.netbeans.jemmy.ComponentChooser implementation,
194      * defining and applying search criteria.
195      * @return TextComponent instance or null if component was not found.
196      */
findTextComponent(Container cont, ComponentChooser chooser)197     public static TextComponent findTextComponent(Container cont, ComponentChooser chooser) {
198         return findTextComponent(cont, chooser, 0);
199     }
200 
201     /**
202      * Searches TextComponent by text.
203      *
204      * @param cont Container to search component in.
205      * @param text TextComponent text. If null, contents is not checked.
206      * @param ce Compare text exactly.
207      * @param ccs Compare text case sensitively.
208      * @param index Ordinal component index.
209      * @return TextComponent instance or null if component was not found.
210      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
211      */
findTextComponent(Container cont, String text, boolean ce, boolean ccs, int index)212     public static TextComponent findTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) {
213         return findTextComponent(cont, new TextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index);
214     }
215 
216     /**
217      * Searches TextComponent by text.
218      *
219      * @param cont Container to search component in.
220      * @param text TextComponent text. If null, contents is not checked.
221      * @param ce Compare text exactly.
222      * @param ccs Compare text case sensitively.
223      * @return TextComponent instance or null if component was not found.
224      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
225      */
findTextComponent(Container cont, String text, boolean ce, boolean ccs)226     public static TextComponent findTextComponent(Container cont, String text, boolean ce, boolean ccs) {
227         return findTextComponent(cont, text, ce, ccs, 0);
228     }
229 
230     /**
231      * Waits TextComponent in container.
232      *
233      * @param cont Container to search component in.
234      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
235      * @param index Ordinal component index.
236      * @return TextComponent instance.
237      */
waitTextComponent(Container cont, ComponentChooser chooser, int index)238     public static TextComponent waitTextComponent(Container cont, ComponentChooser chooser, int index) {
239         return (TextComponent) waitComponent(cont, new TextComponentFinder(chooser), index);
240     }
241 
242     /**
243      * Waits 0'th TextComponent in container.
244      *
245      * @param cont Container to search component in.
246      * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
247      * @return TextComponent instance.
248      */
waitTextComponent(Container cont, ComponentChooser chooser)249     public static TextComponent waitTextComponent(Container cont, ComponentChooser chooser) {
250         return waitTextComponent(cont, chooser, 0);
251     }
252 
253     /**
254      * Waits TextComponent by text.
255      *
256      * @param cont Container to search component in.
257      * @param text TextComponent text. If null, contents is not checked.
258      * @param ce Compare text exactly.
259      * @param ccs Compare text case sensitively.
260      * @param index Ordinal component index.
261      * @return TextComponent instance.
262      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
263      */
waitTextComponent(Container cont, String text, boolean ce, boolean ccs, int index)264     public static TextComponent waitTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) {
265         return waitTextComponent(cont, new TextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index);
266     }
267 
268     /**
269      * Waits TextComponent by text.
270      *
271      * @param cont Container to search component in.
272      * @param text TextComponent text. If null, contents is not checked.
273      * @param ce Compare text exactly.
274      * @param ccs Compare text case sensitively.
275      * @return TextComponent instance.
276      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
277      */
waitTextComponent(Container cont, String text, boolean ce, boolean ccs)278     public static TextComponent waitTextComponent(Container cont, String text, boolean ce, boolean ccs) {
279         return waitTextComponent(cont, text, ce, ccs, 0);
280     }
281 
282     static {
283         Timeouts.initDefault("TextComponentOperator.PushKeyTimeout", PUSH_KEY_TIMEOUT);
284         Timeouts.initDefault("TextComponentOperator.BetweenKeysTimeout", BETWEEN_KEYS_TIMEOUT);
285         Timeouts.initDefault("TextComponentOperator.ChangeCaretPositionTimeout", CHANGE_CARET_POSITION_TIMEOUT);
286         Timeouts.initDefault("TextComponentOperator.TypeTextTimeout", TYPE_TEXT_TIMEOUT);
287     }
288 
289     @Override
setTimeouts(Timeouts timeouts)290     public void setTimeouts(Timeouts timeouts) {
291         super.setTimeouts(timeouts);
292         this.timeouts = timeouts;
293     }
294 
295     @Override
getTimeouts()296     public Timeouts getTimeouts() {
297         return timeouts;
298     }
299 
300     @Override
setOutput(TestOut out)301     public void setOutput(TestOut out) {
302         output = out;
303         super.setOutput(output.createErrorOutput());
304     }
305 
306     @Override
getOutput()307     public TestOut getOutput() {
308         return output;
309     }
310 
311     @Override
copyEnvironment(Operator anotherOperator)312     public void copyEnvironment(Operator anotherOperator) {
313         super.copyEnvironment(anotherOperator);
314         driver
315                 = (TextDriver) DriverManager.
316                 getDriver(DriverManager.TEXT_DRIVER_ID,
317                         getClass(),
318                         anotherOperator.getProperties());
319     }
320 
321     /**
322      * Changes caret position.
323      *
324      * @param position Position to move caret to.
325      *
326      */
changeCaretPosition(final int position)327     public void changeCaretPosition(final int position) {
328         makeComponentVisible();
329         produceTimeRestricted(new Action<Void, Void>() {
330             @Override
331             public Void launch(Void obj) {
332                 driver.changeCaretPosition(TextComponentOperator.this, position);
333                 return null;
334             }
335 
336             @Override
337             public String getDescription() {
338                 return "Caret moving";
339             }
340 
341             @Override
342             public String toString() {
343                 return "TextComponentOperator.changeCaretPosition.Action{description = " + getDescription() + '}';
344             }
345         }, "TextComponentOperator.ChangeCaretPositionTimeout");
346     }
347 
348     /**
349      * Selects a part of text.
350      *
351      * @param startPosition Start caret position
352      * @param finalPosition Final caret position
353      *
354      */
selectText(final int startPosition, final int finalPosition)355     public void selectText(final int startPosition, final int finalPosition) {
356         makeComponentVisible();
357         produceTimeRestricted(new Action<Void, Void>() {
358             @Override
359             public Void launch(Void obj) {
360                 driver.selectText(TextComponentOperator.this, startPosition, finalPosition);
361                 return null;
362             }
363 
364             @Override
365             public String getDescription() {
366                 return "Text selecting";
367             }
368 
369             @Override
370             public String toString() {
371                 return "TextComponentOperator.selectText.Action{description = " + getDescription() + '}';
372             }
373         }, "TextComponentOperator.TypeTextTimeout");
374     }
375 
376     /**
377      * Finds start text position.
378      *
379      * @param text Text to be searched.
380      * @param index Index of text instance (first instance has index 0)
381      * @return Caret position correspondent to text start.
382      */
getPositionByText(String text, int index)383     public int getPositionByText(String text, int index) {
384         String allText = getText();
385         int position = 0;
386         int ind = 0;
387         while ((position = allText.indexOf(text, position)) >= 0) {
388             if (ind == index) {
389                 return position;
390             } else {
391                 ind++;
392             }
393             position = position + text.length();
394         }
395         return -1;
396     }
397 
398     /**
399      * Finds start text position.
400      *
401      * @param text Text to be searched.
402      * @return Caret position correspondent to text start.
403      */
getPositionByText(String text)404     public int getPositionByText(String text) {
405         return getPositionByText(text, 0);
406     }
407 
408     /**
409      * Clears text.
410      *
411      */
clearText()412     public void clearText() {
413         output.printLine("Clearing text in text component\n    : "
414                 + toStringSource());
415         output.printGolden("Clearing text in text component");
416         makeComponentVisible();
417         produceTimeRestricted(new Action<Void, Void>() {
418             @Override
419             public Void launch(Void obj) {
420                 driver.clearText(TextComponentOperator.this);
421                 return null;
422             }
423 
424             @Override
425             public String getDescription() {
426                 return "Text clearing";
427             }
428 
429             @Override
430             public String toString() {
431                 return "TextComponentOperator.clearText.Action{description = " + getDescription() + '}';
432             }
433         }, "TextComponentOperator.TypeTextTimeout");
434     }
435 
436     /**
437      * Types text starting from known position.
438      *
439      * @param text Text to be typed.
440      * @param caretPosition Position to start type text
441      */
typeText(final String text, final int caretPosition)442     public void typeText(final String text, final int caretPosition) {
443         output.printLine("Typing text \"" + text + "\" from "
444                 + Integer.toString(caretPosition) + " position "
445                 + "in text component\n    : "
446                 + toStringSource());
447         output.printGolden("Typing text \"" + text + "\" in text component");
448         makeComponentVisible();
449         produceTimeRestricted(new Action<Void, Void>() {
450             @Override
451             public Void launch(Void obj) {
452                 driver.typeText(TextComponentOperator.this, text, caretPosition);
453                 return null;
454             }
455 
456             @Override
457             public String getDescription() {
458                 return "Text typing";
459             }
460 
461             @Override
462             public String toString() {
463                 return "TextComponentOperator.typeText.Action{description = " + getDescription() + '}';
464             }
465         }, "TextComponentOperator.TypeTextTimeout");
466     }
467 
468     /**
469      * Types text starting from known position.
470      *
471      * @param text Text to be typed.
472      */
typeText(String text)473     public void typeText(String text) {
474         typeText(text, getCaretPosition());
475     }
476 
477     /**
478      * Requests a focus, clears text, types new one and pushes Enter.
479      *
480      * @param text New text value. Shouldn't include final '\n'.
481      *
482      */
enterText(final String text)483     public void enterText(final String text) {
484         makeComponentVisible();
485         produceTimeRestricted(new Action<Void, Void>() {
486             @Override
487             public Void launch(Void obj) {
488                 driver.enterText(TextComponentOperator.this, text);
489                 return null;
490             }
491 
492             @Override
493             public String getDescription() {
494                 return "Text entering";
495             }
496 
497             @Override
498             public String toString() {
499                 return "TextComponentOperator.enterText.Action{description = " + getDescription() + '}';
500             }
501         }, "TextComponentOperator.TypeTextTimeout");
502     }
503 
504     @Override
getDump()505     public Hashtable<String, Object> getDump() {
506         Hashtable<String, Object> result = super.getDump();
507         result.put(TEXT_DPROP, ((TextComponent) getSource()).getText());
508         return result;
509     }
510 
511     ////////////////////////////////////////////////////////
512     //Mapping                                             //
513     /**
514      * Maps {@code TextComponent.addTextListener(TextListener)} through queue
515      */
addTextListener(final TextListener textListener)516     public void addTextListener(final TextListener textListener) {
517         runMapping(new MapVoidAction("addTextListener") {
518             @Override
519             public void map() {
520                 ((TextComponent) getSource()).addTextListener(textListener);
521             }
522         });
523     }
524 
525     /**
526      * Maps {@code TextComponent.getCaretPosition()} through queue
527      */
getCaretPosition()528     public int getCaretPosition() {
529         return (runMapping(new MapIntegerAction("getCaretPosition") {
530             @Override
531             public int map() {
532                 return ((TextComponent) getSource()).getCaretPosition();
533             }
534         }));
535     }
536 
537     /**
538      * Maps {@code TextComponent.getSelectedText()} through queue
539      */
540     public String getSelectedText() {
541         return (runMapping(new MapAction<String>("getSelectedText") {
542             @Override
543             public String map() {
544                 return ((TextComponent) getSource()).getSelectedText();
545             }
546         }));
547     }
548 
549     /**
550      * Maps {@code TextComponent.getSelectionEnd()} through queue
551      */
552     public int getSelectionEnd() {
553         return (runMapping(new MapIntegerAction("getSelectionEnd") {
554             @Override
555             public int map() {
556                 return ((TextComponent) getSource()).getSelectionEnd();
557             }
558         }));
559     }
560 
561     /**
562      * Maps {@code TextComponent.getSelectionStart()} through queue
563      */
564     public int getSelectionStart() {
565         return (runMapping(new MapIntegerAction("getSelectionStart") {
566             @Override
567             public int map() {
568                 return ((TextComponent) getSource()).getSelectionStart();
569             }
570         }));
571     }
572 
573     /**
574      * Maps {@code TextComponent.getText()} through queue
575      */
576     public String getText() {
577         return (runMapping(new MapAction<String>("getText") {
578             @Override
579             public String map() {
580                 return ((TextComponent) getSource()).getText();
581             }
582         }));
583     }
584 
585     /**
586      * Maps {@code TextComponent.isEditable()} through queue
587      */
588     public boolean isEditable() {
589         return (runMapping(new MapBooleanAction("isEditable") {
590             @Override
591             public boolean map() {
592                 return ((TextComponent) getSource()).isEditable();
593             }
594         }));
595     }
596 
597     /**
598      * Maps {@code TextComponent.removeTextListener(TextListener)} through queue
599      */
600     public void removeTextListener(final TextListener textListener) {
601         runMapping(new MapVoidAction("removeTextListener") {
602             @Override
603             public void map() {
604                 ((TextComponent) getSource()).removeTextListener(textListener);
605             }
606         });
607     }
608 
609     /**
610      * Maps {@code TextComponent.select(int, int)} through queue
611      */
612     public void select(final int i, final int i1) {
613         runMapping(new MapVoidAction("select") {
614             @Override
615             public void map() {
616                 ((TextComponent) getSource()).select(i, i1);
617             }
618         });
619     }
620 
621     /**
622      * Maps {@code TextComponent.selectAll()} through queue
623      */
624     public void selectAll() {
625         runMapping(new MapVoidAction("selectAll") {
626             @Override
627             public void map() {
628                 ((TextComponent) getSource()).selectAll();
629             }
630         });
631     }
632 
633     /**
634      * Maps {@code TextComponent.setCaretPosition(int)} through queue
635      */
636     public void setCaretPosition(final int i) {
637         runMapping(new MapVoidAction("setCaretPosition") {
638             @Override
639             public void map() {
640                 ((TextComponent) getSource()).setCaretPosition(i);
641             }
642         });
643     }
644 
645     /**
646      * Maps {@code TextComponent.setEditable(boolean)} through queue
647      */
648     public void setEditable(final boolean b) {
649         runMapping(new MapVoidAction("setEditable") {
650             @Override
651             public void map() {
652                 ((TextComponent) getSource()).setEditable(b);
653             }
654         });
655     }
656 
657     /**
658      * Maps {@code TextComponent.setSelectionEnd(int)} through queue
659      */
660     public void setSelectionEnd(final int i) {
661         runMapping(new MapVoidAction("setSelectionEnd") {
662             @Override
663             public void map() {
664                 ((TextComponent) getSource()).setSelectionEnd(i);
665             }
666         });
667     }
668 
669     /**
670      * Maps {@code TextComponent.setSelectionStart(int)} through queue
671      */
672     public void setSelectionStart(final int i) {
673         runMapping(new MapVoidAction("setSelectionStart") {
674             @Override
675             public void map() {
676                 ((TextComponent) getSource()).setSelectionStart(i);
677             }
678         });
679     }
680 
681     /**
682      * Maps {@code TextComponent.setText(String)} through queue
683      */
684     public void setText(final String string) {
685         runMapping(new MapVoidAction("setText") {
686             @Override
687             public void map() {
688                 ((TextComponent) getSource()).setText(string);
689             }
690         });
691     }
692 
693     //End of mapping                                      //
694     ////////////////////////////////////////////////////////
695     /**
696      * Return a TextDriver used by this component.
697      *
698      * @return a driver got by the operator during creation.
699      */
700     protected TextDriver getTextDriver() {
701         return driver;
702     }
703 
704     /**
705      * Allows to find component by text.
706      */
707     public static class TextComponentByTextFinder implements ComponentChooser {
708 
709         String label;
710         StringComparator comparator;
711 
712         /**
713          * Constructs TextComponentByTextFinder.
714          *
715          * @param lb a text pattern
716          * @param comparator specifies string comparision algorithm.
717          */
718         public TextComponentByTextFinder(String lb, StringComparator comparator) {
719             label = lb;
720             this.comparator = comparator;
721         }
722 
723         /**
724          * Constructs TextComponentByTextFinder.
725          *
726          * @param lb a text pattern
727          */
728         public TextComponentByTextFinder(String lb) {
729             this(lb, Operator.getDefaultStringComparator());
730         }
731 
732         @Override
733         public boolean checkComponent(Component comp) {
734             if (comp instanceof TextComponent) {
735                 if (((TextComponent) comp).getText() != null) {
736                     return (comparator.equals(((TextComponent) comp).getText(),
737                             label));
738                 }
739             }
740             return false;
741         }
742 
743         @Override
744         public String getDescription() {
745             return "TextComponent with text \"" + label + "\"";
746         }
747 
748         @Override
749         public String toString() {
750             return "TextComponentByTextFinder{" + "label=" + label + ", comparator=" + comparator + '}';
751         }
752     }
753 
754     /**
755      * Checks component type.
756      */
757     public static class TextComponentFinder extends Finder {
758 
759         /**
760          * Constructs TextComponentFinder.
761          *
762          * @param sf other searching criteria.
763          */
764         public TextComponentFinder(ComponentChooser sf) {
765             super(TextComponent.class, sf);
766         }
767 
768         /**
769          * Constructs TextComponentFinder.
770          */
771         public TextComponentFinder() {
772             super(TextComponent.class);
773         }
774     }
775 }
776