]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/events/adapter/AWTMouseEventAdapter.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / events / adapter / AWTMouseEventAdapter.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 /*
13  *
14  * @author Toni Kalajainen
15  */
16 package org.simantics.scenegraph.g2d.events.adapter;
17
18 import java.awt.Component;
19 import java.awt.dnd.DnDConstants;
20 import java.awt.dnd.DragGestureEvent;
21 import java.awt.dnd.DragGestureListener;
22 import java.awt.dnd.DragSource;
23 import java.awt.event.InputEvent;
24 import java.awt.event.MouseEvent;
25 import java.awt.event.MouseListener;
26 import java.awt.event.MouseMotionListener;
27 import java.awt.event.MouseWheelEvent;
28 import java.awt.event.MouseWheelListener;
29 import java.awt.geom.Point2D;
30 import java.util.function.UnaryOperator;
31
32 import org.simantics.scenegraph.g2d.events.EventDebugPolicy;
33 import org.simantics.scenegraph.g2d.events.IEventHandler;
34 import org.simantics.scenegraph.g2d.events.IEventQueue;
35 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;
36 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
37 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;
38 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
39 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;
40 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
41 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
42 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;
43
44
45 /**
46  * Adapts AWT mouse events into G2D events.
47  * 
48  * Sends adapted events to IEventHandler
49  */
50 public class AWTMouseEventAdapter extends AbstractEventAdapter implements MouseListener, MouseMotionListener, MouseWheelListener {
51
52     private final boolean   DEBUG                  = EventDebugPolicy.AWT_MOUSE_EVENT_ADAPTION;
53
54     private final boolean   IGNORE_CONSUMED_EVENTS = false;
55
56     /** Mouse id of the default mouse */
57     public static final int MOUSE_ID = 0;
58
59     private final long [] pressTime = new long[5];
60
61     int buttonStatus = 0;
62
63     /**
64      * create new adapter
65      * @param sender the sender field in the events
66      * @param delegator the target of the adapted events
67      */
68     public AWTMouseEventAdapter(Object sender, IEventHandler delegator) {
69         super(sender, delegator);
70     }
71
72     /**
73      * create new adapter
74      * @param sender the sender field in the events
75      * @param queue
76      */
77     public AWTMouseEventAdapter(Object sender, IEventQueue queue) {
78         super(sender, queue);
79     }
80
81     public static Point2D getControlPosition(MouseEvent e)
82     {
83         return new Point2D.Double(e.getX(), e.getY());
84     }
85
86     public static Point2D getScreenPosition(MouseEvent e)
87     {
88         return e.getLocationOnScreen();
89     }
90
91     public static int getStateMask(MouseEvent e) {
92         int modifiers = e.getModifiersEx();
93         int stateMask = 0;
94         if((modifiers & InputEvent.CTRL_DOWN_MASK) != 0)
95             stateMask |= org.simantics.scenegraph.g2d.events.MouseEvent.CTRL_MASK;
96         if((modifiers & InputEvent.ALT_DOWN_MASK) != 0)
97             stateMask |= org.simantics.scenegraph.g2d.events.MouseEvent.ALT_MASK;
98         if((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0)
99             stateMask |= org.simantics.scenegraph.g2d.events.MouseEvent.ALT_GRAPH_MASK;
100         if((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0)
101             stateMask |= org.simantics.scenegraph.g2d.events.MouseEvent.SHIFT_MASK;
102         return stateMask;
103     }
104
105     public static int getMouseButton(MouseEvent e)
106     {
107         int awtMouseButton = e.getButton();
108         if (awtMouseButton == MouseEvent.BUTTON1)
109             return org.simantics.scenegraph.g2d.events.MouseEvent.LEFT_BUTTON;
110         if (awtMouseButton == MouseEvent.BUTTON2)
111             return org.simantics.scenegraph.g2d.events.MouseEvent.MIDDLE_BUTTON;
112         if (awtMouseButton == MouseEvent.BUTTON3)
113             return org.simantics.scenegraph.g2d.events.MouseEvent.RIGHT_BUTTON;
114         return awtMouseButton;
115     }
116
117     /**
118      * Converts AWT {@link MouseEvent#getModifiersEx()} mouse button status to
119      * G2D mouse button status. Only supports three buttons while AWT supports
120      * plenty more.
121      * 
122      * @param e
123      * @return
124      */
125     public static int getButtonStatus(MouseEvent e) {
126         int modex = e.getModifiersEx();
127         int status = 0;
128         status |= (modex & MouseEvent.BUTTON1_DOWN_MASK) != 0 ? org.simantics.scenegraph.g2d.events.MouseEvent.LEFT_MASK : 0;
129         status |= (modex & MouseEvent.BUTTON2_DOWN_MASK) != 0 ? org.simantics.scenegraph.g2d.events.MouseEvent.MIDDLE_MASK : 0;
130         status |= (modex & MouseEvent.BUTTON3_DOWN_MASK) != 0 ? org.simantics.scenegraph.g2d.events.MouseEvent.RIGHT_MASK : 0;
131         return status;
132     }
133
134     @Override
135     public void mouseEntered(MouseEvent e) {
136         if (IGNORE_CONSUMED_EVENTS) {
137             if (e.isConsumed()) {
138                 if (DEBUG)
139                     System.out.println("AWT mouse entered but already consumed: " + e);
140                 return;
141             }
142         }
143         if (DEBUG)
144             System.out.println("AWT mouse entered: " + e);
145         buttonStatus = getButtonStatus(e);
146         MouseEnterEvent me = new MouseEnterEvent(sender, e.getWhen(), MOUSE_ID, buttonStatus, getStateMask(e), getControlPosition(e), getScreenPosition(e));
147         handleEvent(me);
148     }
149
150     @Override
151     public void mouseExited(MouseEvent e) {
152         if (IGNORE_CONSUMED_EVENTS) {
153             if (e.isConsumed()) {
154                 if (DEBUG)
155                     System.out.println("AWT mouse exited but already consumed: " + e);
156                 return;
157             }
158         }
159         if (DEBUG)
160             System.out.println("AWT mouse exited: " + e);
161
162         MouseExitEvent me = new MouseExitEvent(sender, e.getWhen(), MOUSE_ID, buttonStatus, getStateMask(e), getControlPosition(e), getScreenPosition(e));
163         handleEvent(me);
164     }
165
166     @Override
167     public void mousePressed(MouseEvent e) {
168         if (IGNORE_CONSUMED_EVENTS) {
169             if (e.isConsumed()) {
170                 if (DEBUG)
171                     System.out.println("AWT mouse pressed but already consumed: " + e);
172                 return;
173             }
174         }
175         if (DEBUG)
176             System.out.println("AWT mouse pressed: " + e);
177
178         int mouseButton = getMouseButton(e);
179         if (mouseButton == MouseEvent.NOBUTTON) {
180                 // This is strange, seems to happen on Linux constantly when pressing buttons rapidly.
181                 //System.out.println("NO BUTTON EVENT: " + e);
182                 return;
183         }
184         
185         if (mouseButton<=pressTime.length) pressTime[mouseButton-1] = e.getWhen();
186         buttonStatus |= 1 << (mouseButton-1);
187
188         handleEvent(new MouseButtonPressedEvent(sender, e.getWhen(), MOUSE_ID,
189                 buttonStatus, getStateMask(e), mouseButton, getControlPosition(e), getScreenPosition(e)));
190         if (e.getClickCount() == 2) {
191             handleEvent(new MouseDoubleClickedEvent(sender, e.getWhen(),
192                     MOUSE_ID, buttonStatus, getStateMask(e), mouseButton, getControlPosition(e), getScreenPosition(e)));
193         }
194     }
195
196     @Override
197     public void mouseReleased(MouseEvent e) {
198         if (IGNORE_CONSUMED_EVENTS) {
199             if (e.isConsumed()) {
200                 if (DEBUG)
201                     System.out.println("AWT mouse released but already consumed: " + e);
202                 return;
203             }
204         }
205         if (DEBUG)
206             System.out.println("AWT mouse released: " + e);
207
208         int mouseButton = getMouseButton(e);
209         if (mouseButton == MouseEvent.NOBUTTON) {
210             // This is strange, seems to happen on Linux constantly when pressing buttons rapidly.
211             //System.out.println("NO BUTTON EVENT: " + e);
212             return;
213         }
214
215         long holdTime = Long.MAX_VALUE;
216         if (mouseButton<=pressTime.length)
217             holdTime = e.getWhen() - pressTime[mouseButton-1];
218
219         int stateMask = getStateMask(e);
220
221         // This works around the problem of AWT putting the ALT_DOWN_MASK in the
222         // mouse event extended modifiers when button 2 is pressed.
223         if (mouseButton == org.simantics.scenegraph.g2d.events.MouseEvent.MIDDLE_BUTTON) {
224             stateMask &= ~(org.simantics.scenegraph.g2d.events.MouseEvent.ALT_MASK);
225         }
226
227         buttonStatus &=~ (1<<(mouseButton-1));
228         MouseButtonReleasedEvent me = new MouseButtonReleasedEvent(sender, e.getWhen(), MOUSE_ID, buttonStatus, stateMask, mouseButton, holdTime, getControlPosition(e), getScreenPosition(e));
229         handleEvent(me);
230     }
231
232     @Override
233     public void mouseDragged(MouseEvent e) {
234         if (IGNORE_CONSUMED_EVENTS) {
235             if (e.isConsumed()) {
236                 if (DEBUG)
237                     System.out.println("AWT mouse dragged but already consumed: " + e);
238                 return;
239             }
240         }
241         if (DEBUG)
242             System.out.println("AWT mouse dragged: " + e);
243         MouseMovedEvent me = new MouseMovedEvent(sender, e.getWhen(), MOUSE_ID, buttonStatus, getStateMask(e), getControlPosition(e), getScreenPosition(e));
244         handleEvent(me);
245     }
246
247     @Override
248     public void mouseMoved(MouseEvent e) {
249         if (IGNORE_CONSUMED_EVENTS) {
250             if (e.isConsumed()) {
251                 if (DEBUG)
252                     System.out.println("AWT mouse moved but already consumed: " + e);
253                 return;
254             }
255         }
256         if (DEBUG)
257             System.out.println("AWT mouse moved: " + e);
258         MouseMovedEvent me = new MouseMovedEvent(sender, e.getWhen(), MOUSE_ID, buttonStatus, getStateMask(e), getControlPosition(e), getScreenPosition(e));
259         handleEvent(me);
260     }
261
262     @Override
263     public void mouseWheelMoved(MouseWheelEvent e) {
264         if (IGNORE_CONSUMED_EVENTS) {
265             if (e.isConsumed()) {
266                 if (DEBUG)
267                     System.out.println("AWT mouse wheel moved but already consumed: " + e);
268                 return;
269             }
270         }
271         if (DEBUG)
272             System.out.println("AWT mouse wheel moved: " + e);
273         int wheelRotation = 0;
274         if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
275             wheelRotation = -e.getUnitsToScroll();
276         } else {
277             wheelRotation = -e.getWheelRotation();
278         }
279         handleEvent(new MouseWheelMovedEvent(
280                 sender, e.getWhen(), MOUSE_ID, buttonStatus, getStateMask(e), getControlPosition(e), getScreenPosition(e),
281                 e.getScrollType(), e.getScrollAmount(), wheelRotation
282         ));
283
284     }
285
286     @Override
287     public void mouseClicked(MouseEvent e) {
288         if (IGNORE_CONSUMED_EVENTS) {
289             if (e.isConsumed()) {
290                 if (DEBUG)
291                     System.out.println("AWT mouse clicked but already consumed: " + e);
292                 return;
293             }
294         }
295         if (DEBUG)
296             System.out.println("AWT mouse clicked: " + e);
297     }
298
299     public void initDragGestureListener(Component rootPane, UnaryOperator<Point2D> controlToCanvas) {
300         final DragSource ds = new DragSource();
301         DragGestureListener dgl = new DragGestureListener() {
302             @Override
303             public void dragGestureRecognized(DragGestureEvent dge) {
304                 InputEvent ie = dge.getTriggerEvent();
305                 if (ie instanceof java.awt.event.MouseEvent) {
306                     java.awt.event.MouseEvent e = (java.awt.event.MouseEvent) ie;
307                     Point2D controlPos = getControlPosition(e);
308                     Point2D canvasPos = controlToCanvas.apply(controlPos);
309
310                     MouseDragBegin event = new MouseDragBegin(this,
311                             e.getWhen(), 0,
312                             getButtonStatus(e),
313                             getStateMask(e),
314                             getMouseButton(e),
315                             canvasPos,
316                             controlPos,
317                             controlPos,
318                             getScreenPosition(e));
319
320                     syncHandleEvent(event);
321
322                     if (event.transferable != null) {
323                         ds.startDrag(dge, null, event.transferable, null);
324                     }
325                 }
326             }
327         };
328         ds.createDefaultDragGestureRecognizer(
329                 rootPane,
330                 DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK,
331                 dgl);
332     }
333 }