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