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 }