25
25
26
26
package javafx .event ;
27
27
28
- import java .util .EventObject ;
29
-
30
28
import com .sun .javafx .event .EventUtil ;
29
+ import com .sun .javafx .event .UnconsumedEventHandler ;
30
+ import java .util .ArrayList ;
31
+ import java .util .EventObject ;
31
32
import java .io .IOException ;
33
+ import java .io .Serial ;
34
+ import java .util .List ;
32
35
import javafx .beans .NamedArg ;
33
36
34
37
// PENDING_DOC_REVIEW
43
46
*/
44
47
public class Event extends EventObject implements Cloneable {
45
48
46
- private static final long serialVersionUID = 20121107L ;
49
+ static {
50
+ EventUtil .setAccessor (new EventUtil .Accessor () {
51
+ @ Override
52
+ public List <UnconsumedEventHandler > getUnconsumedEventHandlers (Event event ) {
53
+ return event .unconsumedEventHandlers ;
54
+ }
55
+
56
+ @ Override
57
+ public void markDeliveryCompleted (Event event ) {
58
+ event .completed = true ;
59
+ }
60
+ });
61
+ }
62
+
63
+ @ Serial
64
+ private static final long serialVersionUID = 20241110L ;
65
+
47
66
/**
48
67
* The constant which represents an unknown event source / target.
49
68
*/
@@ -65,11 +84,23 @@ public class Event extends EventObject implements Cloneable {
65
84
*/
66
85
protected transient EventTarget target ;
67
86
87
+ /**
88
+ * The list of handlers that have expressed their interest in handling the event
89
+ * if it is still unconsumed at the end of the bubble phase of event delivery.
90
+ */
91
+ private transient List <UnconsumedEventHandler > unconsumedEventHandlers ;
92
+
68
93
/**
69
94
* Whether this event has been consumed by any filter or handler.
70
95
*/
71
96
protected boolean consumed ;
72
97
98
+ /**
99
+ * Indicates whether this event has completed both delivery phases and can no
100
+ * longer accept registrations of unconsumed event handlers.
101
+ */
102
+ private boolean completed ;
103
+
73
104
/**
74
105
* Construct a new {@code Event} with the specified event type. The source
75
106
* and target of the event is set to {@code NULL_SOURCE_TARGET}.
@@ -155,6 +186,44 @@ public void consume() {
155
186
consumed = true ;
156
187
}
157
188
189
+ /**
190
+ * Specifies an event handler that will handle this event if it is still unconsumed after both phases
191
+ * of event delivery have completed. The unconsumed event handlers are invoked in the order they were
192
+ * registered. As soon as an event handler consumes the event, further propagation is stopped.
193
+ * <p>
194
+ * This method can only be called from an event filter or event handler during event delivery; any
195
+ * attempt to call it after event delivery is complete will fail with {@link IllegalStateException}.
196
+ *
197
+ * @param handler the event handler
198
+ * @param <E> the type of the event
199
+ * @throws IllegalStateException when event delivery has already been completed
200
+ * @since 24
201
+ */
202
+ public final <E extends Event > void ifUnconsumed (EventHandler <E > handler ) {
203
+ if (completed ) {
204
+ throw new IllegalStateException ("Event delivery is not in progress" );
205
+ }
206
+
207
+ if (unconsumedEventHandlers == null ) {
208
+ unconsumedEventHandlers = new ArrayList <>(2 ); // most of the time we only expect a single handler
209
+ }
210
+
211
+ @ SuppressWarnings ("unchecked" )
212
+ EventHandler <Event > untypedHandler = (EventHandler <Event >)handler ;
213
+ unconsumedEventHandlers .add (new UnconsumedEventHandler (this , untypedHandler ));
214
+ }
215
+
216
+ /**
217
+ * Discards all event handlers that were added with {@link #ifUnconsumed(EventHandler)}.
218
+ *
219
+ * @since 24
220
+ */
221
+ public final void discardUnconsumedEventHandlers () {
222
+ if (!completed && unconsumedEventHandlers != null ) {
223
+ unconsumedEventHandlers .clear ();
224
+ }
225
+ }
226
+
158
227
/**
159
228
* Creates and returns a copy of this {@code Event}.
160
229
* @return a new instance of {@code Event} with all values copied from
0 commit comments