jdk/test/sanity/client/lib/jemmy/src/org/netbeans/jemmy/drivers/text/TextKeyboardDriver.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.drivers.text;

import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import org.netbeans.jemmy.CharBindingMap;
import org.netbeans.jemmy.QueueTool;
import org.netbeans.jemmy.Timeout;
import org.netbeans.jemmy.drivers.DriverManager;
import org.netbeans.jemmy.drivers.KeyDriver;
import org.netbeans.jemmy.drivers.LightSupportiveDriver;
import org.netbeans.jemmy.drivers.TextDriver;
import org.netbeans.jemmy.operators.ComponentOperator;

/**
 * Superclass for all TextDrivers using keyboard.
 *
 * @author Alexandre Iline(alexandre.iline@oracle.com)
 */
public abstract class TextKeyboardDriver extends LightSupportiveDriver implements TextDriver {

    /**
     * Constructs a TextKeyboardDriver.
     *
     * @param supported an array of supported class names
     */
    public TextKeyboardDriver(String[] supported) {
        super(supported);
    }

    @Override
    public void changeCaretPosition(ComponentOperator oper, int position) {
        DriverManager.getFocusDriver(oper).giveFocus(oper);
        checkSupported(oper);
        changeCaretPosition(oper, position, 0);
    }

    @Override
    public void selectText(ComponentOperator oper, int startPosition, int finalPosition) {
        changeCaretPosition(oper, startPosition);
        DriverManager.getKeyDriver(oper).pressKey(oper, KeyEvent.VK_SHIFT, 0);
        changeCaretPosition(oper, finalPosition, InputEvent.SHIFT_MASK);
        DriverManager.getKeyDriver(oper).releaseKey(oper, KeyEvent.VK_SHIFT, 0);
    }

    @Override
    public void clearText(ComponentOperator oper) {
        DriverManager.getFocusDriver(oper).giveFocus(oper);
        checkSupported(oper);
        KeyDriver kdriver = DriverManager.getKeyDriver(oper);
        Timeout pushTime = oper.getTimeouts().create("ComponentOperator.PushKeyTimeout");
        Timeout betweenTime = getBetweenTimeout(oper);
        while (getCaretPosition(oper) > 0) {
            kdriver.typeKey(oper, KeyEvent.VK_BACK_SPACE, (char) KeyEvent.VK_BACK_SPACE, 0, pushTime);
            betweenTime.sleep();
        }
        while (getText(oper).length() > 0) {
            kdriver.pushKey(oper, KeyEvent.VK_DELETE, 0, pushTime);
            betweenTime.sleep();
        }
    }

    @Override
    public void typeText(ComponentOperator oper, String text, int caretPosition) {
        changeCaretPosition(oper, caretPosition);
        KeyDriver kDriver = DriverManager.getKeyDriver(oper);
        CharBindingMap map = oper.getCharBindingMap();
        Timeout pushTime = oper.getTimeouts().create("ComponentOperator.PushKeyTimeout");
        Timeout betweenTime = getBetweenTimeout(oper);
        char[] crs = text.toCharArray();
        for (char cr : crs) {
            kDriver.typeKey(oper, map.getCharKey(cr), cr, map.getCharModifiers(cr), pushTime);
            betweenTime.sleep();
        }
    }

    @Override
    public void changeText(ComponentOperator oper, String text) {
        clearText(oper);
        typeText(oper, text, 0);
    }

    @Override
    public void enterText(ComponentOperator oper, String text) {
        changeText(oper, text);
        DriverManager.getKeyDriver(oper).pushKey(oper, KeyEvent.VK_ENTER, 0,
                new Timeout("", 0));
    }

    /**
     * Returns operator's text.
     *
     * @param oper an operator.
     * @return string representing component text.
     */
    public abstract String getText(ComponentOperator oper);

    /**
     * Returns current caret position.
     *
     * @param oper an operator.
     * @return int represnting current operator's caret position.
     */
    public abstract int getCaretPosition(ComponentOperator oper);

    /**
     * Returns a caret position of selection start.
     *
     * @param oper an operator.
     * @return int represnting index of operator's selection start.
     */
    public abstract int getSelectionStart(ComponentOperator oper);

    /**
     * Returns a caret position of selection end.
     *
     * @param oper an operator.
     * @return int represnting index of operator's selection end.
     */
    public abstract int getSelectionEnd(ComponentOperator oper);

    /**
     * Returns an array of navigation keys.
     *
     * @param oper an operator.
     * @return an array on NavigationKey instances.
     */
    public abstract NavigationKey[] getKeys(ComponentOperator oper);

    /**
     * Returns a timeout to sleep between text typing and caret operations.
     *
     * @param oper an operator.
     * @return a Timeout instance.
     */
    public abstract Timeout getBetweenTimeout(ComponentOperator oper);

    /**
     * Changes current caret position to specifyed.
     *
     * @param oper an operator.
     * @param position new caret position
     * @param preModifiers a modifiers (combination of
     * {@code InputEvent.*_MASK} fields) pushed before caret moving (like
     * shift during text selection).
     */
    protected void changeCaretPosition(ComponentOperator oper, final int position, final int preModifiers) {
        NavigationKey[] keys = getKeys(oper);
        for (int i = keys.length - 1; i >= 0; i--) {
            if (keys[i] instanceof OffsetKey) {
                moveCaret(oper, (OffsetKey) keys[i], position, preModifiers);
            } else {
                moveCaret(oper, (GoAndBackKey) keys[i], position, preModifiers);
            }
        }
    }

    private int difference(int one, int two) {
        if (one >= two) {
            return one - two;
        } else {
            return two - one;
        }
    }

    private void push(ComponentOperator oper, NavigationKey key, int preModifiers) {
        DriverManager.getKeyDriver(oper).
                pushKey(oper, key.getKeyCode(), key.getModifiers() | preModifiers,
                        oper.getTimeouts().create("ComponentOperator.PushKeyTimeout"));
        getBetweenTimeout(oper).sleep();
    }

    private final void moveCaret(ComponentOperator oper, GoAndBackKey key, int position, int preModifiers) {
        int newDiff = difference(position, getCaretPosition(oper));
        int oldDiff = newDiff;
        QueueTool qTool = new QueueTool();
        qTool.setOutput(oper.getOutput().createErrorOutput());
        while (key.getDirection() * (position - getCaretPosition(oper)) > 0) {
            oldDiff = newDiff;
            push(oper, key, preModifiers);
            qTool.waitEmpty();
            newDiff = difference(position, getCaretPosition(oper));
            if (newDiff == oldDiff) {
                return;
            }
        }
        if (newDiff > oldDiff) {
            push(oper, key.getBackKey(), preModifiers);
        }
    }

    private final void moveCaret(ComponentOperator oper, OffsetKey key, int position, int preModifiers) {
        if (gotToGo(oper, position, key.getExpectedPosition())) {
            push(oper, key, preModifiers);
        }
    }

    private boolean gotToGo(ComponentOperator oper, int point, int offset) {
        return difference(point, offset) < difference(point, getCaretPosition(oper));
    }
}