/* * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.netbeans.jemmy.operators; import java.awt.Component; import java.awt.Container; import java.awt.TextComponent; import java.awt.event.TextListener; import java.util.Hashtable; import org.netbeans.jemmy.Action; import org.netbeans.jemmy.ComponentChooser; import org.netbeans.jemmy.Outputable; import org.netbeans.jemmy.TestOut; import org.netbeans.jemmy.Timeoutable; import org.netbeans.jemmy.Timeouts; import org.netbeans.jemmy.drivers.DriverManager; import org.netbeans.jemmy.drivers.TextDriver; /** * This operator type covers java.awt.TextArea component. * * * @see org.netbeans.jemmy.Timeouts * * @author Alexandre Iline (alexandre.iline@oracle.com) * */ public class TextComponentOperator extends ComponentOperator implements Timeoutable, Outputable { /** * Identifier for a "text" property. * * @see #getDump */ public static final String TEXT_DPROP = "Text"; private final static long PUSH_KEY_TIMEOUT = 0; private final static long BETWEEN_KEYS_TIMEOUT = 0; private final static long CHANGE_CARET_POSITION_TIMEOUT = 60000; private final static long TYPE_TEXT_TIMEOUT = 60000; private Timeouts timeouts; private TestOut output; private TextDriver driver; /** * Constructor. * * @param b The {@code java.awt.TextComponent} managed by this * instance. */ public TextComponentOperator(TextComponent b) { super(b); driver = DriverManager.getTextDriver(getClass()); } /** * Constructs a TextComponentOperator object. * * @param cont a container * @param chooser a component chooser specifying searching criteria. * @param index an index between appropriate ones. */ public TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser, int index) { this((TextComponent) cont. waitSubComponent(new TextComponentFinder(chooser), index)); copyEnvironment(cont); } /** * Constructs a TextComponentOperator object. * * @param cont a container * @param chooser a component chooser specifying searching criteria. */ public TextComponentOperator(ContainerOperator<?> cont, ComponentChooser chooser) { this(cont, chooser, 0); } /** * Constructor. Waits for a component in a container to show. The component * is identified as the {@code index+1}'th * {@code java.awt.TextComponent} that shows, lies below the container * in the display containment hierarchy, and that has the desired text. Uses * cont's timeout and output for waiting and to init this operator. * * @param cont The operator for a container containing the sought for * textComponent. * @param text TextComponent text. * @param index Ordinal component index. The first component has * {@code index} 0. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public TextComponentOperator(ContainerOperator<?> cont, String text, int index) { this((TextComponent) waitComponent(cont, new TextComponentByTextFinder(text, cont.getComparator()), index)); copyEnvironment(cont); } /** * Constructor. Waits for a component in a container to show. The component * is identified as the first {@code java.awt.TextComponent} that * shows, lies below the container in the display containment hierarchy, and * that has the desired text. Uses cont's timeout and output for waiting and * to init this operator. * * @param cont The operator for a container containing the sought for * textComponent. * @param text TextComponent text. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public TextComponentOperator(ContainerOperator<?> cont, String text) { this(cont, text, 0); } /** * Constructor. Waits component in container first. Uses cont's timeout and * output for waiting and to init operator. * * @param cont The operator for a container containing the sought for * textComponent. * @param index Ordinal component index. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public TextComponentOperator(ContainerOperator<?> cont, int index) { this((TextComponent) waitComponent(cont, new TextComponentFinder(), index)); copyEnvironment(cont); } /** * Constructor. Waits component in container first. Uses cont's timeout and * output for waiting and to init operator. * * @param cont The operator for a container containing the sought for * textComponent. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public TextComponentOperator(ContainerOperator<?> cont) { this(cont, 0); } /** * Searches TextComponent in a container. * * @param cont Container in which to search for the component. The container * lies above the component in the display containment hierarchy. The * containment need not be direct. * @param chooser org.netbeans.jemmy.ComponentChooser implementation, * defining and applying search criteria. * @param index Ordinal component index. The first {@code index} is 0. * @return TextComponent instance or null if component was not found. */ public static TextComponent findTextComponent(Container cont, ComponentChooser chooser, int index) { return (TextComponent) findComponent(cont, new TextComponentFinder(chooser), index); } /** * Searches for the first TextComponent in a container. * * @param cont Container in which to search for the component. The container * lies above the component in the display containment hierarchy. The * containment need not be direct. * @param chooser org.netbeans.jemmy.ComponentChooser implementation, * defining and applying search criteria. * @return TextComponent instance or null if component was not found. */ public static TextComponent findTextComponent(Container cont, ComponentChooser chooser) { return findTextComponent(cont, chooser, 0); } /** * Searches TextComponent by text. * * @param cont Container to search component in. * @param text TextComponent text. If null, contents is not checked. * @param ce Compare text exactly. * @param ccs Compare text case sensitively. * @param index Ordinal component index. * @return TextComponent instance or null if component was not found. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public static TextComponent findTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) { return findTextComponent(cont, new TextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index); } /** * Searches TextComponent by text. * * @param cont Container to search component in. * @param text TextComponent text. If null, contents is not checked. * @param ce Compare text exactly. * @param ccs Compare text case sensitively. * @return TextComponent instance or null if component was not found. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public static TextComponent findTextComponent(Container cont, String text, boolean ce, boolean ccs) { return findTextComponent(cont, text, ce, ccs, 0); } /** * Waits TextComponent in container. * * @param cont Container to search component in. * @param chooser org.netbeans.jemmy.ComponentChooser implementation. * @param index Ordinal component index. * @return TextComponent instance. */ public static TextComponent waitTextComponent(Container cont, ComponentChooser chooser, int index) { return (TextComponent) waitComponent(cont, new TextComponentFinder(chooser), index); } /** * Waits 0'th TextComponent in container. * * @param cont Container to search component in. * @param chooser org.netbeans.jemmy.ComponentChooser implementation. * @return TextComponent instance. */ public static TextComponent waitTextComponent(Container cont, ComponentChooser chooser) { return waitTextComponent(cont, chooser, 0); } /** * Waits TextComponent by text. * * @param cont Container to search component in. * @param text TextComponent text. If null, contents is not checked. * @param ce Compare text exactly. * @param ccs Compare text case sensitively. * @param index Ordinal component index. * @return TextComponent instance. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public static TextComponent waitTextComponent(Container cont, String text, boolean ce, boolean ccs, int index) { return waitTextComponent(cont, new TextComponentByTextFinder(text, new DefaultStringComparator(ce, ccs)), index); } /** * Waits TextComponent by text. * * @param cont Container to search component in. * @param text TextComponent text. If null, contents is not checked. * @param ce Compare text exactly. * @param ccs Compare text case sensitively. * @return TextComponent instance. * @see ComponentOperator#isCaptionEqual(String, String, boolean, boolean) */ public static TextComponent waitTextComponent(Container cont, String text, boolean ce, boolean ccs) { return waitTextComponent(cont, text, ce, ccs, 0); } static { Timeouts.initDefault("TextComponentOperator.PushKeyTimeout", PUSH_KEY_TIMEOUT); Timeouts.initDefault("TextComponentOperator.BetweenKeysTimeout", BETWEEN_KEYS_TIMEOUT); Timeouts.initDefault("TextComponentOperator.ChangeCaretPositionTimeout", CHANGE_CARET_POSITION_TIMEOUT); Timeouts.initDefault("TextComponentOperator.TypeTextTimeout", TYPE_TEXT_TIMEOUT); } @Override public void setTimeouts(Timeouts timeouts) { super.setTimeouts(timeouts); this.timeouts = timeouts; } @Override public Timeouts getTimeouts() { return timeouts; } @Override public void setOutput(TestOut out) { output = out; super.setOutput(output.createErrorOutput()); } @Override public TestOut getOutput() { return output; } @Override public void copyEnvironment(Operator anotherOperator) { super.copyEnvironment(anotherOperator); driver = (TextDriver) DriverManager. getDriver(DriverManager.TEXT_DRIVER_ID, getClass(), anotherOperator.getProperties()); } /** * Changes caret position. * * @param position Position to move caret to. * */ public void changeCaretPosition(final int position) { makeComponentVisible(); produceTimeRestricted(new Action<Void, Void>() { @Override public Void launch(Void obj) { driver.changeCaretPosition(TextComponentOperator.this, position); return null; } @Override public String getDescription() { return "Caret moving"; } @Override public String toString() { return "TextComponentOperator.changeCaretPosition.Action{description = " + getDescription() + '}'; } }, "TextComponentOperator.ChangeCaretPositionTimeout"); } /** * Selects a part of text. * * @param startPosition Start caret position * @param finalPosition Final caret position * */ public void selectText(final int startPosition, final int finalPosition) { makeComponentVisible(); produceTimeRestricted(new Action<Void, Void>() { @Override public Void launch(Void obj) { driver.selectText(TextComponentOperator.this, startPosition, finalPosition); return null; } @Override public String getDescription() { return "Text selecting"; } @Override public String toString() { return "TextComponentOperator.selectText.Action{description = " + getDescription() + '}'; } }, "TextComponentOperator.TypeTextTimeout"); } /** * Finds start text position. * * @param text Text to be searched. * @param index Index of text instance (first instance has index 0) * @return Caret position correspondent to text start. */ public int getPositionByText(String text, int index) { String allText = getText(); int position = 0; int ind = 0; while ((position = allText.indexOf(text, position)) >= 0) { if (ind == index) { return position; } else { ind++; } position = position + text.length(); } return -1; } /** * Finds start text position. * * @param text Text to be searched. * @return Caret position correspondent to text start. */ public int getPositionByText(String text) { return getPositionByText(text, 0); } /** * Clears text. * */ public void clearText() { output.printLine("Clearing text in text component\n : " + toStringSource()); output.printGolden("Clearing text in text component"); makeComponentVisible(); produceTimeRestricted(new Action<Void, Void>() { @Override public Void launch(Void obj) { driver.clearText(TextComponentOperator.this); return null; } @Override public String getDescription() { return "Text clearing"; } @Override public String toString() { return "TextComponentOperator.clearText.Action{description = " + getDescription() + '}'; } }, "TextComponentOperator.TypeTextTimeout"); } /** * Types text starting from known position. * * @param text Text to be typed. * @param caretPosition Position to start type text */ public void typeText(final String text, final int caretPosition) { output.printLine("Typing text \"" + text + "\" from " + Integer.toString(caretPosition) + " position " + "in text component\n : " + toStringSource()); output.printGolden("Typing text \"" + text + "\" in text component"); makeComponentVisible(); produceTimeRestricted(new Action<Void, Void>() { @Override public Void launch(Void obj) { driver.typeText(TextComponentOperator.this, text, caretPosition); return null; } @Override public String getDescription() { return "Text typing"; } @Override public String toString() { return "TextComponentOperator.typeText.Action{description = " + getDescription() + '}'; } }, "TextComponentOperator.TypeTextTimeout"); } /** * Types text starting from known position. * * @param text Text to be typed. */ public void typeText(String text) { typeText(text, getCaretPosition()); } /** * Requests a focus, clears text, types new one and pushes Enter. * * @param text New text value. Shouldn't include final '\n'. * */ public void enterText(final String text) { makeComponentVisible(); produceTimeRestricted(new Action<Void, Void>() { @Override public Void launch(Void obj) { driver.enterText(TextComponentOperator.this, text); return null; } @Override public String getDescription() { return "Text entering"; } @Override public String toString() { return "TextComponentOperator.enterText.Action{description = " + getDescription() + '}'; } }, "TextComponentOperator.TypeTextTimeout"); } @Override public Hashtable<String, Object> getDump() { Hashtable<String, Object> result = super.getDump(); result.put(TEXT_DPROP, ((TextComponent) getSource()).getText()); return result; } //////////////////////////////////////////////////////// //Mapping // /** * Maps {@code TextComponent.addTextListener(TextListener)} through queue */ public void addTextListener(final TextListener textListener) { runMapping(new MapVoidAction("addTextListener") { @Override public void map() { ((TextComponent) getSource()).addTextListener(textListener); } }); } /** * Maps {@code TextComponent.getCaretPosition()} through queue */ public int getCaretPosition() { return (runMapping(new MapIntegerAction("getCaretPosition") { @Override public int map() { return ((TextComponent) getSource()).getCaretPosition(); } })); } /** * Maps {@code TextComponent.getSelectedText()} through queue */ public String getSelectedText() { return (runMapping(new MapAction<String>("getSelectedText") { @Override public String map() { return ((TextComponent) getSource()).getSelectedText(); } })); } /** * Maps {@code TextComponent.getSelectionEnd()} through queue */ public int getSelectionEnd() { return (runMapping(new MapIntegerAction("getSelectionEnd") { @Override public int map() { return ((TextComponent) getSource()).getSelectionEnd(); } })); } /** * Maps {@code TextComponent.getSelectionStart()} through queue */ public int getSelectionStart() { return (runMapping(new MapIntegerAction("getSelectionStart") { @Override public int map() { return ((TextComponent) getSource()).getSelectionStart(); } })); } /** * Maps {@code TextComponent.getText()} through queue */ public String getText() { return (runMapping(new MapAction<String>("getText") { @Override public String map() { return ((TextComponent) getSource()).getText(); } })); } /** * Maps {@code TextComponent.isEditable()} through queue */ public boolean isEditable() { return (runMapping(new MapBooleanAction("isEditable") { @Override public boolean map() { return ((TextComponent) getSource()).isEditable(); } })); } /** * Maps {@code TextComponent.removeTextListener(TextListener)} through queue */ public void removeTextListener(final TextListener textListener) { runMapping(new MapVoidAction("removeTextListener") { @Override public void map() { ((TextComponent) getSource()).removeTextListener(textListener); } }); } /** * Maps {@code TextComponent.select(int, int)} through queue */ public void select(final int i, final int i1) { runMapping(new MapVoidAction("select") { @Override public void map() { ((TextComponent) getSource()).select(i, i1); } }); } /** * Maps {@code TextComponent.selectAll()} through queue */ public void selectAll() { runMapping(new MapVoidAction("selectAll") { @Override public void map() { ((TextComponent) getSource()).selectAll(); } }); } /** * Maps {@code TextComponent.setCaretPosition(int)} through queue */ public void setCaretPosition(final int i) { runMapping(new MapVoidAction("setCaretPosition") { @Override public void map() { ((TextComponent) getSource()).setCaretPosition(i); } }); } /** * Maps {@code TextComponent.setEditable(boolean)} through queue */ public void setEditable(final boolean b) { runMapping(new MapVoidAction("setEditable") { @Override public void map() { ((TextComponent) getSource()).setEditable(b); } }); } /** * Maps {@code TextComponent.setSelectionEnd(int)} through queue */ public void setSelectionEnd(final int i) { runMapping(new MapVoidAction("setSelectionEnd") { @Override public void map() { ((TextComponent) getSource()).setSelectionEnd(i); } }); } /** * Maps {@code TextComponent.setSelectionStart(int)} through queue */ public void setSelectionStart(final int i) { runMapping(new MapVoidAction("setSelectionStart") { @Override public void map() { ((TextComponent) getSource()).setSelectionStart(i); } }); } /** * Maps {@code TextComponent.setText(String)} through queue */ public void setText(final String string) { runMapping(new MapVoidAction("setText") { @Override public void map() { ((TextComponent) getSource()).setText(string); } }); } //End of mapping // //////////////////////////////////////////////////////// /** * Return a TextDriver used by this component. * * @return a driver got by the operator during creation. */ protected TextDriver getTextDriver() { return driver; } /** * Allows to find component by text. */ public static class TextComponentByTextFinder implements ComponentChooser { String label; StringComparator comparator; /** * Constructs TextComponentByTextFinder. * * @param lb a text pattern * @param comparator specifies string comparision algorithm. */ public TextComponentByTextFinder(String lb, StringComparator comparator) { label = lb; this.comparator = comparator; } /** * Constructs TextComponentByTextFinder. * * @param lb a text pattern */ public TextComponentByTextFinder(String lb) { this(lb, Operator.getDefaultStringComparator()); } @Override public boolean checkComponent(Component comp) { if (comp instanceof TextComponent) { if (((TextComponent) comp).getText() != null) { return (comparator.equals(((TextComponent) comp).getText(), label)); } } return false; } @Override public String getDescription() { return "TextComponent with text \"" + label + "\""; } @Override public String toString() { return "TextComponentByTextFinder{" + "label=" + label + ", comparator=" + comparator + '}'; } } /** * Checks component type. */ public static class TextComponentFinder extends Finder { /** * Constructs TextComponentFinder. * * @param sf other searching criteria. */ public TextComponentFinder(ComponentChooser sf) { super(TextComponent.class, sf); } /** * Constructs TextComponentFinder. */ public TextComponentFinder() { super(TextComponent.class); } } }