001 /* MouseEvent.java -- a mouse event 002 Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.awt.event; 040 041 import gnu.java.awt.EventModifier; 042 import gnu.java.lang.CPStringBuilder; 043 044 import java.awt.Component; 045 import java.awt.Point; 046 import java.awt.PopupMenu; 047 import java.io.IOException; 048 import java.io.ObjectInputStream; 049 050 /** 051 * This event is generated for a mouse event. There are three main categories 052 * of mouse events: Regular events include pressing, releasing, and clicking 053 * buttons, as well as moving over the boundary of the unobscured portion of 054 * a component. Motion events include movement and dragging. Wheel events are 055 * covered separately by the subclass MouseWheelEvent. 056 * 057 * <p>A mouse event is tied to the unobstructed visible component that the 058 * mouse cursor was over at the time of the action. The button that was 059 * most recently pressed is the only one that shows up in 060 * <code>getModifiers</code>, and is returned by <code>getButton</code>, 061 * while all buttons that are down show up in <code>getModifiersEx</code>. 062 * 063 * <p>Drag events may be cut short if native drag-and-drop operations steal 064 * the event. Likewise, if a mouse drag exceeds the bounds of a window or 065 * virtual device, some platforms may clip the path to fit in the bounds of 066 * the component. 067 * 068 * @author Aaron M. Renn (arenn@urbanophile.com) 069 * @author Eric Blake (ebb9@email.byu.edu) 070 * @see MouseAdapter 071 * @see MouseListener 072 * @see MouseMotionAdapter 073 * @see MouseMotionListener 074 * @see MouseWheelListener 075 * @since 1.1 076 * @status updated to 1.4 077 */ 078 public class MouseEvent extends InputEvent 079 { 080 /** 081 * Compatible with JDK 1.1+. 082 */ 083 private static final long serialVersionUID = -991214153494842848L; 084 085 /** This is the first id in the range of event ids used by this class. */ 086 public static final int MOUSE_FIRST = 500; 087 088 /** This is the last id in the range of event ids used by this class. */ 089 public static final int MOUSE_LAST = 507; 090 091 /** This event id indicates that the mouse was clicked. */ 092 public static final int MOUSE_CLICKED = 500; 093 094 /** This event id indicates that the mouse was pressed. */ 095 public static final int MOUSE_PRESSED = 501; 096 097 /** This event id indicates that the mouse was released. */ 098 public static final int MOUSE_RELEASED = 502; 099 100 /** This event id indicates that the mouse was moved. */ 101 public static final int MOUSE_MOVED = 503; 102 103 /** This event id indicates that the mouse entered a component. */ 104 public static final int MOUSE_ENTERED = 504; 105 106 /** This event id indicates that the mouse exited a component. */ 107 public static final int MOUSE_EXITED = 505; 108 109 /** 110 * This indicates that no button changed state. 111 * 112 * @see #getButton() 113 * @since 1.4 114 */ 115 public static final int NOBUTTON = 0; 116 117 /** 118 * This indicates that button 1 changed state. 119 * 120 * @see #getButton() 121 * @since 1.4 122 */ 123 public static final int BUTTON1 = 1; 124 125 /** 126 * This indicates that button 2 changed state. 127 * 128 * @see #getButton() 129 * @since 1.4 130 */ 131 public static final int BUTTON2 = 2; 132 133 /** 134 * This indicates that button 3 changed state. 135 * 136 * @see #getButton() 137 * @since 1.4 138 */ 139 public static final int BUTTON3 = 3; 140 141 /** This event id indicates that the mouse was dragged over a component. */ 142 public static final int MOUSE_DRAGGED = 506; 143 144 /** 145 * This event id indicates that the mouse wheel was rotated. 146 * 147 * @since 1.4 148 */ 149 public static final int MOUSE_WHEEL = 507; 150 151 /** 152 * The X coordinate of the mouse cursor at the time of the event. 153 * 154 * @see #getX() 155 * @serial the x coordinate 156 */ 157 private int x; 158 159 /** 160 * The Y coordinate of the mouse cursor at the time of the event. 161 * 162 * @see #getY() 163 * @serial the y coordinate 164 */ 165 private int y; 166 167 /** 168 * The screen position of that mouse event, X coordinate. 169 */ 170 private int absX; 171 172 /** 173 * The screen position of that mouse event, Y coordinate. 174 */ 175 private int absY; 176 177 /** 178 * The number of clicks that took place. For MOUSE_CLICKED, MOUSE_PRESSED, 179 * and MOUSE_RELEASED, this will be at least 1; otherwise it is 0. 180 * 181 * see #getClickCount() 182 * @serial the number of clicks 183 */ 184 private final int clickCount; 185 186 /** 187 * Indicates which mouse button changed state. Can only be one of 188 * {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or 189 * {@link #BUTTON3}. 190 * 191 * @see #getButton() 192 * @since 1.4 193 */ 194 private int button; 195 196 /** 197 * Whether or not this event should trigger a popup menu. 198 * 199 * @see PopupMenu 200 * @see #isPopupTrigger() 201 * @serial true if this is a popup trigger 202 */ 203 private final boolean popupTrigger; 204 205 /** 206 * Initializes a new instance of <code>MouseEvent</code> with the specified 207 * information. Note that an invalid id leads to unspecified results. 208 * 209 * @param source the source of the event 210 * @param id the event id 211 * @param when the timestamp of when the event occurred 212 * @param modifiers the modifier keys during the event, in old or new style 213 * @param x the X coordinate of the mouse point 214 * @param y the Y coordinate of the mouse point 215 * @param clickCount the number of mouse clicks for this event 216 * @param popupTrigger true if this event triggers a popup menu 217 * @param button the most recent mouse button to change state 218 * @throws IllegalArgumentException if source is null or button is invalid 219 * @since 1.4 220 */ 221 public MouseEvent(Component source, int id, long when, int modifiers, 222 int x, int y, int clickCount, boolean popupTrigger, 223 int button) 224 { 225 this(source, id, when, modifiers, x, y, 0, 0, clickCount, popupTrigger, 226 button); 227 } 228 229 /** 230 * Initializes a new instance of <code>MouseEvent</code> with the specified 231 * information. Note that an invalid id leads to unspecified results. 232 * 233 * @param source the source of the event 234 * @param id the event id 235 * @param when the timestamp of when the event occurred 236 * @param modifiers the modifier keys during the event, in old or new style 237 * @param x the X coordinate of the mouse point 238 * @param y the Y coordinate of the mouse point 239 * @param clickCount the number of mouse clicks for this event 240 * @param popupTrigger true if this event triggers a popup menu 241 * @throws IllegalArgumentException if source is null 242 */ 243 public MouseEvent(Component source, int id, long when, int modifiers, 244 int x, int y, int clickCount, boolean popupTrigger) 245 { 246 this(source, id, when, modifiers, x, y, clickCount, popupTrigger, 247 NOBUTTON); 248 } 249 250 /** 251 * Creates a new MouseEvent. This is like the other constructors and adds 252 * specific absolute coordinates. 253 * 254 * @param source the source of the event 255 * @param id the event id 256 * @param when the timestamp of when the event occurred 257 * @param modifiers the modifier keys during the event, in old or new style 258 * @param x the X coordinate of the mouse point 259 * @param y the Y coordinate of the mouse point 260 * @param absX the absolute X screen coordinate of this event 261 * @param absY the absolute Y screen coordinate of this event 262 * @param clickCount the number of mouse clicks for this event 263 * @param popupTrigger true if this event triggers a popup menu 264 * @param button the most recent mouse button to change state 265 * 266 * @throws IllegalArgumentException if source is null or button is invalid 267 * 268 * @since 1.6 269 */ 270 public MouseEvent(Component source, int id, long when, int modifiers, 271 int x, int y, int absX, int absY, int clickCount, 272 boolean popupTrigger, int button) 273 { 274 super(source, id, when, modifiers); 275 276 this.x = x; 277 this.y = y; 278 this.clickCount = clickCount; 279 this.popupTrigger = popupTrigger; 280 this.button = button; 281 if (button < NOBUTTON || button > BUTTON3) 282 throw new IllegalArgumentException(); 283 if ((modifiers & EventModifier.OLD_MASK) != 0) 284 { 285 if ((modifiers & BUTTON1_MASK) != 0) 286 this.button = BUTTON1; 287 else if ((modifiers & BUTTON2_MASK) != 0) 288 this.button = BUTTON2; 289 else if ((modifiers & BUTTON3_MASK) != 0) 290 this.button = BUTTON3; 291 } 292 // clear the mouse button modifier masks if this is a button 293 // release event. 294 if (id == MOUSE_RELEASED) 295 this.modifiersEx &= ~(BUTTON1_DOWN_MASK 296 | BUTTON2_DOWN_MASK 297 | BUTTON3_DOWN_MASK); 298 299 this.absX = absX; 300 this.absY = absY; 301 } 302 303 /** 304 * This method returns the X coordinate of the mouse position. This is 305 * relative to the source component. 306 * 307 * @return the x coordinate 308 */ 309 public int getX() 310 { 311 return x; 312 } 313 314 /** 315 * This method returns the Y coordinate of the mouse position. This is 316 * relative to the source component. 317 * 318 * @return the y coordinate 319 */ 320 public int getY() 321 { 322 return y; 323 } 324 325 /** 326 * @since 1.6 327 */ 328 public Point getLocationOnScreen() 329 { 330 return new Point(absX, absY); 331 } 332 333 /** 334 * @since 1.6 335 */ 336 public int getXOnScreen() 337 { 338 return absX; 339 } 340 341 /** 342 * @since 1.6 343 */ 344 public int getYOnScreen() 345 { 346 return absY; 347 } 348 349 /** 350 * This method returns a <code>Point</code> for the x,y position of 351 * the mouse pointer. This is relative to the source component. 352 * 353 * @return a <code>Point</code> for the event position 354 */ 355 public Point getPoint() 356 { 357 return new Point(x, y); 358 } 359 360 /** 361 * Translates the event coordinates by the specified x and y offsets. 362 * 363 * @param dx the value to add to the X coordinate of this event 364 * @param dy the value to add to the Y coordiante of this event 365 */ 366 public void translatePoint(int dx, int dy) 367 { 368 x += dx; 369 y += dy; 370 } 371 372 /** 373 * This method returns the number of mouse clicks associated with this 374 * event. 375 * 376 * @return the number of mouse clicks for this event 377 */ 378 public int getClickCount() 379 { 380 return clickCount; 381 } 382 383 /** 384 * Returns which button, if any, was the most recent to change state. This 385 * will be one of {@link #NOBUTTON}, {@link #BUTTON1}, {@link #BUTTON2}, or 386 * {@link #BUTTON3}. 387 * 388 * @return the button that changed state 389 * @since 1.4 390 */ 391 public int getButton() 392 { 393 return button; 394 } 395 396 /** 397 * This method tests whether or not the event is a popup menu trigger. This 398 * should be checked in both MousePressed and MouseReleased to be 399 * cross-platform compatible, as different systems have different popup 400 * triggers. 401 * 402 * @return true if the event is a popup menu trigger 403 */ 404 public boolean isPopupTrigger() 405 { 406 return popupTrigger; 407 } 408 409 /** 410 * Returns a string describing the modifiers, such as "Shift" or 411 * "Ctrl+Button1". 412 * 413 * XXX Sun claims this can be localized via the awt.properties file - how 414 * do we implement that? 415 * 416 * @param modifiers the old-style modifiers to convert to text 417 * @return a string representation of the modifiers in this bitmask 418 */ 419 public static String getMouseModifiersText(int modifiers) 420 { 421 modifiers &= EventModifier.OLD_MASK; 422 if ((modifiers & BUTTON2_MASK) != 0) 423 modifiers |= BUTTON2_DOWN_MASK; 424 if ((modifiers & BUTTON3_MASK) != 0) 425 modifiers |= BUTTON3_DOWN_MASK; 426 return getModifiersExText(EventModifier.extend(modifiers)); 427 } 428 429 /** 430 * Returns a string identifying this event. This is formatted as the field 431 * name of the id type, followed by the (x,y) point, the most recent button 432 * changed, modifiers (if any), extModifiers (if any), and clickCount. 433 * 434 * @return a string identifying this event 435 */ 436 public String paramString() 437 { 438 CPStringBuilder s = new CPStringBuilder(); 439 switch (id) 440 { 441 case MOUSE_CLICKED: 442 s.append("MOUSE_CLICKED,("); 443 break; 444 case MOUSE_PRESSED: 445 s.append("MOUSE_PRESSED,("); 446 break; 447 case MOUSE_RELEASED: 448 s.append("MOUSE_RELEASED,("); 449 break; 450 case MOUSE_MOVED: 451 s.append("MOUSE_MOVED,("); 452 break; 453 case MOUSE_ENTERED: 454 s.append("MOUSE_ENTERED,("); 455 break; 456 case MOUSE_EXITED: 457 s.append("MOUSE_EXITED,("); 458 break; 459 case MOUSE_DRAGGED: 460 s.append("MOUSE_DRAGGED,("); 461 break; 462 case MOUSE_WHEEL: 463 s.append("MOUSE_WHEEL,("); 464 break; 465 default: 466 s.append("unknown type,("); 467 } 468 s.append(x).append(',').append(y).append("),button=").append(button); 469 // FIXME: need a mauve test for this method 470 if (modifiersEx != 0) 471 s.append(",extModifiers=").append(getModifiersExText(modifiersEx)); 472 473 s.append(",clickCount=").append(clickCount); 474 s.append(",consumed=").append(consumed); 475 476 return s.toString(); 477 } 478 479 /** 480 * Reads in the object from a serial stream. 481 * 482 * @param s the stream to read from 483 * @throws IOException if deserialization fails 484 * @throws ClassNotFoundException if deserialization fails 485 * @serialData default, except that the modifiers are converted to new style 486 */ 487 private void readObject(ObjectInputStream s) 488 throws IOException, ClassNotFoundException 489 { 490 s.defaultReadObject(); 491 if ((modifiers & EventModifier.OLD_MASK) != 0) 492 { 493 if ((modifiers & BUTTON1_MASK) != 0) 494 button = BUTTON1; 495 else if ((modifiers & BUTTON2_MASK) != 0) 496 button = BUTTON2; 497 else if ((modifiers & BUTTON3_MASK) != 0) 498 button = BUTTON3; 499 modifiersEx = EventModifier.extend(modifiers) & EventModifier.NEW_MASK; 500 } 501 } 502 } // class MouseEvent