AbstractScrollDriver.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.scrolling;
24
25import java.awt.Adjustable;
26import java.awt.Point;
27import org.netbeans.jemmy.JemmyException;
28import org.netbeans.jemmy.JemmyProperties;
29
30import org.netbeans.jemmy.Timeout;
31import org.netbeans.jemmy.drivers.LightSupportiveDriver;
32import org.netbeans.jemmy.drivers.ScrollDriver;
33import org.netbeans.jemmy.operators.ComponentOperator;
34
35/**
36 * Superclass for all scroll drivers. Contains all the logic of scrolling. Tries
37 * allowed operations in this order: "jump", "drag'n'drop", "push'n'wait",
38 * "step". Repeats "step" scrolling while scroller value is not equal to the
39 * necessary value, but no more than {@code ADJUST_CLICK_COUNT}.
40 *
41 * @author Alexandre Iline(alexandre.iline@oracle.com)
42 */
43public abstract class AbstractScrollDriver extends LightSupportiveDriver implements ScrollDriver {
44
45    /**
46     * Maximal number of attempts to reach required position by minimal
47     * scrolling operation.
48     */
49    public static final int ADJUST_CLICK_COUNT = 10;
50    public static final String SCROLL_FREEZE_TIMEOUT = AbstractScrollDriver.class.getName() + ".freeze.timeout";
51
52    static {
53        JemmyProperties.getProperties().initTimeout(SCROLL_FREEZE_TIMEOUT, 1000);
54    }
55
56    /**
57     * Constructs an AbstractScrollDriver.
58     *
59     * @param supported an array of supported class names
60     */
61    public AbstractScrollDriver(String[] supported) {
62        super(supported);
63    }
64
65    @Override
66    public void scroll(ComponentOperator oper, ScrollAdjuster adj) {
67        if (canJump(oper)) {
68            doJumps(oper, adj);
69        }
70        if (canDragAndDrop(oper)) {
71            doDragAndDrop(oper, adj);
72        }
73        if (canPushAndWait(oper)) {
74            if (!doPushAndWait(oper, adj, oper.getTimeouts().getTimeout(SCROLL_FREEZE_TIMEOUT))) {
75                throw new JemmyException("Scrolling stuck for more than "
76                        + oper.getTimeouts().getTimeout(SCROLL_FREEZE_TIMEOUT)
77                        + " on " + oper);
78            }
79        }
80        for (int i = 0; i < ADJUST_CLICK_COUNT; i++) {
81            doSteps(oper, adj);
82        }
83    }
84
85    /**
86     * Performs minimal scrolling step.
87     *
88     * @param oper an operator.
89     * @param adj a scroll adjuster
90     */
91    protected abstract void step(ComponentOperator oper, ScrollAdjuster adj);
92
93    /**
94     * Performs maximal scroll step.
95     *
96     * @param oper an operator.
97     * @param adj a scroll adjuster
98     */
99    protected abstract void jump(ComponentOperator oper, ScrollAdjuster adj);
100
101    /**
102     * Presses something like a scroll button.
103     *
104     * @param oper an operator.
105     * @param direction - one of the ScrollAdjister.INCREASE_SCROLL_DIRECTION,
106     * ScrollAdjister.DECREASE_SCROLL_DIRECTION,
107     * ScrollAdjister.DO_NOT_TOUCH_SCROLL_DIRECTION values.
108     * @param orientation one of the Adjustable.HORIZONTAL or
109     * Adjustable.VERTICAL values.
110     */
111    protected abstract void startPushAndWait(ComponentOperator oper, int direction, int orientation);
112
113    /**
114     * Releases something like a scroll button.
115     *
116     * @param oper an operator.
117     * @param direction - one of the ScrollAdjister.INCREASE_SCROLL_DIRECTION,
118     * ScrollAdjister.DECREASE_SCROLL_DIRECTION,
119     * ScrollAdjister.DO_NOT_TOUCH_SCROLL_DIRECTION values.
120     * @param orientation one of the Adjustable.HORIZONTAL or
121     * Adjustable.VERTICAL values.
122     */
123    protected abstract void stopPushAndWait(ComponentOperator oper, int direction, int orientation);
124
125    /**
126     * Starts drag'n'drop scrolling.
127     *
128     * @param oper an operator.
129     * @return start drugging point.
130     */
131    protected abstract Point startDragging(ComponentOperator oper);
132
133    /**
134     * Drop at a specified point.
135     *
136     * @param oper an operator.
137     * @param pnt the point to drop.
138     */
139    protected abstract void drop(ComponentOperator oper, Point pnt);
140
141    /**
142     * Drag to a specified point.
143     *
144     * @param oper an operator.
145     * @param pnt the point to drag to.
146     */
147    protected abstract void drag(ComponentOperator oper, Point pnt);
148
149    /**
150     * Returns a timeout for sleeping between verifications during "push and
151     * wait" scrolling.
152     *
153     * @param oper an operator.
154     * @return a timeout
155     */
156    protected abstract Timeout getScrollDeltaTimeout(ComponentOperator oper);
157
158    /**
159     * Tells if this driver allows to perform drag'n'drop scrolling.
160     *
161     * @param oper an operator.
162     * @return true if this driver allows to drag'n'drop.
163     */
164    protected abstract boolean canDragAndDrop(ComponentOperator oper);
165
166    /**
167     * Tells if this driver allows to perform jumps.
168     *
169     * @param oper an operator.
170     * @return true if this driver allows to jump.
171     */
172    protected abstract boolean canJump(ComponentOperator oper);
173
174    /**
175     * Tells if this driver allows to perform "push and wait" scrolling.
176     *
177     * @param oper an operator.
178     * @return true if this driver allows to "push and wait".
179     */
180    protected abstract boolean canPushAndWait(ComponentOperator oper);
181
182    /**
183     * Returns a number of pixels in one drag and drop scrolling.
184     *
185     * @param oper an operator.
186     * @return drag'n'drop step length.
187     */
188    protected abstract int getDragAndDropStepLength(ComponentOperator oper);
189
190    /**
191     * Performs drag'n'drop scrolling till scroller's value does not cross
192     * required value.
193     *
194     * @param oper an operator.
195     * @param adj a scroll adjuster
196     */
197    protected void doDragAndDrop(ComponentOperator oper, ScrollAdjuster adj) {
198        int direction = adj.getScrollDirection();
199        if (direction != ScrollAdjuster.DO_NOT_TOUCH_SCROLL_DIRECTION) {
200            Point pnt = startDragging(oper);
201            while (adj.getScrollDirection() == direction) {
202                drag(oper, pnt = increasePoint(oper, pnt, adj, direction));
203            }
204            drop(oper, pnt);
205        }
206    }
207
208    /**
209     * Performs jump scrolling till scroller's value does not cross required
210     * value.
211     *
212     * @param oper an operator.
213     * @param adj a scroll adjuster
214     */
215    protected void doJumps(ComponentOperator oper, ScrollAdjuster adj) {
216        int direction = adj.getScrollDirection();
217        if (direction != ScrollAdjuster.DO_NOT_TOUCH_SCROLL_DIRECTION) {
218            while (adj.getScrollDirection() == direction) {
219                jump(oper, adj);
220            }
221        }
222    }
223
224    protected abstract int position(ComponentOperator oper, int orientation);
225
226    /**
227     * Performs "push and wait" scrolling till scroller's value does not cross
228     * required value.
229     *
230     * @param oper an operator.
231     * @param adj a scroll adjuster
232     */
233    protected boolean doPushAndWait(ComponentOperator oper, ScrollAdjuster adj, long freezeTimeout) {
234        int direction = adj.getScrollDirection();
235        int orientation = adj.getScrollOrientation();
236        int position = position(oper, orientation);
237        long lastChanded = System.currentTimeMillis();
238        if (direction != ScrollAdjuster.DO_NOT_TOUCH_SCROLL_DIRECTION) {
239            Timeout delta = getScrollDeltaTimeout(oper);
240            startPushAndWait(oper, direction, orientation);
241            while (adj.getScrollDirection() == direction) {
242                delta.sleep();
243                int curPosition = position(oper, orientation);
244                if (curPosition != position) {
245                    position = curPosition;
246                    lastChanded = System.currentTimeMillis();
247                } else if ((System.currentTimeMillis() - lastChanded) > freezeTimeout) {
248                    return false;
249                }
250            }
251            stopPushAndWait(oper, direction, orientation);
252        }
253        return true;
254    }
255
256    /**
257     * Performs minimal scrollings till scroller's value does not cross required
258     * value.
259     *
260     * @param oper an operator.
261     * @param adj a scroll adjuster
262     */
263    protected void doSteps(ComponentOperator oper, ScrollAdjuster adj) {
264        int direction = adj.getScrollDirection();
265        if (direction != ScrollAdjuster.DO_NOT_TOUCH_SCROLL_DIRECTION) {
266            while (adj.getScrollDirection() == direction) {
267                step(oper, adj);
268            }
269        }
270    }
271
272    private Point increasePoint(ComponentOperator oper, Point pnt, ScrollAdjuster adj, int direction) {
273        return ((adj.getScrollOrientation() == Adjustable.HORIZONTAL)
274                ? new Point(pnt.x + ((direction == 1) ? 1 : -1) * getDragAndDropStepLength(oper), pnt.y)
275                : new Point(pnt.x, pnt.y + ((direction == 1) ? 1 : -1) * getDragAndDropStepLength(oper)));
276    }
277}
278