1 /*
   2  * Copyright (c) 2000, 2013, 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 
  26 package java.awt.event;
  27 
  28 import java.awt.Component;
  29 
  30 import java.lang.annotation.Native;
  31 
  32 /**
  33  * An event which indicates that the mouse wheel was rotated in a component.
  34  * <P>
  35  * A wheel mouse is a mouse which has a wheel in place of the middle button.
  36  * This wheel can be rotated towards or away from the user.  Mouse wheels are
  37  * most often used for scrolling, though other uses are possible.
  38  * <P>
  39  * A MouseWheelEvent object is passed to every <code>MouseWheelListener</code>
  40  * object which registered to receive the "interesting" mouse events using the
  41  * component's <code>addMouseWheelListener</code> method.  Each such listener
  42  * object gets a <code>MouseEvent</code> containing the mouse event.
  43  * <P>
  44  * Due to the mouse wheel's special relationship to scrolling Components,
  45  * MouseWheelEvents are delivered somewhat differently than other MouseEvents.
  46  * This is because while other MouseEvents usually affect a change on
  47  * the Component directly under the mouse
  48  * cursor (for instance, when clicking a button), MouseWheelEvents often have
  49  * an effect away from the mouse cursor (moving the wheel while
  50  * over a Component inside a ScrollPane should scroll one of the
  51  * Scrollbars on the ScrollPane).
  52  * <P>
  53  * MouseWheelEvents start delivery from the Component underneath the
  54  * mouse cursor.  If MouseWheelEvents are not enabled on the
  55  * Component, the event is delivered to the first ancestor
  56  * Container with MouseWheelEvents enabled.  This will usually be
  57  * a ScrollPane with wheel scrolling enabled.  The source
  58  * Component and x,y coordinates will be relative to the event's
  59  * final destination (the ScrollPane).  This allows a complex
  60  * GUI to be installed without modification into a ScrollPane, and
  61  * for all MouseWheelEvents to be delivered to the ScrollPane for
  62  * scrolling.
  63  * <P>
  64  * Some AWT Components are implemented using native widgets which
  65  * display their own scrollbars and handle their own scrolling.
  66  * The particular Components for which this is true will vary from
  67  * platform to platform.  When the mouse wheel is
  68  * moved over one of these Components, the event is delivered straight to
  69  * the native widget, and not propagated to ancestors.
  70  * <P>
  71  * Platforms offer customization of the amount of scrolling that
  72  * should take place when the mouse wheel is moved.  The two most
  73  * common settings are to scroll a certain number of "units"
  74  * (commonly lines of text in a text-based component) or an entire "block"
  75  * (similar to page-up/page-down).  The MouseWheelEvent offers
  76  * methods for conforming to the underlying platform settings.  These
  77  * platform settings can be changed at any time by the user.  MouseWheelEvents
  78  * reflect the most recent settings.
  79  * <P>
  80  * The <code>MouseWheelEvent</code> class includes methods for
  81  * getting the number of "clicks" by which the mouse wheel is rotated.
  82  * The {@link #getWheelRotation} method returns the integer number
  83  * of "clicks" corresponding to the number of notches by which the wheel was
  84  * rotated. In addition to this method, the <code>MouseWheelEvent</code>
  85  * class provides the {@link #getPreciseWheelRotation} method which returns
  86  * a double number of "clicks" in case a partial rotation occurred.
  87  * The {@link #getPreciseWheelRotation} method is useful if a mouse supports
  88  * a high-resolution wheel, such as a freely rotating wheel with no
  89  * notches. Applications can benefit by using this method to process
  90  * mouse wheel events more precisely, and thus, making visual perception
  91  * smoother.
  92  *
  93  * @author Brent Christian
  94  * @see MouseWheelListener
  95  * @see java.awt.ScrollPane
  96  * @see java.awt.ScrollPane#setWheelScrollingEnabled(boolean)
  97  * @see javax.swing.JScrollPane
  98  * @see javax.swing.JScrollPane#setWheelScrollingEnabled(boolean)
  99  * @since 1.4
 100  */
 101 
 102 public class MouseWheelEvent extends MouseEvent {
 103 
 104     /**
 105      * Constant representing scrolling by "units" (like scrolling with the
 106      * arrow keys)
 107      *
 108      * @see #getScrollType
 109      */
 110     @Native public static final int WHEEL_UNIT_SCROLL = 0;
 111 
 112     /**
 113      * Constant representing scrolling by a "block" (like scrolling
 114      * with page-up, page-down keys)
 115      *
 116      * @see #getScrollType
 117      */
 118     @Native public static final int WHEEL_BLOCK_SCROLL = 1;
 119 
 120     /**
 121      * Indicates what sort of scrolling should take place in response to this
 122      * event, based on platform settings.  Legal values are:
 123      * <ul>
 124      * <li> WHEEL_UNIT_SCROLL
 125      * <li> WHEEL_BLOCK_SCROLL
 126      * </ul>
 127      *
 128      * @see #getScrollType
 129      */
 130     int scrollType;
 131 
 132     /**
 133      * Only valid for scrollType WHEEL_UNIT_SCROLL.
 134      * Indicates number of units that should be scrolled per
 135      * click of mouse wheel rotation, based on platform settings.
 136      *
 137      * @see #getScrollAmount
 138      * @see #getScrollType
 139      */
 140     int scrollAmount;
 141 
 142     /**
 143      * Indicates how far the mouse wheel was rotated.
 144      *
 145      * @see #getWheelRotation
 146      */
 147     int wheelRotation;
 148 
 149     /**
 150      * Indicates how far the mouse wheel was rotated.
 151      *
 152      * @see #getPreciseWheelRotation
 153      */
 154     double preciseWheelRotation;
 155 
 156     /*
 157      * serialVersionUID
 158      */
 159 
 160     private static final long serialVersionUID = 6459879390515399677L;
 161 
 162     /**
 163      * Constructs a <code>MouseWheelEvent</code> object with the
 164      * specified source component, type, modifiers, coordinates,
 165      * scroll type, scroll amount, and wheel rotation.
 166      * <p>Absolute coordinates xAbs and yAbs are set to source's location on screen plus
 167      * relative coordinates x and y. xAbs and yAbs are set to zero if the source is not showing.
 168      * <p>Note that passing in an invalid <code>id</code> results in
 169      * unspecified behavior. This method throws an
 170      * <code>IllegalArgumentException</code> if <code>source</code>
 171      * is <code>null</code>.
 172      *
 173      * @param source         the <code>Component</code> that originated
 174      *                       the event
 175      * @param id             the integer that identifies the event
 176      * @param when           a long that gives the time the event occurred
 177      * @param modifiers      the modifier keys down during event
 178      *                       (shift, ctrl, alt, meta)
 179      * @param x              the horizontal x coordinate for the mouse location
 180      * @param y              the vertical y coordinate for the mouse location
 181      * @param clickCount     the number of mouse clicks associated with event
 182      * @param popupTrigger   a boolean, true if this event is a trigger for a
 183      *                       popup-menu
 184      * @param scrollType     the type of scrolling which should take place in
 185      *                       response to this event;  valid values are
 186      *                       <code>WHEEL_UNIT_SCROLL</code> and
 187      *                       <code>WHEEL_BLOCK_SCROLL</code>
 188      * @param  scrollAmount  for scrollType <code>WHEEL_UNIT_SCROLL</code>,
 189      *                       the number of units to be scrolled
 190      * @param wheelRotation  the integer number of "clicks" by which the mouse
 191      *                       wheel was rotated
 192      *
 193      * @throws IllegalArgumentException if <code>source</code> is null
 194      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean)
 195      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, int, int, boolean, int)
 196      */
 197     public MouseWheelEvent (Component source, int id, long when, int modifiers,
 198                       int x, int y, int clickCount, boolean popupTrigger,
 199                       int scrollType, int scrollAmount, int wheelRotation) {
 200 
 201         this(source, id, when, modifiers, x, y, 0, 0, clickCount,
 202              popupTrigger, scrollType, scrollAmount, wheelRotation);
 203     }
 204 
 205     /**
 206      * Constructs a <code>MouseWheelEvent</code> object with the
 207      * specified source component, type, modifiers, coordinates,
 208      * absolute coordinates, scroll type, scroll amount, and wheel rotation.
 209      * <p>Note that passing in an invalid <code>id</code> results in
 210      * unspecified behavior. This method throws an
 211      * <code>IllegalArgumentException</code> if <code>source</code>
 212      * is <code>null</code>.<p>
 213      * Even if inconsistent values for relative and absolute coordinates are
 214      * passed to the constructor, the MouseWheelEvent instance is still
 215      * created and no exception is thrown.
 216      *
 217      * @param source         the <code>Component</code> that originated
 218      *                       the event
 219      * @param id             the integer that identifies the event
 220      * @param when           a long that gives the time the event occurred
 221      * @param modifiers      the modifier keys down during event
 222      *                       (shift, ctrl, alt, meta)
 223      * @param x              the horizontal x coordinate for the mouse location
 224      * @param y              the vertical y coordinate for the mouse location
 225      * @param xAbs           the absolute horizontal x coordinate for the mouse location
 226      * @param yAbs           the absolute vertical y coordinate for the mouse location
 227      * @param clickCount     the number of mouse clicks associated with event
 228      * @param popupTrigger   a boolean, true if this event is a trigger for a
 229      *                       popup-menu
 230      * @param scrollType     the type of scrolling which should take place in
 231      *                       response to this event;  valid values are
 232      *                       <code>WHEEL_UNIT_SCROLL</code> and
 233      *                       <code>WHEEL_BLOCK_SCROLL</code>
 234      * @param  scrollAmount  for scrollType <code>WHEEL_UNIT_SCROLL</code>,
 235      *                       the number of units to be scrolled
 236      * @param wheelRotation  the integer number of "clicks" by which the mouse
 237      *                       wheel was rotated
 238      *
 239      * @throws IllegalArgumentException if <code>source</code> is null
 240      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean)
 241      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, int, int, boolean, int)
 242      * @since 1.6
 243      */
 244     public MouseWheelEvent (Component source, int id, long when, int modifiers,
 245                             int x, int y, int xAbs, int yAbs, int clickCount, boolean popupTrigger,
 246                             int scrollType, int scrollAmount, int wheelRotation) {
 247 
 248         this(source, id, when, modifiers, x, y, xAbs, yAbs, clickCount, popupTrigger,
 249              scrollType, scrollAmount, wheelRotation, wheelRotation);
 250 
 251     }
 252 
 253 
 254     /**
 255      * Constructs a <code>MouseWheelEvent</code> object with the specified
 256      * source component, type, modifiers, coordinates, absolute coordinates,
 257      * scroll type, scroll amount, and wheel rotation.
 258      * <p>Note that passing in an invalid <code>id</code> parameter results
 259      * in unspecified behavior. This method throws an
 260      * <code>IllegalArgumentException</code> if <code>source</code> equals
 261      * <code>null</code>.
 262      * <p>Even if inconsistent values for relative and absolute coordinates
 263      * are passed to the constructor, a <code>MouseWheelEvent</code> instance
 264      * is still created and no exception is thrown.
 265      *
 266      * @param source         the <code>Component</code> that originated the event
 267      * @param id             the integer value that identifies the event
 268      * @param when           a long value that gives the time when the event occurred
 269      * @param modifiers      the modifier keys down during event
 270      *                       (shift, ctrl, alt, meta)
 271      * @param x              the horizontal <code>x</code> coordinate for the
 272      *                       mouse location
 273      * @param y              the vertical <code>y</code> coordinate for the
 274      *                       mouse location
 275      * @param xAbs           the absolute horizontal <code>x</code> coordinate for
 276      *                       the mouse location
 277      * @param yAbs           the absolute vertical <code>y</code> coordinate for
 278      *                       the mouse location
 279      * @param clickCount     the number of mouse clicks associated with the event
 280      * @param popupTrigger   a boolean value, <code>true</code> if this event is a trigger
 281      *                       for a popup-menu
 282      * @param scrollType     the type of scrolling which should take place in
 283      *                       response to this event;  valid values are
 284      *                       <code>WHEEL_UNIT_SCROLL</code> and
 285      *                       <code>WHEEL_BLOCK_SCROLL</code>
 286      * @param  scrollAmount  for scrollType <code>WHEEL_UNIT_SCROLL</code>,
 287      *                       the number of units to be scrolled
 288      * @param wheelRotation  the integer number of "clicks" by which the mouse wheel
 289      *                       was rotated
 290      * @param preciseWheelRotation the double number of "clicks" by which the mouse wheel
 291      *                       was rotated
 292      *
 293      * @throws IllegalArgumentException if <code>source</code> is null
 294      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean)
 295      * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, int, int, boolean, int)
 296      * @since 1.7
 297      */
 298     public MouseWheelEvent (Component source, int id, long when, int modifiers,
 299                             int x, int y, int xAbs, int yAbs, int clickCount, boolean popupTrigger,
 300                             int scrollType, int scrollAmount, int wheelRotation, double preciseWheelRotation) {
 301 
 302         super(source, id, when, modifiers, x, y, xAbs, yAbs, clickCount,
 303               popupTrigger, MouseEvent.NOBUTTON);
 304 
 305         this.scrollType = scrollType;
 306         this.scrollAmount = scrollAmount;
 307         this.wheelRotation = wheelRotation;
 308         this.preciseWheelRotation = preciseWheelRotation;
 309 
 310     }
 311 
 312     /**
 313      * Returns the type of scrolling that should take place in response to this
 314      * event.  This is determined by the native platform.  Legal values are:
 315      * <ul>
 316      * <li> MouseWheelEvent.WHEEL_UNIT_SCROLL
 317      * <li> MouseWheelEvent.WHEEL_BLOCK_SCROLL
 318      * </ul>
 319      *
 320      * @return either MouseWheelEvent.WHEEL_UNIT_SCROLL or
 321      *  MouseWheelEvent.WHEEL_BLOCK_SCROLL, depending on the configuration of
 322      *  the native platform.
 323      * @see java.awt.Adjustable#getUnitIncrement
 324      * @see java.awt.Adjustable#getBlockIncrement
 325      * @see javax.swing.Scrollable#getScrollableUnitIncrement
 326      * @see javax.swing.Scrollable#getScrollableBlockIncrement
 327      */
 328     public int getScrollType() {
 329         return scrollType;
 330     }
 331 
 332     /**
 333      * Returns the number of units that should be scrolled per
 334      * click of mouse wheel rotation.
 335      * Only valid if <code>getScrollType</code> returns
 336      * <code>MouseWheelEvent.WHEEL_UNIT_SCROLL</code>
 337      *
 338      * @return number of units to scroll, or an undefined value if
 339      *  <code>getScrollType</code> returns
 340      *  <code>MouseWheelEvent.WHEEL_BLOCK_SCROLL</code>
 341      * @see #getScrollType
 342      */
 343     public int getScrollAmount() {
 344         return scrollAmount;
 345     }
 346 
 347     /**
 348      * Returns the number of "clicks" the mouse wheel was rotated, as an integer.
 349      * A partial rotation may occur if the mouse supports a high-resolution wheel.
 350      * In this case, the method returns zero until a full "click" has been accumulated.
 351      *
 352      * @return negative values if the mouse wheel was rotated up/away from
 353      * the user, and positive values if the mouse wheel was rotated down/
 354      * towards the user
 355      * @see #getPreciseWheelRotation
 356      */
 357     public int getWheelRotation() {
 358         return wheelRotation;
 359     }
 360 
 361     /**
 362      * Returns the number of "clicks" the mouse wheel was rotated, as a double.
 363      * A partial rotation may occur if the mouse supports a high-resolution wheel.
 364      * In this case, the return value will include a fractional "click".
 365      *
 366      * @return negative values if the mouse wheel was rotated up or away from
 367      * the user, and positive values if the mouse wheel was rotated down or
 368      * towards the user
 369      * @see #getWheelRotation
 370      * @since 1.7
 371      */
 372     public double getPreciseWheelRotation() {
 373         return preciseWheelRotation;
 374     }
 375 
 376     /**
 377      * This is a convenience method to aid in the implementation of
 378      * the common-case MouseWheelListener - to scroll a ScrollPane or
 379      * JScrollPane by an amount which conforms to the platform settings.
 380      * (Note, however, that <code>ScrollPane</code> and
 381      * <code>JScrollPane</code> already have this functionality built in.)
 382      * <P>
 383      * This method returns the number of units to scroll when scroll type is
 384      * MouseWheelEvent.WHEEL_UNIT_SCROLL, and should only be called if
 385      * <code>getScrollType</code> returns MouseWheelEvent.WHEEL_UNIT_SCROLL.
 386      * <P>
 387      * Direction of scroll, amount of wheel movement,
 388      * and platform settings for wheel scrolling are all accounted for.
 389      * This method does not and cannot take into account value of the
 390      * Adjustable/Scrollable unit increment, as this will vary among
 391      * scrolling components.
 392      * <P>
 393      * A simplified example of how this method might be used in a
 394      * listener:
 395      * <pre>
 396      *  mouseWheelMoved(MouseWheelEvent event) {
 397      *      ScrollPane sp = getScrollPaneFromSomewhere();
 398      *      Adjustable adj = sp.getVAdjustable()
 399      *      if (MouseWheelEvent.getScrollType() == WHEEL_UNIT_SCROLL) {
 400      *          int totalScrollAmount =
 401      *              event.getUnitsToScroll() *
 402      *              adj.getUnitIncrement();
 403      *          adj.setValue(adj.getValue() + totalScrollAmount);
 404      *      }
 405      *  }
 406      * </pre>
 407      *
 408      * @return the number of units to scroll based on the direction and amount
 409      *  of mouse wheel rotation, and on the wheel scrolling settings of the
 410      *  native platform
 411      * @see #getScrollType
 412      * @see #getScrollAmount
 413      * @see MouseWheelListener
 414      * @see java.awt.Adjustable
 415      * @see java.awt.Adjustable#getUnitIncrement
 416      * @see javax.swing.Scrollable
 417      * @see javax.swing.Scrollable#getScrollableUnitIncrement
 418      * @see java.awt.ScrollPane
 419      * @see java.awt.ScrollPane#setWheelScrollingEnabled
 420      * @see javax.swing.JScrollPane
 421      * @see javax.swing.JScrollPane#setWheelScrollingEnabled
 422      */
 423     public int getUnitsToScroll() {
 424         return scrollAmount * wheelRotation;
 425     }
 426 
 427     /**
 428      * Returns a parameter string identifying this event.
 429      * This method is useful for event-logging and for debugging.
 430      *
 431      * @return a string identifying the event and its attributes
 432      */
 433     public String paramString() {
 434         String scrollTypeStr = null;
 435 
 436         if (getScrollType() == WHEEL_UNIT_SCROLL) {
 437             scrollTypeStr = "WHEEL_UNIT_SCROLL";
 438         }
 439         else if (getScrollType() == WHEEL_BLOCK_SCROLL) {
 440             scrollTypeStr = "WHEEL_BLOCK_SCROLL";
 441         }
 442         else {
 443             scrollTypeStr = "unknown scroll type";
 444         }
 445         return super.paramString()+",scrollType="+scrollTypeStr+
 446          ",scrollAmount="+getScrollAmount()+",wheelRotation="+
 447          getWheelRotation()+",preciseWheelRotation="+getPreciseWheelRotation();
 448     }
 449 }