1 /* 2 * Copyright (c) 2007, 2017 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 */ 23 package org.jemmy.input; 24 25 import java.util.ArrayList; 26 import org.jemmy.JemmyException; 27 import org.jemmy.Point; 28 import org.jemmy.action.Action; 29 import org.jemmy.control.Wrap; 30 import org.jemmy.env.Environment; 31 import org.jemmy.env.Timeout; 32 import org.jemmy.interfaces.Caret; 33 import org.jemmy.interfaces.CaretOwner; 34 import org.jemmy.interfaces.Focusable; 35 import org.jemmy.interfaces.Keyboard.KeyboardButton; 36 import org.jemmy.interfaces.Keyboard.KeyboardModifier; 37 import org.jemmy.interfaces.Mouse.MouseButtons; 38 39 /** 40 * 41 * @author shura 42 */ 43 public class CaretImpl implements Caret { 44 45 /** 46 * Time to sleep between scrolling actions 47 */ 48 public static final Timeout SCROLL_TIMEOUT = 49 new Timeout("ScrollerImpl.scroll", 1); 50 51 static { 52 Environment.getEnvironment().initTimeout(SCROLL_TIMEOUT); 53 } 54 private Wrap<?> wrap; 55 private CaretOwner caretOwner; 56 private ArrayList<ScrollAction> actions; 57 58 /** 59 * 60 * @param wrap 61 * @param caretOwner only position() is used 62 */ 63 public CaretImpl(Wrap<?> wrap, CaretOwner caretOwner) { 64 this.wrap = wrap; 65 this.caretOwner = caretOwner; 66 actions = new ArrayList<ScrollAction>(); 67 } 68 69 /** 70 * 71 * @return 72 */ 73 public Wrap<?> getWrap() { 74 return wrap; 75 } 76 77 /** 78 * 79 * @param action 80 */ 81 protected void addScrollAction(ScrollAction action) { 82 actions.add(0, action); 83 } 84 85 public void to(final double value) { 86 to(new DirectionToPosition(caretOwner, value)); 87 } 88 89 public void to(final Caret.Direction direction) { 90 wrap.getEnvironment().getExecutor().execute(wrap.getEnvironment(), false, new Action() { 91 92 @Override 93 public void run(Object... parameters) { 94 if (direction.to() == 0) { 95 return; 96 } 97 if (wrap.is(Focusable.class)) { 98 wrap.as(Focusable.class).focuser().focus(); 99 } 100 int orig = direction.to(); 101 if (orig == 0) { 102 return; 103 } 104 double prevPos = caretOwner.position(); 105 double prevDist = Double.MAX_VALUE; 106 for (int i = 0; i < actions.size(); i++) { 107 while (!isInterrupted() && (direction.to() * orig) >= 0) { 108 actions.get(i).scrollTo(orig); 109 wrap.getEnvironment().getTimeout(SCROLL_TIMEOUT).sleep(); 110 //if didn't move - use the smaller adjustment 111 //like, puching up when in the first line 112 if(caretOwner.position() == prevPos) { 113 //if did not move and there are more - move to next 114 if(i < actions.size() - 1) { 115 break; 116 } else { 117 //try more and finally fail by timeout 118 //throw new JemmyException("Unable to scoll.", wrap); 119 } 120 } 121 prevPos = caretOwner.position(); 122 if (direction.to() == 0) { 123 return; 124 } 125 } 126 orig = direction.to(); 127 } 128 } 129 130 @Override 131 public String toString() { 132 return "Scrolling to " + direction.toString() + " condition"; 133 } 134 }); 135 } 136 137 /** 138 * @deprecated Use ApproximateCaretOwner.ToPosition or PreciseCaretOwner.ToPosition 139 */ 140 public static class DirectionToPosition implements Direction { 141 142 private double value; 143 private CaretOwner caret; 144 private double precision; 145 146 /** 147 * 148 * @param caret 149 * @param value 150 */ 151 public DirectionToPosition(CaretOwner caret, double value, double precision) { 152 this.value = value; 153 this.caret = caret; 154 this.precision = precision; 155 } 156 157 public DirectionToPosition(CaretOwner caret, double value) { 158 this(caret, value, 0); 159 } 160 161 public int to() { 162 double diff = position() - caret.position(); 163 return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1); 164 } 165 166 /** 167 * 168 * @return 169 */ 170 @Override 171 public String toString() { 172 return "value == " + position(); 173 } 174 175 /** 176 * 177 * @return 178 */ 179 protected double position() { 180 return value; 181 } 182 } 183 184 /** 185 * 186 */ 187 protected static interface ScrollAction { 188 189 /** 190 * 191 * @param direction 192 */ 193 public void scrollTo(int direction); 194 } 195 196 /** 197 * 198 */ 199 protected class MouseScrollAction implements ScrollAction { 200 201 Point up, down; 202 KeyboardModifier[] upMods, downMods; 203 204 /** 205 * 206 * @param down 207 * @param downMods 208 * @param up 209 * @param upMods 210 */ 211 public MouseScrollAction(Point down, KeyboardModifier[] downMods, Point up, KeyboardModifier[] upMods) { 212 this.up = up; 213 this.down = down; 214 this.upMods = upMods; 215 this.downMods = downMods; 216 } 217 218 /** 219 * 220 * @param down 221 * @param up 222 */ 223 public MouseScrollAction(Point down, Point up) { 224 this(up, new KeyboardModifier[0], up, new KeyboardModifier[0]); 225 } 226 227 /** 228 * 229 * @param direction 230 */ 231 public void scrollTo(int direction) { 232 wrap.mouse().click(1, (direction > 0) ? up : down, MouseButtons.BUTTON1, 233 (direction > 0) ? upMods : downMods); 234 } 235 } 236 237 /** 238 * 239 */ 240 protected class KeyboardScrollAction implements ScrollAction { 241 242 KeyboardButton down, up; 243 KeyboardModifier[] downMods, upMods; 244 245 /** 246 * 247 * @param down 248 * @param downMods 249 * @param up 250 * @param upMods 251 */ 252 public KeyboardScrollAction(KeyboardButton down, KeyboardModifier[] downMods, KeyboardButton up, KeyboardModifier[] upMods) { 253 this.down = down; 254 this.up = up; 255 this.downMods = downMods; 256 this.upMods = upMods; 257 } 258 259 /** 260 * 261 * @param down 262 * @param up 263 */ 264 public KeyboardScrollAction(KeyboardButton down, KeyboardButton up) { 265 this(down, new KeyboardModifier[0], up, new KeyboardModifier[0]); 266 } 267 268 /** 269 * 270 * @param direction 271 */ 272 public void scrollTo(int direction) { 273 wrap.keyboard().pushKey((direction > 0) ? up : down, 274 (direction > 0) ? upMods : downMods); 275 } 276 } 277 }