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