001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s): Alexandre Iline.
025: *
026: * The Original Software is the Jemmy library.
027: * The Initial Developer of the Original Software is Alexandre Iline.
028: * All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: *
041: *
042: *
043: * $Id: TextComponentOperator.java,v 1.10 2007/10/05 11:35:58 jskrivanek Exp $ $Revision: 1.10 $ $Date: 2007/10/05 11:35:58 $
044: *
045: */
046:
047: package org.netbeans.jemmy.operators;
048:
049: import org.netbeans.jemmy.ActionProducer;
050: import org.netbeans.jemmy.Action;
051: import org.netbeans.jemmy.ComponentChooser;
052: import org.netbeans.jemmy.ComponentSearcher;
053: import org.netbeans.jemmy.JemmyProperties;
054: import org.netbeans.jemmy.Outputable;
055: import org.netbeans.jemmy.TestOut;
056: import org.netbeans.jemmy.Timeoutable;
057: import org.netbeans.jemmy.Timeouts;
058:
059: import org.netbeans.jemmy.drivers.DriverManager;
060: import org.netbeans.jemmy.drivers.TextDriver;
061:
062: import java.awt.Component;
063: import java.awt.Container;
064: import java.awt.TextComponent;
065:
066: import java.awt.event.KeyEvent;
067: import java.awt.event.TextListener;
068:
069: import java.util.Hashtable;
070:
071: /**
072: * This operator type covers java.awt.TextArea component.
073: *
074: *
075: * @see org.netbeans.jemmy.Timeouts
076: *
077: * @author Alexandre Iline (alexandre.iline@sun.com)
078: *
079: */
080: public class TextComponentOperator extends ComponentOperator implements
081: Timeoutable, Outputable {
082:
083: /**
084: * Identifier for a "text" property.
085: * @see #getDump
086: */
087: public static final String TEXT_DPROP = "Text";
088:
089: private final static long PUSH_KEY_TIMEOUT = 0;
090: private final static long BETWEEN_KEYS_TIMEOUT = 0;
091: private final static long CHANGE_CARET_POSITION_TIMEOUT = 60000;
092: private final static long TYPE_TEXT_TIMEOUT = 60000;
093:
094: private Timeouts timeouts;
095: private TestOut output;
096:
097: private TextDriver driver;
098:
099: /**
100: * Constructor.
101: * @param b The <code>java.awt.TextComponent</code> managed by
102: * this instance.
103: */
104: public TextComponentOperator(TextComponent b) {
105: super (b);
106: driver = DriverManager.getTextDriver(getClass());
107: }
108:
109: /**
110: * Constructs a TextComponentOperator object.
111: * @param cont a container
112: * @param chooser a component chooser specifying searching criteria.
113: * @param index an index between appropriate ones.
114: */
115: public TextComponentOperator(ContainerOperator cont,
116: ComponentChooser chooser, int index) {
117: this ((TextComponent) cont.waitSubComponent(
118: new TextComponentFinder(chooser), index));
119: copyEnvironment(cont);
120: }
121:
122: /**
123: * Constructs a TextComponentOperator object.
124: * @param cont a container
125: * @param chooser a component chooser specifying searching criteria.
126: */
127: public TextComponentOperator(ContainerOperator cont,
128: ComponentChooser chooser) {
129: this (cont, chooser, 0);
130: }
131:
132: /**
133: * Constructor.
134: * Waits for a component in a container to show. The component is
135: * identified as the <code>index+1</code>'th
136: * <code>java.awt.TextComponent</code> that shows, lies below
137: * the container in the display containment hierarchy,
138: * and that has the desired text. Uses cont's timeout and output
139: * for waiting and to init this operator.
140: * @param cont The operator for a container containing the sought for textComponent.
141: * @param text TextComponent text.
142: * @param index Ordinal component index. The first component has <code>index</code> 0.
143: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
144: */
145: public TextComponentOperator(ContainerOperator cont, String text,
146: int index) {
147: this ((TextComponent) waitComponent(cont,
148: new TextComponentByTextFinder(text, cont
149: .getComparator()), index));
150: copyEnvironment(cont);
151: }
152:
153: /**
154: * Constructor.
155: * Waits for a component in a container to show. The component is
156: * identified as the first
157: * <code>java.awt.TextComponent</code> that shows, lies below
158: * the container in the display containment hierarchy,
159: * and that has the desired text. Uses cont's timeout and output
160: * for waiting and to init this operator.
161: * @param cont The operator for a container containing the sought for textComponent.
162: * @param text TextComponent text.
163: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
164: */
165: public TextComponentOperator(ContainerOperator cont, String text) {
166: this (cont, text, 0);
167: }
168:
169: /**
170: * Constructor.
171: * Waits component in container first.
172: * Uses cont's timeout and output for waiting and to init operator.
173: * @param cont The operator for a container containing the sought for textComponent.
174: * @param index Ordinal component index.
175: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
176: */
177: public TextComponentOperator(ContainerOperator cont, int index) {
178: this ((TextComponent) waitComponent(cont,
179: new TextComponentFinder(), index));
180: copyEnvironment(cont);
181: }
182:
183: /**
184: * Constructor.
185: * Waits component in container first.
186: * Uses cont's timeout and output for waiting and to init operator.
187: * @param cont The operator for a container containing the sought for textComponent.
188: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
189: */
190: public TextComponentOperator(ContainerOperator cont) {
191: this (cont, 0);
192: }
193:
194: /**
195: * Searches TextComponent in a container.
196: * @param cont Container in which to search for the component. The container
197: * lies above the component in the display containment hierarchy. The containment
198: * need not be direct.
199: * @param chooser org.netbeans.jemmy.ComponentChooser implementation, defining and
200: * applying search criteria.
201: * @param index Ordinal component index. The first <code>index</code> is 0.
202: * @return TextComponent instance or null if component was not found.
203: */
204: public static TextComponent findTextComponent(Container cont,
205: ComponentChooser chooser, int index) {
206: return ((TextComponent) findComponent(cont,
207: new TextComponentFinder(chooser), index));
208: }
209:
210: /**
211: * Searches for the first TextComponent in a container.
212: * @param cont Container in which to search for the component. The container
213: * lies above the component in the display containment hierarchy. The containment
214: * need not be direct.
215: * @param chooser org.netbeans.jemmy.ComponentChooser implementation, defining and
216: * applying search criteria.
217: * @return TextComponent instance or null if component was not found.
218: */
219: public static TextComponent findTextComponent(Container cont,
220: ComponentChooser chooser) {
221: return (findTextComponent(cont, chooser, 0));
222: }
223:
224: /**
225: * Searches TextComponent by text.
226: * @param cont Container to search component in.
227: * @param text TextComponent text. If null, contents is not checked.
228: * @param ce Compare text exactly.
229: * @param ccs Compare text case sensitively.
230: * @param index Ordinal component index.
231: * @return TextComponent instance or null if component was not found.
232: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
233: */
234: public static TextComponent findTextComponent(Container cont,
235: String text, boolean ce, boolean ccs, int index) {
236: return (findTextComponent(cont, new TextComponentByTextFinder(
237: text, new DefaultStringComparator(ce, ccs)), index));
238: }
239:
240: /**
241: * Searches TextComponent by text.
242: * @param cont Container to search component in.
243: * @param text TextComponent text. If null, contents is not checked.
244: * @param ce Compare text exactly.
245: * @param ccs Compare text case sensitively.
246: * @return TextComponent instance or null if component was not found.
247: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
248: */
249: public static TextComponent findTextComponent(Container cont,
250: String text, boolean ce, boolean ccs) {
251: return (findTextComponent(cont, text, ce, ccs, 0));
252: }
253:
254: /**
255: * Waits TextComponent in container.
256: * @param cont Container to search component in.
257: * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
258: * @param index Ordinal component index.
259: * @return TextComponent instance.
260: */
261: public static TextComponent waitTextComponent(Container cont,
262: ComponentChooser chooser, int index) {
263: return ((TextComponent) waitComponent(cont,
264: new TextComponentFinder(chooser), index));
265: }
266:
267: /**
268: * Waits 0'th TextComponent in container.
269: * @param cont Container to search component in.
270: * @param chooser org.netbeans.jemmy.ComponentChooser implementation.
271: * @return TextComponent instance.
272: */
273: public static TextComponent waitTextComponent(Container cont,
274: ComponentChooser chooser) {
275: return (waitTextComponent(cont, chooser, 0));
276: }
277:
278: /**
279: * Waits TextComponent by text.
280: * @param cont Container to search component in.
281: * @param text TextComponent text. If null, contents is not checked.
282: * @param ce Compare text exactly.
283: * @param ccs Compare text case sensitively.
284: * @param index Ordinal component index.
285: * @return TextComponent instance.
286: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
287: */
288: public static TextComponent waitTextComponent(Container cont,
289: String text, boolean ce, boolean ccs, int index) {
290: return (waitTextComponent(cont, new TextComponentByTextFinder(
291: text, new DefaultStringComparator(ce, ccs)), index));
292: }
293:
294: /**
295: * Waits TextComponent by text.
296: * @param cont Container to search component in.
297: * @param text TextComponent text. If null, contents is not checked.
298: * @param ce Compare text exactly.
299: * @param ccs Compare text case sensitively.
300: * @return TextComponent instance.
301: * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean)
302: */
303: public static TextComponent waitTextComponent(Container cont,
304: String text, boolean ce, boolean ccs) {
305: return (waitTextComponent(cont, text, ce, ccs, 0));
306: }
307:
308: static {
309: Timeouts.initDefault("TextComponentOperator.PushKeyTimeout",
310: PUSH_KEY_TIMEOUT);
311: Timeouts.initDefault(
312: "TextComponentOperator.BetweenKeysTimeout",
313: BETWEEN_KEYS_TIMEOUT);
314: Timeouts.initDefault(
315: "TextComponentOperator.ChangeCaretPositionTimeout",
316: CHANGE_CARET_POSITION_TIMEOUT);
317: Timeouts.initDefault("TextComponentOperator.TypeTextTimeout",
318: TYPE_TEXT_TIMEOUT);
319: }
320:
321: public void setTimeouts(Timeouts timeouts) {
322: super .setTimeouts(timeouts);
323: this .timeouts = timeouts;
324: }
325:
326: public Timeouts getTimeouts() {
327: return (timeouts);
328: }
329:
330: public void setOutput(TestOut out) {
331: output = out;
332: super .setOutput(output.createErrorOutput());
333: }
334:
335: public TestOut getOutput() {
336: return (output);
337: }
338:
339: public void copyEnvironment(Operator anotherOperator) {
340: super .copyEnvironment(anotherOperator);
341: driver = (TextDriver) DriverManager.getDriver(
342: DriverManager.TEXT_DRIVER_ID, getClass(),
343: anotherOperator.getProperties());
344: }
345:
346: /**
347: * Changes caret position.
348: * @param position Position to move caret to.
349: *
350: */
351: public void changeCaretPosition(final int position) {
352: makeComponentVisible();
353: produceTimeRestricted(new Action() {
354: public Object launch(Object obj) {
355: driver.changeCaretPosition(TextComponentOperator.this ,
356: position);
357: return (null);
358: }
359:
360: public String getDescription() {
361: return ("Caret moving");
362: }
363: }, getTimeouts().getTimeout(
364: "TextComponentOperator.ChangeCaretPositionTimeout"));
365: }
366:
367: /**
368: * Selects a part of text.
369: * @param startPosition Start caret position
370: * @param finalPosition Final caret position
371: *
372: */
373: public void selectText(final int startPosition,
374: final int finalPosition) {
375: makeComponentVisible();
376: produceTimeRestricted(new Action() {
377: public Object launch(Object obj) {
378: driver.selectText(TextComponentOperator.this ,
379: startPosition, finalPosition);
380: return (null);
381: }
382:
383: public String getDescription() {
384: return ("Text selecting");
385: }
386: }, getTimeouts().getTimeout(
387: "TextComponentOperator.TypeTextTimeout"));
388: }
389:
390: /**
391: * Finds start text position.
392: * @param text Text to be searched.
393: * @param index Index of text instance (first instance has index 0)
394: * @return Caret position correspondent to text start.
395: */
396: public int getPositionByText(String text, int index) {
397: String allText = getText();
398: int position = 0;
399: int ind = 0;
400: while ((position = allText.indexOf(text, position)) >= 0) {
401: if (ind == index) {
402: return (position);
403: } else {
404: ind++;
405: }
406: position = position + text.length();
407: }
408: return (-1);
409: }
410:
411: /**
412: * Finds start text position.
413: * @param text Text to be searched.
414: * @return Caret position correspondent to text start.
415: */
416: public int getPositionByText(String text) {
417: return (getPositionByText(text, 0));
418: }
419:
420: /**
421: * Clears text.
422: *
423: */
424: public void clearText() {
425: output.printLine("Clearing text in text component\n : "
426: + toStringSource());
427: output.printGolden("Clearing text in text component");
428: makeComponentVisible();
429: produceTimeRestricted(new Action() {
430: public Object launch(Object obj) {
431: driver.clearText(TextComponentOperator.this );
432: return (null);
433: }
434:
435: public String getDescription() {
436: return ("Text clearing");
437: }
438: }, getTimeouts().getTimeout(
439: "TextComponentOperator.TypeTextTimeout"));
440: }
441:
442: /**
443: * Types text starting from known position.
444: * @param text Text to be typed.
445: * @param caretPosition Position to start type text
446: */
447: public void typeText(final String text, final int caretPosition) {
448: output.printLine("Typing text \"" + text + "\" from "
449: + Integer.toString(caretPosition) + " position "
450: + "in text component\n : " + toStringSource());
451: output.printGolden("Typing text \"" + text
452: + "\" in text component");
453: makeComponentVisible();
454: produceTimeRestricted(new Action() {
455: public Object launch(Object obj) {
456: driver.typeText(TextComponentOperator.this , text,
457: caretPosition);
458: return (null);
459: }
460:
461: public String getDescription() {
462: return ("Text typing");
463: }
464: }, getTimeouts().getTimeout(
465: "TextComponentOperator.TypeTextTimeout"));
466: }
467:
468: /**
469: * Types text starting from known position.
470: * @param text Text to be typed.
471: */
472: public void typeText(String text) {
473: typeText(text, getCaretPosition());
474: }
475:
476: /**
477: * Requests a focus, clears text, types new one and pushes Enter.
478: * @param text New text value. Shouln't include final '\n'.
479: *
480: */
481: public void enterText(final String text) {
482: makeComponentVisible();
483: produceTimeRestricted(new Action() {
484: public Object launch(Object obj) {
485: driver.enterText(TextComponentOperator.this , text);
486: return (null);
487: }
488:
489: public String getDescription() {
490: return ("Text entering");
491: }
492: }, getTimeouts().getTimeout(
493: "TextComponentOperator.TypeTextTimeout"));
494: }
495:
496: public Hashtable getDump() {
497: Hashtable result = super .getDump();
498: result.put(TEXT_DPROP, ((TextComponent) getSource()).getText());
499: return (result);
500: }
501:
502: ////////////////////////////////////////////////////////
503: //Mapping //
504: /**Maps <code>TextComponent.addTextListener(TextListener)</code> through queue*/
505: public void addTextListener(final TextListener textListener) {
506: runMapping(new MapVoidAction("addTextListener") {
507: public void map() {
508: ((TextComponent) getSource())
509: .addTextListener(textListener);
510: }
511: });
512: }
513:
514: /**Maps <code>TextComponent.getCaretPosition()</code> through queue*/
515: public int getCaretPosition() {
516: return (runMapping(new MapIntegerAction("getCaretPosition") {
517: public int map() {
518: return (((TextComponent) getSource())
519: .getCaretPosition());
520: }
521: }));
522: }
523:
524: /**Maps <code>TextComponent.getSelectedText()</code> through queue*/
525: public String getSelectedText() {
526: return ((String) runMapping(new MapAction("getSelectedText") {
527: public Object map() {
528: return (((TextComponent) getSource()).getSelectedText());
529: }
530: }));
531: }
532:
533: /**Maps <code>TextComponent.getSelectionEnd()</code> through queue*/
534: public int getSelectionEnd() {
535: return (runMapping(new MapIntegerAction("getSelectionEnd") {
536: public int map() {
537: return (((TextComponent) getSource()).getSelectionEnd());
538: }
539: }));
540: }
541:
542: /**Maps <code>TextComponent.getSelectionStart()</code> through queue*/
543: public int getSelectionStart() {
544: return (runMapping(new MapIntegerAction("getSelectionStart") {
545: public int map() {
546: return (((TextComponent) getSource())
547: .getSelectionStart());
548: }
549: }));
550: }
551:
552: /**Maps <code>TextComponent.getText()</code> through queue*/
553: public String getText() {
554: return ((String) runMapping(new MapAction("getText") {
555: public Object map() {
556: return (((TextComponent) getSource()).getText());
557: }
558: }));
559: }
560:
561: /**Maps <code>TextComponent.isEditable()</code> through queue*/
562: public boolean isEditable() {
563: return (runMapping(new MapBooleanAction("isEditable") {
564: public boolean map() {
565: return (((TextComponent) getSource()).isEditable());
566: }
567: }));
568: }
569:
570: /**Maps <code>TextComponent.removeTextListener(TextListener)</code> through queue*/
571: public void removeTextListener(final TextListener textListener) {
572: runMapping(new MapVoidAction("removeTextListener") {
573: public void map() {
574: ((TextComponent) getSource())
575: .removeTextListener(textListener);
576: }
577: });
578: }
579:
580: /**Maps <code>TextComponent.select(int, int)</code> through queue*/
581: public void select(final int i, final int i1) {
582: runMapping(new MapVoidAction("select") {
583: public void map() {
584: ((TextComponent) getSource()).select(i, i1);
585: }
586: });
587: }
588:
589: /**Maps <code>TextComponent.selectAll()</code> through queue*/
590: public void selectAll() {
591: runMapping(new MapVoidAction("selectAll") {
592: public void map() {
593: ((TextComponent) getSource()).selectAll();
594: }
595: });
596: }
597:
598: /**Maps <code>TextComponent.setCaretPosition(int)</code> through queue*/
599: public void setCaretPosition(final int i) {
600: runMapping(new MapVoidAction("setCaretPosition") {
601: public void map() {
602: ((TextComponent) getSource()).setCaretPosition(i);
603: }
604: });
605: }
606:
607: /**Maps <code>TextComponent.setEditable(boolean)</code> through queue*/
608: public void setEditable(final boolean b) {
609: runMapping(new MapVoidAction("setEditable") {
610: public void map() {
611: ((TextComponent) getSource()).setEditable(b);
612: }
613: });
614: }
615:
616: /**Maps <code>TextComponent.setSelectionEnd(int)</code> through queue*/
617: public void setSelectionEnd(final int i) {
618: runMapping(new MapVoidAction("setSelectionEnd") {
619: public void map() {
620: ((TextComponent) getSource()).setSelectionEnd(i);
621: }
622: });
623: }
624:
625: /**Maps <code>TextComponent.setSelectionStart(int)</code> through queue*/
626: public void setSelectionStart(final int i) {
627: runMapping(new MapVoidAction("setSelectionStart") {
628: public void map() {
629: ((TextComponent) getSource()).setSelectionStart(i);
630: }
631: });
632: }
633:
634: /**Maps <code>TextComponent.setText(String)</code> through queue*/
635: public void setText(final String string) {
636: runMapping(new MapVoidAction("setText") {
637: public void map() {
638: ((TextComponent) getSource()).setText(string);
639: }
640: });
641: }
642:
643: //End of mapping //
644: ////////////////////////////////////////////////////////
645:
646: /**
647: * Return a TextDriver used by this component.
648: * @return a driver got by the operator during creation.
649: */
650: protected TextDriver getTextDriver() {
651: return (driver);
652: }
653:
654: /**
655: * Allows to find component by text.
656: */
657: public static class TextComponentByTextFinder implements
658: ComponentChooser {
659: String label;
660: StringComparator comparator;
661:
662: /**
663: * Constructs TextComponentByTextFinder.
664: * @param lb a text pattern
665: * @param comparator specifies string comparision algorithm.
666: */
667: public TextComponentByTextFinder(String lb,
668: StringComparator comparator) {
669: label = lb;
670: this .comparator = comparator;
671: }
672:
673: /**
674: * Constructs TextComponentByTextFinder.
675: * @param lb a text pattern
676: */
677: public TextComponentByTextFinder(String lb) {
678: this (lb, Operator.getDefaultStringComparator());
679: }
680:
681: public boolean checkComponent(Component comp) {
682: if (comp instanceof TextComponent) {
683: if (((TextComponent) comp).getText() != null) {
684: return (comparator.equals(((TextComponent) comp)
685: .getText(), label));
686: }
687: }
688: return (false);
689: }
690:
691: public String getDescription() {
692: return ("TextComponent with text \"" + label + "\"");
693: }
694: }
695:
696: /**
697: * Checks component type.
698: */
699: public static class TextComponentFinder extends Finder {
700: /**
701: * Constructs TextComponentFinder.
702: * @param sf other searching criteria.
703: */
704: public TextComponentFinder(ComponentChooser sf) {
705: super (TextComponent.class, sf);
706: }
707:
708: /**
709: * Constructs TextComponentFinder.
710: */
711: public TextComponentFinder() {
712: super (TextComponent.class);
713: }
714: }
715: }
|