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.Color;
28 import java.awt.Component;
29 import java.awt.Container;
30 import java.awt.Dimension;
31 import java.awt.Insets;
32 import java.awt.Point;
33 import java.awt.Rectangle;
34 import java.io.IOException;
35 import java.io.Reader;
36 import java.io.Writer;
37 import java.util.Hashtable;
38 
39 import javax.swing.JScrollPane;
40 import javax.swing.event.CaretListener;
41 import javax.swing.plaf.TextUI;
42 import javax.swing.text.BadLocationException;
43 import javax.swing.text.Caret;
44 import javax.swing.text.Document;
45 import javax.swing.text.Highlighter;
46 import javax.swing.text.JTextComponent;
47 import javax.swing.text.Keymap;
48 
49 import org.netbeans.jemmy.Action;
50 import org.netbeans.jemmy.ComponentChooser;
51 import org.netbeans.jemmy.ComponentSearcher;
52 import org.netbeans.jemmy.JemmyException;
53 import org.netbeans.jemmy.JemmyInputException;
54 import org.netbeans.jemmy.Outputable;
55 import org.netbeans.jemmy.TestOut;
56 import org.netbeans.jemmy.TimeoutExpiredException;
57 import org.netbeans.jemmy.Timeoutable;
58 import org.netbeans.jemmy.Timeouts;
59 import org.netbeans.jemmy.drivers.DriverManager;
60 import org.netbeans.jemmy.drivers.TextDriver;
61 import org.netbeans.jemmy.util.EmptyVisualizer;
62 
63 /**
64  *
65  * Class provides basic functions to operate with JTextComponent (selection,
66  * typing, deleting)
67  *
68  * <BR><BR>Timeouts used: <BR>
69  * JTextComponentOperator.PushKeyTimeout - time between key pressing and
70  * releasing during text typing <BR>
71  * JTextComponentOperator.BetweenKeysTimeout - time to sleep between two chars
72  * typing <BR>
73  * JTextComponentOperator.ChangeCaretPositionTimeout - maximum time to chenge
74  * caret position <BR>
75  * JTextComponentOperator.TypeTextTimeout - maximum time to type text <BR>
76  * ComponentOperator.WaitComponentTimeout - time to wait component displayed
77  * <BR>
78  * ComponentOperator.WaitFocusTimeout - time to wait component focus <BR>
79  * ComponentOperator.WaitStateTimeout - time to wait for text <BR>
80  * JScrollBarOperator.OneScrollClickTimeout - time for one scroll click <BR>
81  * JScrollBarOperator.WholeScrollTimeout - time for the whole scrolling <BR>.
82  *
83  * @see org.netbeans.jemmy.Timeouts
84  *
85  * @author Alexandre Iline (alexandre.iline@oracle.com)
86  */
87 public class JTextComponentOperator extends JComponentOperator
88         implements Timeoutable, Outputable {
89 
90     /**
91      * Identifier for a "text" property.
92      *
93      * @see #getDump
94      */
95     public static final String TEXT_DPROP = "Text";
96 
97     /**
98      * Identifier for a "selected text" property.
99      *
100      * @see #getDump
101      */
102     public static final String SELECTED_TEXT_DPROP = "Selected text";
103 
104     /**
105      * Identifier for a "editable" property.
106      *
107      * @see #getDump
108      */
109     public static final String IS_EDITABLE_DPROP = "Editable";
110 
111     private final static long PUSH_KEY_TIMEOUT = 0;
112     private final static long BETWEEN_KEYS_TIMEOUT = 0;
113     private final static long CHANGE_CARET_POSITION_TIMEOUT = 60000;
114     private final static long TYPE_TEXT_TIMEOUT = 60000;
115 
116     private Timeouts timeouts;
117     private TestOut output;
118 
119     /**
120      * Notifies what modifiers are pressed.
121      *
122      * @deprecated All text operations are performed by TextDriver regitered for
123      * this operator type.
124      */
125     @Deprecated
126     protected int modifiersPressed = 0;
127 
128     private TextDriver driver;
129 
130     /**
131      * Constructor.
132      *
133      * @param b Component to operate with.
134      */
JTextComponentOperator(JTextComponent b)135     public JTextComponentOperator(JTextComponent b) {
136         super(b);
137         driver = DriverManager.getTextDriver(getClass());
138     }
139 
140     /**
141      * Constructs a JTextComponentOperator object.
142      *
143      * @param cont a container
144      * @param chooser a component chooser specifying searching criteria.
145      * @param index an index between appropriate ones.
146      */
JTextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index)147     public JTextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index) {
148         this((JTextComponent) cont.
149                 waitSubComponent(new JTextComponentFinder(chooser),
150                         index));
151         copyEnvironment(cont);
152     }
153 
154     /**
155      * Constructs a JTextComponentOperator object.
156      *
157      * @param cont a container
158      * @param chooser a component chooser specifying searching criteria.
159      */
JTextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser)160     public JTextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser) {
161         this(cont, chooser, 0);
162     }
163 
164     /**
165      * Constructor. Waits component in container first. Uses cont's timeout and
166      * output for waiting and to init operator.
167      *
168      * @param cont a container
169      * @param text Button text.
170      * @param index Ordinal component index.
171      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
172      * @throws TimeoutExpiredException
173      */
JTextComponentOperator(ContainerOperator<?> cont, String text, int index)174     public JTextComponentOperator(ContainerOperator<?> cont, String text, int index) {
175         this((JTextComponent) waitComponent(cont,
176                 new JTextComponentByTextFinder(text,
177                         cont.getComparator()),
178                 index));
179         copyEnvironment(cont);
180     }
181 
182     /**
183      * Constructor. Waits component in container first. Uses cont's timeout and
184      * output for waiting and to init operator.
185      *
186      * @param cont a container
187      * @param text Button text.
188      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
189      * @throws TimeoutExpiredException
190      */
JTextComponentOperator(ContainerOperator<?> cont, String text)191     public JTextComponentOperator(ContainerOperator<?> cont, String text) {
192         this(cont, text, 0);
193     }
194 
195     /**
196      * Constructor. Waits component in container first. Uses cont's timeout and
197      * output for waiting and to init operator.
198      *
199      * @param cont a container
200      * @param index Ordinal component index.
201      * @throws TimeoutExpiredException
202      */
JTextComponentOperator(ContainerOperator<?> cont, int index)203     public JTextComponentOperator(ContainerOperator<?> cont, int index) {
204         this((JTextComponent) waitComponent(cont,
205                 new JTextComponentFinder(),
206                 index));
207         copyEnvironment(cont);
208     }
209 
210     /**
211      * Constructor. Waits component in container first. Uses cont's timeout and
212      * output for waiting and to init operator.
213      *
214      * @param cont a container
215      * @throws TimeoutExpiredException
216      */
JTextComponentOperator(ContainerOperator<?> cont)217     public JTextComponentOperator(ContainerOperator<?> cont) {
218         this(cont, 0);
219     }
220 
221     static {
222         Timeouts.initDefault("JTextComponentOperator.PushKeyTimeout", PUSH_KEY_TIMEOUT);
223         Timeouts.initDefault("JTextComponentOperator.BetweenKeysTimeout", BETWEEN_KEYS_TIMEOUT);
224         Timeouts.initDefault("JTextComponentOperator.ChangeCaretPositionTimeout", CHANGE_CARET_POSITION_TIMEOUT);
225         Timeouts.initDefault("JTextComponentOperator.TypeTextTimeout", TYPE_TEXT_TIMEOUT);
226     }
227 
228     /**
229      * Searches JTextComponent in container.
230      *
231      * @param cont Container to search component in.
232      * @param chooser a component chooser specifying searching criteria.
233      * @param index Ordinal component index.
234      * @return JTextComponent instance or null if component was not found.
235      */
findJTextComponent(Container cont, ComponentChooser chooser, int index)236     public static JTextComponent findJTextComponent(Container cont, ComponentChooser chooser, int index) {
237         return (JTextComponent) findComponent(cont, new JTextComponentFinder(chooser), index);
238     }
239 
240     /**
241      * Searches JTextComponent in container.
242      *
243      * @param cont Container to search component in.
244      * @param chooser a component chooser specifying searching criteria.
245      * @return JTextComponent instance or null if component was not found.
246      */
findJTextComponent(Container cont, ComponentChooser chooser)247     public static JTextComponent findJTextComponent(Container cont, ComponentChooser chooser) {
248         return findJTextComponent(cont, chooser, 0);
249     }
250 
251     /**
252      * Searches JTextComponent by text.
253      *
254      * @param cont Container to search component in.
255      * @param text Component text.
256      * @param ce Compare text exactly.
257      * @param ccs Compare text case sensitively.
258      * @param index Ordinal component index.
259      * @return JTextComponent instance or null if component was not found.
260      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
261      */
findJTextComponent(Container cont, String text, boolean ce, boolean ccs, int index)262     public static JTextComponent findJTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) {
263         return findJTextComponent(cont, new JTextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index);
264     }
265 
266     /**
267      * Searches JTextComponent by text.
268      *
269      * @param cont Container to search component in.
270      * @param text Component text.
271      * @param ce Compare text exactly.
272      * @param ccs Compare text case sensitively.
273      * @return JTextComponent instance or null if component was not found.
274      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
275      */
findJTextComponent(Container cont, String text, boolean ce, boolean ccs)276     public static JTextComponent findJTextComponent(Container cont, String text, boolean ce, boolean ccs) {
277         return findJTextComponent(cont, text, ce, ccs, 0);
278     }
279 
280     /**
281      * Waits JTextComponent in container.
282      *
283      * @param cont Container to search component in.
284      * @param chooser a component chooser specifying searching criteria.
285      * @param index Ordinal component index.
286      * @return JTextComponent instance.
287      * @throws TimeoutExpiredException
288      */
waitJTextComponent(final Container cont, final ComponentChooser chooser, final int index)289     public static JTextComponent waitJTextComponent(final Container cont, final ComponentChooser chooser, final int index) {
290         return (JTextComponent) waitComponent(cont, new JTextComponentFinder(chooser), index);
291     }
292 
293     /**
294      * Waits JTextComponent in container.
295      *
296      * @param cont Container to search component in.
297      * @param chooser a component chooser specifying searching criteria.
298      * @return JTextComponent instance.
299      * @throws TimeoutExpiredException
300      */
waitJTextComponent(Container cont, ComponentChooser chooser)301     public static JTextComponent waitJTextComponent(Container cont, ComponentChooser chooser) {
302         return waitJTextComponent(cont, chooser, 0);
303     }
304 
305     /**
306      * Waits JTextComponent by text.
307      *
308      * @param cont Container to search component in.
309      * @param text Component text.
310      * @param ce Compare text exactly.
311      * @param ccs Compare text case sensitively.
312      * @param index Ordinal component index.
313      * @return JTextComponent instance.
314      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
315      * @throws TimeoutExpiredException
316      */
waitJTextComponent(Container cont, String text, boolean ce, boolean ccs, int index)317     public static JTextComponent waitJTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) {
318         return waitJTextComponent(cont, new JTextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index);
319     }
320 
321     /**
322      * Waits JTextComponent by text.
323      *
324      * @param cont Container to search component in.
325      * @param text Component text.
326      * @param ce Compare text exactly.
327      * @param ccs Compare text case sensitively.
328      * @return JTextComponent instance.
329      * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
330      * @throws TimeoutExpiredException
331      */
waitJTextComponent(Container cont, String text, boolean ce, boolean ccs)332     public static JTextComponent waitJTextComponent(Container cont, String text, boolean ce, boolean ccs) {
333         return waitJTextComponent(cont, text, ce, ccs, 0);
334     }
335 
336     @Override
setTimeouts(Timeouts times)337     public void setTimeouts(Timeouts times) {
338         timeouts = times;
339         timeouts.setTimeout("ComponentOperator.PushKeyTimeout",
340                 timeouts.getTimeout("JTextComponentOperator.PushKeyTimeout"));
341         super.setTimeouts(timeouts);
342     }
343 
344     @Override
getTimeouts()345     public Timeouts getTimeouts() {
346         return timeouts;
347     }
348 
349     @Override
setOutput(TestOut out)350     public void setOutput(TestOut out) {
351         output = out;
352         super.setOutput(output.createErrorOutput());
353     }
354 
355     @Override
getOutput()356     public TestOut getOutput() {
357         return output;
358     }
359 
360     @Override
copyEnvironment(Operator anotherOperator)361     public void copyEnvironment(Operator anotherOperator) {
362         super.copyEnvironment(anotherOperator);
363         driver
364                 = (TextDriver) DriverManager.
365                 getDriver(DriverManager.TEXT_DRIVER_ID,
366                         getClass(),
367                         anotherOperator.getProperties());
368     }
369 
370     /**
371      * Finds start text position.
372      *
373      * @param text Text to be searched.
374      * @param tChooser Additional search criteria.
375      * @param index Index of text instance (first instance has index 0)
376      * @return Caret position correspondent to text start.
377      * @see JTextComponentOperator.TextChooser
378      */
getPositionByText(String text, TextChooser tChooser, int index)379     public int getPositionByText(String text, TextChooser tChooser, int index) {
380         output.printLine("Find " + tChooser.getDescription() + "\"" + text
381                 + "\" text in text component\n    : "
382                 + toStringSource());
383         output.printGolden("Find " + tChooser.getDescription() + "\"" + text
384                 + "\" text in text component");
385         String allText = getDisplayedText();
386         Document doc = getDocument();
387         int position = 0;
388         int ind = 0;
389         while ((position = allText.indexOf(text, position)) >= 0) {
390             if (tChooser.checkPosition(doc, position)) {
391                 if (ind == index) {
392                     return position;
393                 } else {
394                     ind++;
395                 }
396             }
397             position = position + text.length();
398         }
399         return -1;
400     }
401 
402     /**
403      * Finds start text position.
404      *
405      * @param text Text to be searched.
406      * @param tChooser Additional search criteria.
407      * @return Caret position correspondent to text start.
408      */
getPositionByText(String text, TextChooser tChooser)409     public int getPositionByText(String text, TextChooser tChooser) {
410         return getPositionByText(text, tChooser, 0);
411     }
412 
413     /**
414      * Finds start text position.
415      *
416      * @param text Text to be searched.
417      * @param index Index of text instance (first instance has index 0)
418      * @return Caret position correspondent to text start.
419      */
getPositionByText(String text, int index)420     public int getPositionByText(String text, int index) {
421         return (getPositionByText(text, new TextChooser() {
422             @Override
423             public boolean checkPosition(Document doc, int offset) {
424                 return true;
425             }
426 
427             @Override
428             public String getDescription() {
429                 return "any";
430             }
431 
432             @Override
433             public String toString() {
434                 return "JTextComponentOperator.getPositionByText.TextChooser{description = " + getDescription() + '}';
435             }
436         }, index));
437     }
438 
439     /**
440      * Finds start text position.
441      *
442      * @param text Text to be searched.
443      * @return Caret position correspondent to text start.
444      */
445     public int getPositionByText(String text) {
446         return getPositionByText(text, 0);
447     }
448 
449     /**
450      * Requests a focus, clears text, types new one and pushes Enter.
451      *
452      * @param text New text value. Shouldn't include final '\n'.
453      * @throws TimeoutExpiredException
454      */
455     public void enterText(final String text) {
456         makeComponentVisible();
457         produceTimeRestricted(new Action<Void, Void>() {
458             @Override
459             public Void launch(Void obj) {
460                 driver.enterText(JTextComponentOperator.this, text);
461                 return null;
462             }
463 
464             @Override
465             public String getDescription() {
466                 return "Text entering";
467             }
468 
469             @Override
470             public String toString() {
471                 return "JTextComponentOperator.enterText.Action{description = " + getDescription() + '}';
472             }
473         }, "JTextComponentOperator.TypeTextTimeout");
474     }
475 
476     /**
477      * Changes caret position.
478      *
479      * @param position Position to move caret to.
480      * @see #changeCaretPosition(String, int, boolean)
481      * @throws TimeoutExpiredException
482      */
483     public void changeCaretPosition(final int position) {
484         output.printLine("Change caret position to " + Integer.toString(position));
485         makeComponentVisible();
486         produceTimeRestricted(new Action<Void, Void>() {
487             @Override
488             public Void launch(Void obj) {
489                 driver.changeCaretPosition(JTextComponentOperator.this, position);
490                 return null;
491             }
492 
493             @Override
494             public String getDescription() {
495                 return "Caret moving";
496             }
497 
498             @Override
499             public String toString() {
500                 return "JTextComponentOperator.changeCaretPosition.Action{description = " + getDescription() + '}';
501             }
502         }, "JTextComponentOperator.ChangeCaretPositionTimeout");
503         if (getVerification()) {
504             waitCaretPosition(position);
505         }
506     }
507 
508     /**
509      * Puts caret before or after text.
510      *
511      * @param text Text to be searched.
512      * @param index Index of text instance (first instance has index 0)
513      * @param before If true put caret before text, otherwise after.
514      * @see #changeCaretPosition(int)
515      * @see #getPositionByText(String, int)
516      * @throws TimeoutExpiredException
517      * @throws NoSuchTextException
518      */
519     public void changeCaretPosition(String text, int index, boolean before) {
520         output.printLine("Put caret "
521                 + (before ? "before" : "after") + " "
522                 + Integer.toString(index) + "'th instance of \""
523                 + text + "\" text");
524         makeComponentVisible();
525         int offset = getPositionByText(text, index);
526         if (offset == -1) {
527             throw (new NoSuchTextException(text));
528         }
529         offset = before ? offset : offset + text.length();
530         changeCaretPosition(offset);
531     }
532 
533     /**
534      * Puts caret before or after text.
535      *
536      * @param text Text to be searched.
537      * @param before If true put caret before text, otherwise after.
538      * @see #changeCaretPosition(int)
539      * @see #getPositionByText(String, int)
540      * @throws TimeoutExpiredException
541      * @throws NoSuchTextException
542      */
543     public void changeCaretPosition(String text, boolean before) {
544         changeCaretPosition(text, 0, before);
545     }
546 
547     /**
548      * Types text starting from known position. If verification mode is on,
549      * checks that right text has been typed and caret has been moved to right
550      * position.
551      *
552      * @param text Text to be typed.
553      * @param caretPosition Position to start type text
554      * @see #typeText(String)
555      * @throws TimeoutExpiredException
556      * @throws NoSuchTextException
557      */
558     public void typeText(final String text, final int caretPosition) {
559         output.printLine("Typing text \"" + text + "\" from "
560                 + Integer.toString(caretPosition) + " position "
561                 + "in text component\n    : "
562                 + toStringSource());
563         output.printGolden("Typing text \"" + text + "\" in text component");
564         makeComponentVisible();
565         produceTimeRestricted(new Action<Void, Void>() {
566             @Override
567             public Void launch(Void obj) {
568                 driver.typeText(JTextComponentOperator.this, text, caretPosition);
569                 return null;
570             }
571 
572             @Override
573             public String getDescription() {
574                 return "Text typing";
575             }
576 
577             @Override
578             public String toString() {
579                 return "JTextComponentOperator.typeText.Action{description = " + getDescription() + '}';
580             }
581         }, "JTextComponentOperator.TypeTextTimeout");
582         if (getVerification()) {
583             waitText(text, -1);
584         }
585     }
586 
587     /**
588      * Types text starting from the current position.
589      *
590      * @param text Text to be typed.
591      * @see #typeText(String, int)
592      * @throws TimeoutExpiredException
593      */
594     public void typeText(String text) {
595         typeText(text, getCaretPosition());
596     }
597 
598     /**
599      * Selects a part of text.
600      *
601      * @param startPosition Start caret position
602      * @param finalPosition Final caret position
603      * @see #selectText(String, int)
604      * @see #selectText(String)
605      * @throws TimeoutExpiredException
606      */
607     public void selectText(final int startPosition, final int finalPosition) {
608         output.printLine("Select text from "
609                 + Integer.toString(startPosition) + " to "
610                 + Integer.toString(finalPosition)
611                 + " in text component\n    : "
612                 + toStringSource());
613         makeComponentVisible();
614         produceTimeRestricted(new Action<Void, Void>() {
615             @Override
616             public Void launch(Void obj) {
617                 driver.selectText(JTextComponentOperator.this, startPosition, finalPosition);
618                 return null;
619             }
620 
621             @Override
622             public String getDescription() {
623                 return "Text selecting";
624             }
625 
626             @Override
627             public String toString() {
628                 return "JTextComponentOperator.selectText.Action{description = " + getDescription() + '}';
629             }
630         }, "JTextComponentOperator.TypeTextTimeout");
631     }
632 
633     /**
634      * Selects a part of text.
635      *
636      * @param text Text to be selected
637      * @param index Index of text instance (first instance has index 0)
638      * @see #selectText(int, int)
639      * @see #selectText(String)
640      * @see #getPositionByText(String, int)
641      * @throws TimeoutExpiredException
642      * @throws NoSuchTextException
643      */
644     public void selectText(String text, int index) {
645         output.printLine("Select "
646                 + Integer.toString(index) + "'th instance of \""
647                 + text + "\" text in component\n    : "
648                 + toStringSource());
649         makeComponentVisible();
650         int start = getPositionByText(text, index);
651         if (start == -1) {
652             throw (new NoSuchTextException(text));
653         }
654         selectText(start, start + text.length());
655     }
656 
657     /**
658      * Selects a part of text.
659      *
660      * @param text Text to be selected
661      * @see #selectText(String, int)
662      * @see #selectText(int, int)
663      * @throws TimeoutExpiredException
664      * @throws NoSuchTextException
665      */
666     public void selectText(String text) {
667         selectText(text, 0);
668     }
669 
670     /**
671      * Clears text.
672      *
673      * @throws TimeoutExpiredException
674      */
675     public void clearText() {
676         output.printLine("Clearing text in text component\n    : "
677                 + toStringSource());
678         output.printGolden("Clearing text in text component");
679         makeComponentVisible();
680         produceTimeRestricted(new Action<Void, Void>() {
681             @Override
682             public Void launch(Void obj) {
683                 driver.clearText(JTextComponentOperator.this);
684                 return null;
685             }
686 
687             @Override
688             public String getDescription() {
689                 return "Text clearing";
690             }
691 
692             @Override
693             public String toString() {
694                 return "JTextComponentOperator.clearText.Action{description = " + getDescription() + '}';
695             }
696         }, "JTextComponentOperator.TypeTextTimeout");
697     }
698 
699     /**
700      * Scrolls to a text poistion.
701      *
702      * @param position a position to scroll.
703      * @throws TimeoutExpiredException
704      */
705     public void scrollToPosition(int position) {
706         output.printTrace("Scroll JTextComponent to " + Integer.toString(position) + " position\n    : "
707                 + toStringSource());
708         output.printGolden("Scroll JTextComponent to " + Integer.toString(position) + " position");
709         makeComponentVisible();
710         //try to find JScrollPane under.
711         JScrollPane scroll = (JScrollPane) getContainer(new JScrollPaneOperator.JScrollPaneFinder(ComponentSearcher.
712                 getTrueChooser("JScrollPane")));
713         if (scroll == null) {
714             return;
715         }
716         JScrollPaneOperator scroller = new JScrollPaneOperator(scroll);
717         scroller.copyEnvironment(this);
718         scroller.setVisualizer(new EmptyVisualizer());
719         Rectangle rect = modelToView(position);
720         scroller.scrollToComponentRectangle(getSource(),
721                 (int) rect.getX(),
722                 (int) rect.getY(),
723                 (int) rect.getWidth(),
724                 (int) rect.getHeight());
725     }
726 
727     /**
728      * Returns text which is really displayed. Results returned by
729      * {@code getText()} and {@code getDisplayedText()} are different
730      * if text component is used to display
731      * {@code javax.swing.text.StyledDocument}
732      *
733      * @return the text which is displayed.
734      */
735     public String getDisplayedText() {
736         try {
737             Document doc = getDocument();
738             return doc.getText(0, doc.getLength());
739         } catch (BadLocationException e) {
740             throw (new JemmyException("Exception during text operation with\n    : "
741                     + toStringSource(), e));
742         }
743     }
744 
745     /**
746      * Wait for text to be displayed starting from certain position.
747      *
748      * @param text text to wait.
749      * @param position starting text position.
750      */
751     public void waitText(final String text, final int position) {
752         getOutput().printLine("Wait \"" + text + "\" text starting from "
753                 + Integer.toString(position) + " position in component \n    : "
754                 + toStringSource());
755         getOutput().printGolden("Wait \"" + text + "\" text starting from "
756                 + Integer.toString(position) + " position");
757         waitState(new ComponentChooser() {
758             @Override
759             public boolean checkComponent(Component comp) {
760                 String alltext = getDisplayedText();
761                 if (position >= 0) {
762                     if (position + text.length() <= alltext.length()) {
763                         return (alltext.substring(position, position + text.length()).
764                                 equals(text));
765                     } else {
766                         return false;
767                     }
768                 } else {
769                     return alltext.indexOf(text) >= 0;
770                 }
771             }
772 
773             @Override
774             public String getDescription() {
775                 return ("Has \"" + text + "\" text starting from "
776                         + Integer.toString(position) + " position");
777             }
778 
779             @Override
780             public String toString() {
781                 return "JTextComponentOperator.waitText.ComponentChooser{description = " + getDescription() + '}';
782             }
783         });
784     }
785 
786     /**
787      * Waits for certain text.
788      *
789      * @param text Text to be compared by getComparator() comparator.
790      */
791     public void waitText(String text) {
792         getOutput().printLine("Wait \"" + text + "\" text in component \n    : "
793                 + toStringSource());
794         getOutput().printGolden("Wait \"" + text + "\" text");
795         waitState(new JTextComponentByTextFinder(text, getComparator()));
796     }
797 
798     /**
799      * Wait for caret to be moved to certain position.
800      *
801      * @param position a position which caret supposed to be moved to.
802      */
803     public void waitCaretPosition(final int position) {
804         getOutput().printLine("Wait caret to be at \"" + Integer.toString(position)
805                 + " position in component \n    : "
806                 + toStringSource());
807         getOutput().printGolden("Wait caret to be at \"" + Integer.toString(position)
808                 + " position");
809         waitState(new ComponentChooser() {
810             @Override
811             public boolean checkComponent(Component comp) {
812                 return getCaretPosition() == position;
813             }
814 
815             @Override
816             public String getDescription() {
817                 return "Has caret at " + Integer.toString(position) + " position";
818             }
819 
820             @Override
821             public String toString() {
822                 return "JTextComponentOperator.waitCaretPosition.ComponentChooser{description = " + getDescription() + '}';
823             }
824         });
825     }
826 
827     @Override
828     public Hashtable<String, Object> getDump() {
829         Hashtable<String, Object> result = super.getDump();
830         result.put(TEXT_DPROP, ((JTextComponent) getSource()).getText());
831         if (((JTextComponent) getSource()).getSelectedText() != null
832                 && !((JTextComponent) getSource()).getSelectedText().equals("")) {
833             result.put(SELECTED_TEXT_DPROP, ((JTextComponent) getSource()).getSelectedText());
834         }
835         result.put(IS_EDITABLE_DPROP, ((JTextComponent) getSource()).isEditable() ? "true" : "false");
836         return result;
837     }
838 
839     ////////////////////////////////////////////////////////
840     //Mapping                                             //
841     /**
842      * Maps {@code JTextComponent.addCaretListener(CaretListener)} through queue
843      */
844     public void addCaretListener(final CaretListener caretListener) {
845         runMapping(new MapVoidAction("addCaretListener") {
846             @Override
847             public void map() {
848                 ((JTextComponent) getSource()).addCaretListener(caretListener);
849             }
850         });
851     }
852 
853     /**
854      * Maps {@code JTextComponent.copy()} through queue
855      */
856     public void copy() {
857         runMapping(new MapVoidAction("copy") {
858             @Override
859             public void map() {
860                 ((JTextComponent) getSource()).copy();
861             }
862         });
863     }
864 
865     /**
866      * Maps {@code JTextComponent.cut()} through queue
867      */
868     public void cut() {
869         runMapping(new MapVoidAction("cut") {
870             @Override
871             public void map() {
872                 ((JTextComponent) getSource()).cut();
873             }
874         });
875     }
876 
877     /**
878      * Maps {@code JTextComponent.getActions()} through queue
879      */
880     public javax.swing.Action[] getActions() {
881         return ((javax.swing.Action[]) runMapping(new MapAction<Object>("getActions") {
882             @Override
883             public Object map() {
884                 return ((JTextComponent) getSource()).getActions();
885             }
886         }));
887     }
888 
889     /**
890      * Maps {@code JTextComponent.getCaret()} through queue
891      */
892     public Caret getCaret() {
893         return (runMapping(new MapAction<Caret>("getCaret") {
894             @Override
895             public Caret map() {
896                 return ((JTextComponent) getSource()).getCaret();
897             }
898         }));
899     }
900 
901     /**
902      * Maps {@code JTextComponent.getCaretColor()} through queue
903      */
904     public Color getCaretColor() {
905         return (runMapping(new MapAction<Color>("getCaretColor") {
906             @Override
907             public Color map() {
908                 return ((JTextComponent) getSource()).getCaretColor();
909             }
910         }));
911     }
912 
913     /**
914      * Maps {@code JTextComponent.getCaretPosition()} through queue
915      */
916     public int getCaretPosition() {
917         return (runMapping(new MapIntegerAction("getCaretPosition") {
918             @Override
919             public int map() {
920                 return ((JTextComponent) getSource()).getCaretPosition();
921             }
922         }));
923     }
924 
925     /**
926      * Maps {@code JTextComponent.getDisabledTextColor()} through queue
927      */
928     public Color getDisabledTextColor() {
929         return (runMapping(new MapAction<Color>("getDisabledTextColor") {
930             @Override
931             public Color map() {
932                 return ((JTextComponent) getSource()).getDisabledTextColor();
933             }
934         }));
935     }
936 
937     /**
938      * Maps {@code JTextComponent.getDocument()} through queue
939      */
940     public Document getDocument() {
941         return (runMapping(new MapAction<Document>("getDocument") {
942             @Override
943             public Document map() {
944                 return ((JTextComponent) getSource()).getDocument();
945             }
946         }));
947     }
948 
949     /**
950      * Maps {@code JTextComponent.getFocusAccelerator()} through queue
951      */
952     public char getFocusAccelerator() {
953         return (runMapping(new MapCharacterAction("getFocusAccelerator") {
954             @Override
955             public char map() {
956                 return ((JTextComponent) getSource()).getFocusAccelerator();
957             }
958         }));
959     }
960 
961     /**
962      * Maps {@code JTextComponent.getHighlighter()} through queue
963      */
964     public Highlighter getHighlighter() {
965         return (runMapping(new MapAction<Highlighter>("getHighlighter") {
966             @Override
967             public Highlighter map() {
968                 return ((JTextComponent) getSource()).getHighlighter();
969             }
970         }));
971     }
972 
973     /**
974      * Maps {@code JTextComponent.getKeymap()} through queue
975      */
976     public Keymap getKeymap() {
977         return (runMapping(new MapAction<Keymap>("getKeymap") {
978             @Override
979             public Keymap map() {
980                 return ((JTextComponent) getSource()).getKeymap();
981             }
982         }));
983     }
984 
985     /**
986      * Maps {@code JTextComponent.getMargin()} through queue
987      */
988     public Insets getMargin() {
989         return (runMapping(new MapAction<Insets>("getMargin") {
990             @Override
991             public Insets map() {
992                 return ((JTextComponent) getSource()).getMargin();
993             }
994         }));
995     }
996 
997     /**
998      * Maps {@code JTextComponent.getPreferredScrollableViewportSize()}
999      * through queue
1000      */
1001     public Dimension getPreferredScrollableViewportSize() {
1002         return (runMapping(new MapAction<Dimension>("getPreferredScrollableViewportSize") {
1003             @Override
1004             public Dimension map() {
1005                 return ((JTextComponent) getSource()).getPreferredScrollableViewportSize();
1006             }
1007         }));
1008     }
1009 
1010     /**
1011      * Maps
1012      * {@code JTextComponent.getScrollableBlockIncrement(Rectangle, int, int)}
1013      * through queue
1014      */
1015     public int getScrollableBlockIncrement(final Rectangle rectangle, final int i, final int i1) {
1016         return (runMapping(new MapIntegerAction("getScrollableBlockIncrement") {
1017             @Override
1018             public int map() {
1019                 return ((JTextComponent) getSource()).getScrollableBlockIncrement(rectangle, i, i1);
1020             }
1021         }));
1022     }
1023 
1024     /**
1025      * Maps {@code JTextComponent.getScrollableTracksViewportHeight()}
1026      * through queue
1027      */
1028     public boolean getScrollableTracksViewportHeight() {
1029         return (runMapping(new MapBooleanAction("getScrollableTracksViewportHeight") {
1030             @Override
1031             public boolean map() {
1032                 return ((JTextComponent) getSource()).getScrollableTracksViewportHeight();
1033             }
1034         }));
1035     }
1036 
1037     /**
1038      * Maps {@code JTextComponent.getScrollableTracksViewportWidth()}
1039      * through queue
1040      */
1041     public boolean getScrollableTracksViewportWidth() {
1042         return (runMapping(new MapBooleanAction("getScrollableTracksViewportWidth") {
1043             @Override
1044             public boolean map() {
1045                 return ((JTextComponent) getSource()).getScrollableTracksViewportWidth();
1046             }
1047         }));
1048     }
1049 
1050     /**
1051      * Maps
1052      * {@code JTextComponent.getScrollableUnitIncrement(Rectangle, int, int)}
1053      * through queue
1054      */
1055     public int getScrollableUnitIncrement(final Rectangle rectangle, final int i, final int i1) {
1056         return (runMapping(new MapIntegerAction("getScrollableUnitIncrement") {
1057             @Override
1058             public int map() {
1059                 return ((JTextComponent) getSource()).getScrollableUnitIncrement(rectangle, i, i1);
1060             }
1061         }));
1062     }
1063 
1064     /**
1065      * Maps {@code JTextComponent.getSelectedText()} through queue
1066      */
1067     public String getSelectedText() {
1068         return (runMapping(new MapAction<String>("getSelectedText") {
1069             @Override
1070             public String map() {
1071                 return ((JTextComponent) getSource()).getSelectedText();
1072             }
1073         }));
1074     }
1075 
1076     /**
1077      * Maps {@code JTextComponent.getSelectedTextColor()} through queue
1078      */
1079     public Color getSelectedTextColor() {
1080         return (runMapping(new MapAction<Color>("getSelectedTextColor") {
1081             @Override
1082             public Color map() {
1083                 return ((JTextComponent) getSource()).getSelectedTextColor();
1084             }
1085         }));
1086     }
1087 
1088     /**
1089      * Maps {@code JTextComponent.getSelectionColor()} through queue
1090      */
1091     public Color getSelectionColor() {
1092         return (runMapping(new MapAction<Color>("getSelectionColor") {
1093             @Override
1094             public Color map() {
1095                 return ((JTextComponent) getSource()).getSelectionColor();
1096             }
1097         }));
1098     }
1099 
1100     /**
1101      * Maps {@code JTextComponent.getSelectionEnd()} through queue
1102      */
1103     public int getSelectionEnd() {
1104         return (runMapping(new MapIntegerAction("getSelectionEnd") {
1105             @Override
1106             public int map() {
1107                 return ((JTextComponent) getSource()).getSelectionEnd();
1108             }
1109         }));
1110     }
1111 
1112     /**
1113      * Maps {@code JTextComponent.getSelectionStart()} through queue
1114      */
1115     public int getSelectionStart() {
1116         return (runMapping(new MapIntegerAction("getSelectionStart") {
1117             @Override
1118             public int map() {
1119                 return ((JTextComponent) getSource()).getSelectionStart();
1120             }
1121         }));
1122     }
1123 
1124     /**
1125      * Maps {@code JTextComponent.getText()} through queue
1126      */
1127     public String getText() {
1128         return (runMapping(new MapAction<String>("getText") {
1129             @Override
1130             public String map() {
1131                 return ((JTextComponent) getSource()).getText();
1132             }
1133         }));
1134     }
1135 
1136     /**
1137      * Maps {@code JTextComponent.getText(int, int)} through queue
1138      */
1139     public String getText(final int i, final int i1) {
1140         return (runMapping(new MapAction<String>("getText") {
1141             @Override
1142             public String map() throws BadLocationException {
1143                 return ((JTextComponent) getSource()).getText(i, i1);
1144             }
1145         }));
1146     }
1147 
1148     /**
1149      * Maps {@code JTextComponent.getUI()} through queue
1150      */
1151     public TextUI getUI() {
1152         return (runMapping(new MapAction<TextUI>("getUI") {
1153             @Override
1154             public TextUI map() {
1155                 return ((JTextComponent) getSource()).getUI();
1156             }
1157         }));
1158     }
1159 
1160     /**
1161      * Maps {@code JTextComponent.isEditable()} through queue
1162      */
1163     public boolean isEditable() {
1164         return (runMapping(new MapBooleanAction("isEditable") {
1165             @Override
1166             public boolean map() {
1167                 return ((JTextComponent) getSource()).isEditable();
1168             }
1169         }));
1170     }
1171 
1172     /**
1173      * Maps {@code JTextComponent.modelToView(int)} through queue
1174      */
1175     public Rectangle modelToView(final int i) {
1176         return (runMapping(new MapAction<Rectangle>("modelToView") {
1177             @Override
1178             public Rectangle map() throws BadLocationException {
1179                 return ((JTextComponent) getSource()).modelToView(i);
1180             }
1181         }));
1182     }
1183 
1184     /**
1185      * Maps {@code JTextComponent.moveCaretPosition(int)} through queue
1186      */
1187     public void moveCaretPosition(final int i) {
1188         runMapping(new MapVoidAction("moveCaretPosition") {
1189             @Override
1190             public void map() {
1191                 ((JTextComponent) getSource()).moveCaretPosition(i);
1192             }
1193         });
1194     }
1195 
1196     /**
1197      * Maps {@code JTextComponent.paste()} through queue
1198      */
1199     public void paste() {
1200         runMapping(new MapVoidAction("paste") {
1201             @Override
1202             public void map() {
1203                 ((JTextComponent) getSource()).paste();
1204             }
1205         });
1206     }
1207 
1208     /**
1209      * Maps {@code JTextComponent.read(Reader, Object)} through queue
1210      */
1211     public void read(final Reader reader, final Object object) {
1212         runMapping(new MapVoidAction("read") {
1213             @Override
1214             public void map() throws IOException {
1215                 ((JTextComponent) getSource()).read(reader, object);
1216             }
1217         });
1218     }
1219 
1220     /**
1221      * Maps {@code JTextComponent.removeCaretListener(CaretListener)}
1222      * through queue
1223      */
1224     public void removeCaretListener(final CaretListener caretListener) {
1225         runMapping(new MapVoidAction("removeCaretListener") {
1226             @Override
1227             public void map() {
1228                 ((JTextComponent) getSource()).removeCaretListener(caretListener);
1229             }
1230         });
1231     }
1232 
1233     /**
1234      * Maps {@code JTextComponent.replaceSelection(String)} through queue
1235      */
1236     public void replaceSelection(final String string) {
1237         runMapping(new MapVoidAction("replaceSelection") {
1238             @Override
1239             public void map() {
1240                 ((JTextComponent) getSource()).replaceSelection(string);
1241             }
1242         });
1243     }
1244 
1245     /**
1246      * Maps {@code JTextComponent.select(int, int)} through queue
1247      */
1248     public void select(final int i, final int i1) {
1249         runMapping(new MapVoidAction("select") {
1250             @Override
1251             public void map() {
1252                 ((JTextComponent) getSource()).select(i, i1);
1253             }
1254         });
1255     }
1256 
1257     /**
1258      * Maps {@code JTextComponent.selectAll()} through queue
1259      */
1260     public void selectAll() {
1261         runMapping(new MapVoidAction("selectAll") {
1262             @Override
1263             public void map() {
1264                 ((JTextComponent) getSource()).selectAll();
1265             }
1266         });
1267     }
1268 
1269     /**
1270      * Maps {@code JTextComponent.setCaret(Caret)} through queue
1271      */
1272     public void setCaret(final Caret caret) {
1273         runMapping(new MapVoidAction("setCaret") {
1274             @Override
1275             public void map() {
1276                 ((JTextComponent) getSource()).setCaret(caret);
1277             }
1278         });
1279     }
1280 
1281     /**
1282      * Maps {@code JTextComponent.setCaretColor(Color)} through queue
1283      */
1284     public void setCaretColor(final Color color) {
1285         runMapping(new MapVoidAction("setCaretColor") {
1286             @Override
1287             public void map() {
1288                 ((JTextComponent) getSource()).setCaretColor(color);
1289             }
1290         });
1291     }
1292 
1293     /**
1294      * Maps {@code JTextComponent.setCaretPosition(int)} through queue
1295      */
1296     public void setCaretPosition(final int i) {
1297         runMapping(new MapVoidAction("setCaretPosition") {
1298             @Override
1299             public void map() {
1300                 ((JTextComponent) getSource()).setCaretPosition(i);
1301             }
1302         });
1303     }
1304 
1305     /**
1306      * Maps {@code JTextComponent.setDisabledTextColor(Color)} through queue
1307      */
1308     public void setDisabledTextColor(final Color color) {
1309         runMapping(new MapVoidAction("setDisabledTextColor") {
1310             @Override
1311             public void map() {
1312                 ((JTextComponent) getSource()).setDisabledTextColor(color);
1313             }
1314         });
1315     }
1316 
1317     /**
1318      * Maps {@code JTextComponent.setDocument(Document)} through queue
1319      */
1320     public void setDocument(final Document document) {
1321         runMapping(new MapVoidAction("setDocument") {
1322             @Override
1323             public void map() {
1324                 ((JTextComponent) getSource()).setDocument(document);
1325             }
1326         });
1327     }
1328 
1329     /**
1330      * Maps {@code JTextComponent.setEditable(boolean)} through queue
1331      */
1332     public void setEditable(final boolean b) {
1333         runMapping(new MapVoidAction("setEditable") {
1334             @Override
1335             public void map() {
1336                 ((JTextComponent) getSource()).setEditable(b);
1337             }
1338         });
1339     }
1340 
1341     /**
1342      * Maps {@code JTextComponent.setFocusAccelerator(char)} through queue
1343      */
1344     public void setFocusAccelerator(final char c) {
1345         runMapping(new MapVoidAction("setFocusAccelerator") {
1346             @Override
1347             public void map() {
1348                 ((JTextComponent) getSource()).setFocusAccelerator(c);
1349             }
1350         });
1351     }
1352 
1353     /**
1354      * Maps {@code JTextComponent.setHighlighter(Highlighter)} through queue
1355      */
1356     public void setHighlighter(final Highlighter highlighter) {
1357         runMapping(new MapVoidAction("setHighlighter") {
1358             @Override
1359             public void map() {
1360                 ((JTextComponent) getSource()).setHighlighter(highlighter);
1361             }
1362         });
1363     }
1364 
1365     /**
1366      * Maps {@code JTextComponent.setKeymap(Keymap)} through queue
1367      */
1368     public void setKeymap(final Keymap keymap) {
1369         runMapping(new MapVoidAction("setKeymap") {
1370             @Override
1371             public void map() {
1372                 ((JTextComponent) getSource()).setKeymap(keymap);
1373             }
1374         });
1375     }
1376 
1377     /**
1378      * Maps {@code JTextComponent.setMargin(Insets)} through queue
1379      */
1380     public void setMargin(final Insets insets) {
1381         runMapping(new MapVoidAction("setMargin") {
1382             @Override
1383             public void map() {
1384                 ((JTextComponent) getSource()).setMargin(insets);
1385             }
1386         });
1387     }
1388 
1389     /**
1390      * Maps {@code JTextComponent.setSelectedTextColor(Color)} through queue
1391      */
1392     public void setSelectedTextColor(final Color color) {
1393         runMapping(new MapVoidAction("setSelectedTextColor") {
1394             @Override
1395             public void map() {
1396                 ((JTextComponent) getSource()).setSelectedTextColor(color);
1397             }
1398         });
1399     }
1400 
1401     /**
1402      * Maps {@code JTextComponent.setSelectionColor(Color)} through queue
1403      */
1404     public void setSelectionColor(final Color color) {
1405         runMapping(new MapVoidAction("setSelectionColor") {
1406             @Override
1407             public void map() {
1408                 ((JTextComponent) getSource()).setSelectionColor(color);
1409             }
1410         });
1411     }
1412 
1413     /**
1414      * Maps {@code JTextComponent.setSelectionEnd(int)} through queue
1415      */
1416     public void setSelectionEnd(final int i) {
1417         runMapping(new MapVoidAction("setSelectionEnd") {
1418             @Override
1419             public void map() {
1420                 ((JTextComponent) getSource()).setSelectionEnd(i);
1421             }
1422         });
1423     }
1424 
1425     /**
1426      * Maps {@code JTextComponent.setSelectionStart(int)} through queue
1427      */
1428     public void setSelectionStart(final int i) {
1429         runMapping(new MapVoidAction("setSelectionStart") {
1430             @Override
1431             public void map() {
1432                 ((JTextComponent) getSource()).setSelectionStart(i);
1433             }
1434         });
1435     }
1436 
1437     /**
1438      * Maps {@code JTextComponent.setText(String)} through queue
1439      */
1440     public void setText(final String string) {
1441         runMapping(new MapVoidAction("setText") {
1442             @Override
1443             public void map() {
1444                 ((JTextComponent) getSource()).setText(string);
1445             }
1446         });
1447     }
1448 
1449     /**
1450      * Maps {@code JTextComponent.setUI(TextUI)} through queue
1451      */
1452     public void setUI(final TextUI textUI) {
1453         runMapping(new MapVoidAction("setUI") {
1454             @Override
1455             public void map() {
1456                 ((JTextComponent) getSource()).setUI(textUI);
1457             }
1458         });
1459     }
1460 
1461     /**
1462      * Maps {@code JTextComponent.viewToModel(Point)} through queue
1463      */
1464     public int viewToModel(final Point point) {
1465         return (runMapping(new MapIntegerAction("viewToModel") {
1466             @Override
1467             public int map() {
1468                 return ((JTextComponent) getSource()).viewToModel(point);
1469             }
1470         }));
1471     }
1472 
1473     /**
1474      * Maps {@code JTextComponent.write(Writer)} through queue
1475      */
1476     public void write(final Writer writer) {
1477         runMapping(new MapVoidAction("write") {
1478             @Override
1479             public void map() throws IOException {
1480                 ((JTextComponent) getSource()).write(writer);
1481             }
1482         });
1483     }
1484 
1485     //End of mapping                                      //
1486     ////////////////////////////////////////////////////////
1487     /**
1488      * Can be throught during a text operation if text has not been found in the
1489      * component.
1490      */
1491     public class NoSuchTextException extends JemmyInputException {
1492 
1493         private static final long serialVersionUID = 42L;
1494 
1495         /**
1496          * Constructor.
1497          *
1498          * @param text a nonexistent text.
1499          */
1500         public NoSuchTextException(String text) {
1501             super("No such text as \"" + text + "\"", getSource());
1502         }
1503     }
1504 
1505     /**
1506      * Interface defining additional text cearch criteria.
1507      *
1508      * @see #getPositionByText(java.lang.String,
1509      * JTextComponentOperator.TextChooser)
1510      */
1511     public interface TextChooser {
1512 
1513         /**
1514          * Checkes if position fits the criteria.
1515          *
1516          * @param document a document to be checked.
1517          * @param offset a checked position
1518          * @return true if the position fits the criteria.
1519          */
1520         public boolean checkPosition(Document document, int offset);
1521 
1522         /**
1523          * Returns a printable description of the criteria.
1524          *
1525          * @return a description of this chooser.
1526          */
1527         public String getDescription();
1528     }
1529 
1530     /**
1531      * Allows to find component by text.
1532      */
1533     public static class JTextComponentByTextFinder implements ComponentChooser {
1534 
1535         String label;
1536         StringComparator comparator;
1537 
1538         /**
1539          * Constructs JTextComponentByTextFinder.
1540          *
1541          * @param lb a text pattern
1542          * @param comparator specifies string comparision algorithm.
1543          */
1544         public JTextComponentByTextFinder(String lb, StringComparator comparator) {
1545             label = lb;
1546             this.comparator = comparator;
1547         }
1548 
1549         /**
1550          * Constructs JTextComponentByTextFinder.
1551          *
1552          * @param lb a text pattern
1553          */
1554         public JTextComponentByTextFinder(String lb) {
1555             this(lb, Operator.getDefaultStringComparator());
1556         }
1557 
1558         @Override
1559         public boolean checkComponent(Component comp) {
1560             if (comp instanceof JTextComponent) {
1561                 if (((JTextComponent) comp).getText() != null) {
1562                     return (comparator.equals(((JTextComponent) comp).getText(),
1563                             label));
1564                 }
1565             }
1566             return false;
1567         }
1568 
1569         @Override
1570         public String getDescription() {
1571             return "JTextComponent with text \"" + label + "\"";
1572         }
1573 
1574         @Override
1575         public String toString() {
1576             return "JTextComponentByTextFinder{" + "label=" + label + ", comparator=" + comparator + '}';
1577         }
1578     }
1579 
1580     /**
1581      * Checks component type.
1582      */
1583     public static class JTextComponentFinder extends Finder {
1584 
1585         /**
1586          * Constructs JTextComponentFinder.
1587          *
1588          * @param sf other searching criteria.
1589          */
1590         public JTextComponentFinder(ComponentChooser sf) {
1591             super(JTextComponent.class, sf);
1592         }
1593 
1594         /**
1595          * Constructs JTextComponentFinder.
1596          */
1597         public JTextComponentFinder() {
1598             super(JTextComponent.class);
1599         }
1600     }
1601 }
1602