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