1 /*
2  * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.awt.event;
27 
28 import java.awt.Component;
29 import java.io.ObjectStreamException;
30 
31 import sun.awt.AWTAccessor;
32 import sun.awt.AppContext;
33 import sun.awt.SunToolkit;
34 
35 /**
36  * A low-level event which indicates that a Component has gained or lost the
37  * input focus. This low-level event is generated by a Component (such as a
38  * TextField). The event is passed to every {@code FocusListener} or
39  * {@code FocusAdapter} object which registered to receive such events
40  * using the Component's {@code addFocusListener} method.
41  * ({@code FocusAdapter} objects implement the {@code FocusListener}
42  * interface.) Each such listener object gets this {@code FocusEvent} when
43  * the event occurs.
44  * <p>
45  * There are two levels of focus events: permanent and temporary. Permanent
46  * focus change events occur when focus is directly moved from one Component to
47  * another, such as through a call to requestFocus() or as the user uses the
48  * TAB key to traverse Components. Temporary focus change events occur when
49  * focus is temporarily lost for a Component as the indirect result of another
50  * operation, such as Window deactivation or a Scrollbar drag. In this case,
51  * the original focus state will automatically be restored once that operation
52  * is finished, or, for the case of Window deactivation, when the Window is
53  * reactivated. Both permanent and temporary focus events are delivered using
54  * the FOCUS_GAINED and FOCUS_LOST event ids; the level may be distinguished in
55  * the event using the isTemporary() method.
56  * <p>
57  * Every {@code FocusEvent} records its cause - the reason why this event was
58  * generated. The cause is assigned during the focus event creation and may be
59  * retrieved by calling {@link #getCause}.
60  * <p>
61  * An unspecified behavior will be caused if the {@code id} parameter
62  * of any particular {@code FocusEvent} instance is not
63  * in the range from {@code FOCUS_FIRST} to {@code FOCUS_LAST}.
64  *
65  * @see FocusAdapter
66  * @see FocusListener
67  * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html">Tutorial: Writing a Focus Listener</a>
68  *
69  * @author Carl Quinn
70  * @author Amy Fowler
71  * @since 1.1
72  */
73 public class FocusEvent extends ComponentEvent {
74 
75     /**
76      * This enum represents the cause of a {@code FocusEvent}- the reason why it
77      * occurred. Possible reasons include mouse events, keyboard focus
78      * traversal, window activation.
79      * If no cause is provided then the reason is {@code UNKNOWN}.
80      *
81      * @since 9
82      */
83     public enum Cause {
84         /**
85          * The default value.
86          */
87         UNKNOWN,
88         /**
89          * An activating mouse event.
90          */
91         MOUSE_EVENT,
92         /**
93          * A focus traversal action with unspecified direction.
94          */
95         TRAVERSAL,
96         /**
97          * An up-cycle focus traversal action.
98          */
99         TRAVERSAL_UP,
100         /**
101          * A down-cycle focus traversal action.
102          */
103         TRAVERSAL_DOWN,
104         /**
105          * A forward focus traversal action.
106          */
107         TRAVERSAL_FORWARD,
108         /**
109          * A backward focus traversal action.
110          */
111         TRAVERSAL_BACKWARD,
112         /**
113          * Restoring focus after a focus request has been rejected.
114          */
115         ROLLBACK,
116         /**
117          * A system action causing an unexpected focus change.
118          */
119         UNEXPECTED,
120         /**
121          * An activation of a toplevel window.
122          */
123         ACTIVATION,
124         /**
125          * Clearing global focus owner.
126          */
127         CLEAR_GLOBAL_FOCUS_OWNER
128     }
129 
130     /**
131      * The first number in the range of ids used for focus events.
132      */
133     public static final int FOCUS_FIRST         = 1004;
134 
135     /**
136      * The last number in the range of ids used for focus events.
137      */
138     public static final int FOCUS_LAST          = 1005;
139 
140     /**
141      * This event indicates that the Component is now the focus owner.
142      */
143     public static final int FOCUS_GAINED = FOCUS_FIRST; //Event.GOT_FOCUS
144 
145     /**
146      * This event indicates that the Component is no longer the focus owner.
147      */
148     public static final int FOCUS_LOST = 1 + FOCUS_FIRST; //Event.LOST_FOCUS
149 
150     /**
151      * A focus event has the reason why this event was generated.
152      * The cause is set during the focus event creation.
153      *
154      * @serial
155      * @see #getCause()
156      * @since 9
157      */
158     private final Cause cause;
159 
160     /**
161      * A focus event can have two different levels, permanent and temporary.
162      * It will be set to true if some operation takes away the focus
163      * temporarily and intends on getting it back once the event is completed.
164      * Otherwise it will be set to false.
165      *
166      * @serial
167      * @see #isTemporary
168      */
169     boolean temporary;
170 
171     /**
172      * The other Component involved in this focus change. For a FOCUS_GAINED
173      * event, this is the Component that lost focus. For a FOCUS_LOST event,
174      * this is the Component that gained focus. If this focus change occurs
175      * with a native application, a Java application in a different VM, or with
176      * no other Component, then the opposite Component is null.
177      *
178      * @see #getOppositeComponent
179      * @since 1.4
180      */
181     transient Component opposite;
182 
183     /*
184      * JDK 1.1 serialVersionUID
185      */
186     private static final long serialVersionUID = 523753786457416396L;
187 
188     /**
189      * Constructs a {@code FocusEvent} object with the
190      * specified temporary state, opposite {@code Component} and the
191      * {@code Cause.UNKNOWN} cause.
192      * The opposite {@code Component} is the other
193      * {@code Component} involved in this focus change.
194      * For a {@code FOCUS_GAINED} event, this is the
195      * {@code Component} that lost focus. For a
196      * {@code FOCUS_LOST} event, this is the {@code Component}
197      * that gained focus. If this focus change occurs with a native
198      * application, with a Java application in a different VM,
199      * or with no other {@code Component}, then the opposite
200      * {@code Component} is {@code null}.
201      * <p> This method throws an
202      * {@code IllegalArgumentException} if {@code source}
203      * is {@code null}.
204      *
205      * @param source     The {@code Component} that originated the event
206      * @param id         An integer indicating the type of event.
207      *                     For information on allowable values, see
208      *                     the class description for {@link FocusEvent}
209      * @param temporary  Equals {@code true} if the focus change is temporary;
210      *                   {@code false} otherwise
211      * @param opposite   The other Component involved in the focus change,
212      *                   or {@code null}
213      * @throws IllegalArgumentException if {@code source} equals {@code null}
214      * @see #getSource()
215      * @see #getID()
216      * @see #isTemporary()
217      * @see #getOppositeComponent()
218      * @see Cause#UNKNOWN
219      * @since 1.4
220      */
FocusEvent(Component source, int id, boolean temporary, Component opposite)221     public FocusEvent(Component source, int id, boolean temporary,
222                       Component opposite) {
223         this(source, id, temporary, opposite, Cause.UNKNOWN);
224     }
225 
226     /**
227      * Constructs a {@code FocusEvent} object with the
228      * specified temporary state, opposite {@code Component} and the cause.
229      * The opposite {@code Component} is the other
230      * {@code Component} involved in this focus change.
231      * For a {@code FOCUS_GAINED} event, this is the
232      * {@code Component} that lost focus. For a
233      * {@code FOCUS_LOST} event, this is the {@code Component}
234      * that gained focus. If this focus change occurs with a native
235      * application, with a Java application in a different VM,
236      * or with no other {@code Component}, then the opposite
237      * {@code Component} is {@code null}.
238      * <p> This method throws an
239      * {@code IllegalArgumentException} if {@code source} or {@code cause}
240      * is {@code null}.
241      *
242      * @param source    The {@code Component} that originated the event
243      * @param id        An integer indicating the type of event.
244      *                  For information on allowable values, see
245      *                  the class description for {@link FocusEvent}
246      * @param temporary Equals {@code true} if the focus change is temporary;
247      *                  {@code false} otherwise
248      * @param opposite  The other Component involved in the focus change,
249      *                  or {@code null}
250      * @param cause     The focus event cause.
251      * @throws IllegalArgumentException if {@code source} equals {@code null}
252      *                                  or if {@code cause} equals {@code null}
253      * @see #getSource()
254      * @see #getID()
255      * @see #isTemporary()
256      * @see #getOppositeComponent()
257      * @see Cause
258      * @since 9
259      */
FocusEvent(Component source, int id, boolean temporary, Component opposite, Cause cause)260     public FocusEvent(Component source, int id, boolean temporary,
261                       Component opposite, Cause cause) {
262         super(source, id);
263         if (cause == null) {
264             throw new IllegalArgumentException("null cause");
265         }
266         this.temporary = temporary;
267         this.opposite = opposite;
268         this.cause = cause;
269     }
270 
271     /**
272      * Constructs a {@code FocusEvent} object and identifies
273      * whether or not the change is temporary.
274      * <p> This method throws an
275      * {@code IllegalArgumentException} if {@code source}
276      * is {@code null}.
277      *
278      * @param source    The {@code Component} that originated the event
279      * @param id        An integer indicating the type of event.
280      *                     For information on allowable values, see
281      *                     the class description for {@link FocusEvent}
282      * @param temporary Equals {@code true} if the focus change is temporary;
283      *                  {@code false} otherwise
284      * @throws IllegalArgumentException if {@code source} equals {@code null}
285      * @see #getSource()
286      * @see #getID()
287      * @see #isTemporary()
288      */
FocusEvent(Component source, int id, boolean temporary)289     public FocusEvent(Component source, int id, boolean temporary) {
290         this(source, id, temporary, null);
291     }
292 
293     /**
294      * Constructs a {@code FocusEvent} object and identifies it
295      * as a permanent change in focus.
296      * <p> This method throws an
297      * {@code IllegalArgumentException} if {@code source}
298      * is {@code null}.
299      *
300      * @param source    The {@code Component} that originated the event
301      * @param id        An integer indicating the type of event.
302      *                     For information on allowable values, see
303      *                     the class description for {@link FocusEvent}
304      * @throws IllegalArgumentException if {@code source} equals {@code null}
305      * @see #getSource()
306      * @see #getID()
307      */
FocusEvent(Component source, int id)308     public FocusEvent(Component source, int id) {
309         this(source, id, false);
310     }
311 
312     /**
313      * Identifies the focus change event as temporary or permanent.
314      *
315      * @return {@code true} if the focus change is temporary;
316      *         {@code false} otherwise
317      */
isTemporary()318     public boolean isTemporary() {
319         return temporary;
320     }
321 
322     /**
323      * Returns the other Component involved in this focus change. For a
324      * FOCUS_GAINED event, this is the Component that lost focus. For a
325      * FOCUS_LOST event, this is the Component that gained focus. If this
326      * focus change occurs with a native application, with a Java application
327      * in a different VM or context, or with no other Component, then null is
328      * returned.
329      *
330      * @return the other Component involved in the focus change, or null
331      * @since 1.4
332      */
getOppositeComponent()333     public Component getOppositeComponent() {
334         if (opposite == null) {
335             return null;
336         }
337 
338         return (SunToolkit.targetToAppContext(opposite) ==
339                 AppContext.getAppContext())
340                 ? opposite
341                 : null;
342     }
343 
344     /**
345      * Returns a parameter string identifying this event.
346      * This method is useful for event-logging and for debugging.
347      *
348      * @return a string identifying the event and its attributes
349      */
paramString()350     public String paramString() {
351         String typeStr;
352         switch(id) {
353             case FOCUS_GAINED:
354                 typeStr = "FOCUS_GAINED";
355                 break;
356             case FOCUS_LOST:
357                 typeStr = "FOCUS_LOST";
358                 break;
359             default:
360                 typeStr = "unknown type";
361         }
362         return typeStr + (temporary ? ",temporary" : ",permanent") +
363                 ",opposite=" + getOppositeComponent() + ",cause=" + getCause();
364     }
365 
366     /**
367      * Returns the event cause.
368      *
369      * @return one of {@link Cause} values
370      * @since 9
371      */
getCause()372     public final Cause getCause() {
373         return cause;
374     }
375 
376     /**
377      * Checks if this deserialized {@code FocusEvent} instance is compatible
378      * with the current specification which implies that focus event has
379      * non-null {@code cause} value. If the check fails a new {@code FocusEvent}
380      * instance is returned which {@code cause} field equals to
381      * {@link Cause#UNKNOWN} and its other fields have the same values as in
382      * this {@code FocusEvent} instance.
383      *
384      * @return a newly created object from deserialized data
385      * @throws ObjectStreamException if a new object replacing this object could
386      *         not be created
387      * @serial
388      * @see #cause
389      * @since 9
390      */
391     @SuppressWarnings("serial")
readResolve()392     Object readResolve() throws ObjectStreamException {
393         if (cause != null) {
394             return this;
395         }
396         FocusEvent focusEvent = new FocusEvent(new Component(){}, getID(),
397                 isTemporary(), getOppositeComponent());
398         focusEvent.setSource(null);
399         focusEvent.consumed = consumed;
400 
401         AWTAccessor.AWTEventAccessor accessor =
402                 AWTAccessor.getAWTEventAccessor();
403         accessor.setBData(focusEvent, accessor.getBData(this));
404         return focusEvent;
405     }
406 
407 
408 }