jdk/test/sanity/client/lib/jemmy/src/org/netbeans/jemmy/operators/TextComponentOperator.java
author mrkam
Wed, 30 Mar 2016 19:05:58 -0700
changeset 36744 a00905527ec2
permissions -rw-r--r--
8153141: Develop initial set of tests for SwingSet Reviewed-by: prr

/*
 * 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);
        }
    }
}