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