1
1
/*
2
- * Copyright (c) 2013, 2018 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2013, 2020 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
25
25
26
26
package test .com .sun .javafx .scene .control .infrastructure ;
27
27
28
+ import java .util .Arrays ;
29
+ import java .util .List ;
30
+
28
31
import javafx .event .Event ;
29
32
import javafx .event .EventTarget ;
30
33
import javafx .event .EventType ;
31
34
import javafx .geometry .BoundingBox ;
32
35
import javafx .geometry .Bounds ;
36
+ import javafx .geometry .Point2D ;
33
37
import javafx .scene .Node ;
34
38
import javafx .scene .Scene ;
35
39
import javafx .scene .input .MouseButton ;
36
40
import javafx .scene .input .MouseEvent ;
37
41
import javafx .scene .input .PickResult ;
38
42
import javafx .stage .Window ;
39
43
40
- import java .util .Arrays ;
41
- import java .util .List ;
42
-
44
+ /**
45
+ * Helper to fire MouseEvents onto a EventTarget which is either Node or Scene.
46
+ * There are methods to configure the event by eventType, clickCount, location (delta from default),
47
+ * mouseButton and keyModifiers.
48
+ * <p>
49
+ * The default local coordinates are the center of the target.
50
+ */
43
51
public final class MouseEventFirer {
44
52
private final EventTarget target ;
45
53
46
54
private final Scene scene ;
47
55
private final Bounds targetBounds ;
48
56
private StageLoader sl ;
49
57
58
+ private boolean alternative ;
59
+
50
60
public MouseEventFirer (EventTarget target ) {
51
61
this .target = target ;
52
62
@@ -73,6 +83,19 @@ public MouseEventFirer(EventTarget target) {
73
83
}
74
84
}
75
85
86
+ /**
87
+ * Instantiates a MouseEventFirer on the given node.
88
+ * <p>
89
+ * Note: this was added as hot-fix for JDK-8253769.
90
+ *
91
+ * @param target the node to fire on
92
+ * @param alternative uses alternative creation path for mouseEvent if true.
93
+ */
94
+ public MouseEventFirer (Node target , boolean alternative ) {
95
+ this (target );
96
+ this .alternative = alternative ;
97
+ }
98
+
76
99
public void dispose () {
77
100
if (sl != null ) {
78
101
sl .dispose ();
@@ -158,6 +181,15 @@ public void fireMouseEvent(EventType<MouseEvent> evtType, MouseButton button, do
158
181
}
159
182
160
183
private void fireMouseEvent (EventType <MouseEvent > evtType , MouseButton button , int clickCount , double deltaX , double deltaY , KeyModifier ... modifiers ) {
184
+ if (alternative ) {
185
+ fireMouseEventAlternative (evtType , button , clickCount , deltaX , deltaY , modifiers );
186
+ return ;
187
+ }
188
+ // TBD: JDK-8253769
189
+ // the mouseEvent created here seems to be valid (in regard to coordinate transformations
190
+ // of local/scene/screen) only if the target is glued to the upper leading edge of the scene
191
+ // and zero deltaX/Y!
192
+
161
193
// calculate bounds
162
194
final Window window = scene .getWindow ();
163
195
@@ -221,6 +253,55 @@ private void fireMouseEvent(EventType<MouseEvent> evtType, MouseButton button, i
221
253
Event .fireEvent (target , evt );
222
254
}
223
255
256
+ /**
257
+ * Fires a mouseEvent with the given configuration options onto the target.
258
+ * Hot-fix for JDK-8253769.
259
+ * The mouseEvent is created such that coordinate transformation constraints seem to be respected.
260
+ */
261
+ private void fireMouseEventAlternative (EventType <MouseEvent > evtType , MouseButton button , int clickCount , double deltaX , double deltaY , KeyModifier ... modifiers ) {
262
+
263
+ // width / height of target node
264
+ final double w = targetBounds .getWidth ();
265
+ final double h = targetBounds .getHeight ();
266
+
267
+ // x / y click position is centered
268
+ final double x = w / 2.0 + deltaX ;
269
+ final double y = h / 2.0 + deltaY ;
270
+
271
+ Node node = (Node ) target ;
272
+
273
+ Point2D localP = new Point2D (x , y );
274
+ Point2D sceneP = node .localToScene (localP );
275
+ Point2D screenP = node .localToScreen (localP );
276
+
277
+ final List <KeyModifier > ml = Arrays .asList (modifiers );
278
+
279
+ MouseEvent evt = new MouseEvent (
280
+ target , // target of this firer
281
+ null , // default source (don't care, event dispatch will take over)
282
+ evtType ,
283
+ sceneP .getX (), sceneP .getY (), // can use scene coordinates because source is null
284
+ screenP .getX (), screenP .getY (),
285
+ button ,
286
+ clickCount ,
287
+ ml .contains (KeyModifier .SHIFT ), // shiftDown
288
+ ml .contains (KeyModifier .CTRL ), // ctrlDown
289
+ ml .contains (KeyModifier .ALT ), // altDown
290
+ ml .contains (KeyModifier .META ), // metaData
291
+ button == MouseButton .PRIMARY , // primary button
292
+ button == MouseButton .MIDDLE , // middle button
293
+ button == MouseButton .SECONDARY , // secondary button
294
+ button == MouseButton .BACK , // back button
295
+ button == MouseButton .FORWARD , // forward button
296
+ false , // synthesized
297
+ button == MouseButton .SECONDARY , // is popup trigger
298
+ true , // still since pick
299
+ null // default pick (don't care, event constructor will take over)
300
+ );
301
+
302
+ Event .fireEvent (target , evt );
303
+ }
304
+
224
305
// public void fireMouseEvent(Scene target, EventType<MouseEvent> evtType, MouseButton button, int clickCount, double deltaX, double deltaY, KeyModifier... modifiers) {
225
306
// List<KeyModifier> ml = Arrays.asList(modifiers);
226
307
//
0 commit comments