TextKeyboardDriver.java revision 13978:1993af50385d
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.drivers.text;
24
25import java.awt.event.InputEvent;
26import java.awt.event.KeyEvent;
27
28import org.netbeans.jemmy.CharBindingMap;
29import org.netbeans.jemmy.QueueTool;
30import org.netbeans.jemmy.Timeout;
31import org.netbeans.jemmy.drivers.DriverManager;
32import org.netbeans.jemmy.drivers.KeyDriver;
33import org.netbeans.jemmy.drivers.LightSupportiveDriver;
34import org.netbeans.jemmy.drivers.TextDriver;
35import org.netbeans.jemmy.operators.ComponentOperator;
36
37/**
38 * Superclass for all TextDrivers using keyboard.
39 *
40 * @author Alexandre Iline(alexandre.iline@oracle.com)
41 */
42public abstract class TextKeyboardDriver extends LightSupportiveDriver implements TextDriver {
43
44    /**
45     * Constructs a TextKeyboardDriver.
46     *
47     * @param supported an array of supported class names
48     */
49    public TextKeyboardDriver(String[] supported) {
50        super(supported);
51    }
52
53    @Override
54    public void changeCaretPosition(ComponentOperator oper, int position) {
55        DriverManager.getFocusDriver(oper).giveFocus(oper);
56        checkSupported(oper);
57        changeCaretPosition(oper, position, 0);
58    }
59
60    @Override
61    public void selectText(ComponentOperator oper, int startPosition, int finalPosition) {
62        changeCaretPosition(oper, startPosition);
63        DriverManager.getKeyDriver(oper).pressKey(oper, KeyEvent.VK_SHIFT, 0);
64        changeCaretPosition(oper, finalPosition, InputEvent.SHIFT_MASK);
65        DriverManager.getKeyDriver(oper).releaseKey(oper, KeyEvent.VK_SHIFT, 0);
66    }
67
68    @Override
69    public void clearText(ComponentOperator oper) {
70        DriverManager.getFocusDriver(oper).giveFocus(oper);
71        checkSupported(oper);
72        KeyDriver kdriver = DriverManager.getKeyDriver(oper);
73        Timeout pushTime = oper.getTimeouts().create("ComponentOperator.PushKeyTimeout");
74        Timeout betweenTime = getBetweenTimeout(oper);
75        while (getCaretPosition(oper) > 0) {
76            kdriver.typeKey(oper, KeyEvent.VK_BACK_SPACE, (char) KeyEvent.VK_BACK_SPACE, 0, pushTime);
77            betweenTime.sleep();
78        }
79        while (getText(oper).length() > 0) {
80            kdriver.pushKey(oper, KeyEvent.VK_DELETE, 0, pushTime);
81            betweenTime.sleep();
82        }
83    }
84
85    @Override
86    public void typeText(ComponentOperator oper, String text, int caretPosition) {
87        changeCaretPosition(oper, caretPosition);
88        KeyDriver kDriver = DriverManager.getKeyDriver(oper);
89        CharBindingMap map = oper.getCharBindingMap();
90        Timeout pushTime = oper.getTimeouts().create("ComponentOperator.PushKeyTimeout");
91        Timeout betweenTime = getBetweenTimeout(oper);
92        char[] crs = text.toCharArray();
93        for (char cr : crs) {
94            kDriver.typeKey(oper, map.getCharKey(cr), cr, map.getCharModifiers(cr), pushTime);
95            betweenTime.sleep();
96        }
97    }
98
99    @Override
100    public void changeText(ComponentOperator oper, String text) {
101        clearText(oper);
102        typeText(oper, text, 0);
103    }
104
105    @Override
106    public void enterText(ComponentOperator oper, String text) {
107        changeText(oper, text);
108        DriverManager.getKeyDriver(oper).pushKey(oper, KeyEvent.VK_ENTER, 0,
109                new Timeout("", 0));
110    }
111
112    /**
113     * Returns operator's text.
114     *
115     * @param oper an operator.
116     * @return string representing component text.
117     */
118    public abstract String getText(ComponentOperator oper);
119
120    /**
121     * Returns current caret position.
122     *
123     * @param oper an operator.
124     * @return int represnting current operator's caret position.
125     */
126    public abstract int getCaretPosition(ComponentOperator oper);
127
128    /**
129     * Returns a caret position of selection start.
130     *
131     * @param oper an operator.
132     * @return int represnting index of operator's selection start.
133     */
134    public abstract int getSelectionStart(ComponentOperator oper);
135
136    /**
137     * Returns a caret position of selection end.
138     *
139     * @param oper an operator.
140     * @return int represnting index of operator's selection end.
141     */
142    public abstract int getSelectionEnd(ComponentOperator oper);
143
144    /**
145     * Returns an array of navigation keys.
146     *
147     * @param oper an operator.
148     * @return an array on NavigationKey instances.
149     */
150    public abstract NavigationKey[] getKeys(ComponentOperator oper);
151
152    /**
153     * Returns a timeout to sleep between text typing and caret operations.
154     *
155     * @param oper an operator.
156     * @return a Timeout instance.
157     */
158    public abstract Timeout getBetweenTimeout(ComponentOperator oper);
159
160    /**
161     * Changes current caret position to specifyed.
162     *
163     * @param oper an operator.
164     * @param position new caret position
165     * @param preModifiers a modifiers (combination of
166     * {@code InputEvent.*_MASK} fields) pushed before caret moving (like
167     * shift during text selection).
168     */
169    protected void changeCaretPosition(ComponentOperator oper, final int position, final int preModifiers) {
170        NavigationKey[] keys = getKeys(oper);
171        for (int i = keys.length - 1; i >= 0; i--) {
172            if (keys[i] instanceof OffsetKey) {
173                moveCaret(oper, (OffsetKey) keys[i], position, preModifiers);
174            } else {
175                moveCaret(oper, (GoAndBackKey) keys[i], position, preModifiers);
176            }
177        }
178    }
179
180    private int difference(int one, int two) {
181        if (one >= two) {
182            return one - two;
183        } else {
184            return two - one;
185        }
186    }
187
188    private void push(ComponentOperator oper, NavigationKey key, int preModifiers) {
189        DriverManager.getKeyDriver(oper).
190                pushKey(oper, key.getKeyCode(), key.getModifiers() | preModifiers,
191                        oper.getTimeouts().create("ComponentOperator.PushKeyTimeout"));
192        getBetweenTimeout(oper).sleep();
193    }
194
195    private final void moveCaret(ComponentOperator oper, GoAndBackKey key, int position, int preModifiers) {
196        int newDiff = difference(position, getCaretPosition(oper));
197        int oldDiff = newDiff;
198        QueueTool qTool = new QueueTool();
199        qTool.setOutput(oper.getOutput().createErrorOutput());
200        while (key.getDirection() * (position - getCaretPosition(oper)) > 0) {
201            oldDiff = newDiff;
202            push(oper, key, preModifiers);
203            qTool.waitEmpty();
204            newDiff = difference(position, getCaretPosition(oper));
205            if (newDiff == oldDiff) {
206                return;
207            }
208        }
209        if (newDiff > oldDiff) {
210            push(oper, key.getBackKey(), preModifiers);
211        }
212    }
213
214    private final void moveCaret(ComponentOperator oper, OffsetKey key, int position, int preModifiers) {
215        if (gotToGo(oper, position, key.getExpectedPosition())) {
216            push(oper, key, preModifiers);
217        }
218    }
219
220    private boolean gotToGo(ComponentOperator oper, int point, int offset) {
221        return difference(point, offset) < difference(point, getCaretPosition(oper));
222    }
223}
224