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