1 /*
   2  * Copyright (c) 1996, 2015, 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="http://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     private final Cause cause;
 151 
 152     /**
 153      * A focus event can have two different levels, permanent and temporary.
 154      * It will be set to true if some operation takes away the focus
 155      * temporarily and intends on getting it back once the event is completed.
 156      * Otherwise it will be set to false.
 157      *
 158      * @serial
 159      * @see #isTemporary
 160      */
 161     boolean temporary;
 162 
 163     /**
 164      * The other Component involved in this focus change. For a FOCUS_GAINED
 165      * event, this is the Component that lost focus. For a FOCUS_LOST event,
 166      * this is the Component that gained focus. If this focus change occurs
 167      * with a native application, a Java application in a different VM, or with
 168      * no other Component, then the opposite Component is null.
 169      *
 170      * @see #getOppositeComponent
 171      * @since 1.4
 172      */
 173     transient Component opposite;
 174 
 175     /*
 176      * JDK 1.1 serialVersionUID
 177      */
 178     private static final long serialVersionUID = 523753786457416396L;
 179 
 180     /**
 181      * Constructs a {@code FocusEvent} object with the
 182      * specified temporary state, opposite {@code Component} and the
 183      * {@code Cause.UNKNOWN} cause.
 184      * The opposite {@code Component} is the other
 185      * {@code Component} involved in this focus change.
 186      * For a {@code FOCUS_GAINED} event, this is the
 187      * {@code Component} that lost focus. For a
 188      * {@code FOCUS_LOST} event, this is the {@code Component}
 189      * that gained focus. If this focus change occurs with a native
 190      * application, with a Java application in a different VM,
 191      * or with no other {@code Component}, then the opposite
 192      * {@code Component} is {@code null}.
 193      * <p> This method throws an
 194      * {@code IllegalArgumentException} if {@code source}
 195      * is {@code null}.
 196      *
 197      * @param source     The {@code Component} that originated the event
 198      * @param id         An integer indicating the type of event.
 199      *                     For information on allowable values, see
 200      *                     the class description for {@link FocusEvent}
 201      * @param temporary  Equals {@code true} if the focus change is temporary;
 202      *                   {@code false} otherwise
 203      * @param opposite   The other Component involved in the focus change,
 204      *                   or {@code null}
 205      * @throws IllegalArgumentException if {@code source} equals {@code null}
 206      * @see #getSource()
 207      * @see #getID()
 208      * @see #isTemporary()
 209      * @see #getOppositeComponent()
 210      * @see Cause#UNKNOWN
 211      * @since 1.4
 212      */
 213     public FocusEvent(Component source, int id, boolean temporary,
 214                       Component opposite) {
 215         this(source, id, temporary, opposite, Cause.UNKNOWN);
 216     }
 217 
 218     /**
 219      * Constructs a {@code FocusEvent} object with the
 220      * specified temporary state, opposite {@code Component} and the cause.
 221      * The opposite {@code Component} is the other
 222      * {@code Component} involved in this focus change.
 223      * For a {@code FOCUS_GAINED} event, this is the
 224      * {@code Component} that lost focus. For a
 225      * {@code FOCUS_LOST} event, this is the {@code Component}
 226      * that gained focus. If this focus change occurs with a native
 227      * application, with a Java application in a different VM,
 228      * or with no other {@code Component}, then the opposite
 229      * {@code Component} is {@code null}.
 230      * <p> This method throws an
 231      * {@code IllegalArgumentException} if {@code source} or {@code cause}
 232      * is {@code null}.
 233      *
 234      * @param source    The {@code Component} that originated the event
 235      * @param id        An integer indicating the type of event.
 236      *                  For information on allowable values, see
 237      *                  the class description for {@link FocusEvent}
 238      * @param temporary Equals {@code true} if the focus change is temporary;
 239      *                  {@code false} otherwise
 240      * @param opposite  The other Component involved in the focus change,
 241      *                  or {@code null}
 242      * @param cause     The focus event cause.
 243      * @throws IllegalArgumentException if {@code source} equals {@code null}
 244      *                                  or if {@code cause} equals {@code null}
 245      * @see #getSource()
 246      * @see #getID()
 247      * @see #isTemporary()
 248      * @see #getOppositeComponent()
 249      * @see Cause
 250      * @since 9
 251      */
 252     public FocusEvent(Component source, int id, boolean temporary,
 253                       Component opposite, Cause cause) {
 254         super(source, id);
 255         if (cause == null) {
 256             throw new IllegalArgumentException("null cause");
 257         }
 258         this.temporary = temporary;
 259         this.opposite = opposite;
 260         this.cause = cause;
 261     }
 262 
 263     /**
 264      * Constructs a {@code FocusEvent} object and identifies
 265      * whether or not the change is temporary.
 266      * <p> This method throws an
 267      * {@code IllegalArgumentException} if {@code source}
 268      * is {@code null}.
 269      *
 270      * @param source    The {@code Component} that originated the event
 271      * @param id        An integer indicating the type of event.
 272      *                     For information on allowable values, see
 273      *                     the class description for {@link FocusEvent}
 274      * @param temporary Equals {@code true} if the focus change is temporary;
 275      *                  {@code false} otherwise
 276      * @throws IllegalArgumentException if {@code source} equals {@code null}
 277      * @see #getSource()
 278      * @see #getID()
 279      * @see #isTemporary()
 280      */
 281     public FocusEvent(Component source, int id, boolean temporary) {
 282         this(source, id, temporary, null);
 283     }
 284 
 285     /**
 286      * Constructs a {@code FocusEvent} object and identifies it
 287      * as a permanent change in focus.
 288      * <p> This method throws an
 289      * {@code IllegalArgumentException} if {@code source}
 290      * is {@code null}.
 291      *
 292      * @param source    The {@code Component} that originated the event
 293      * @param id        An integer indicating the type of event.
 294      *                     For information on allowable values, see
 295      *                     the class description for {@link FocusEvent}
 296      * @throws IllegalArgumentException if {@code source} equals {@code null}
 297      * @see #getSource()
 298      * @see #getID()
 299      */
 300     public FocusEvent(Component source, int id) {
 301         this(source, id, false);
 302     }
 303 
 304     /**
 305      * Identifies the focus change event as temporary or permanent.
 306      *
 307      * @return {@code true} if the focus change is temporary;
 308      *         {@code false} otherwise
 309      */
 310     public boolean isTemporary() {
 311         return temporary;
 312     }
 313 
 314     /**
 315      * Returns the other Component involved in this focus change. For a
 316      * FOCUS_GAINED event, this is the Component that lost focus. For a
 317      * FOCUS_LOST event, this is the Component that gained focus. If this
 318      * focus change occurs with a native application, with a Java application
 319      * in a different VM or context, or with no other Component, then null is
 320      * returned.
 321      *
 322      * @return the other Component involved in the focus change, or null
 323      * @since 1.4
 324      */
 325     public Component getOppositeComponent() {
 326         if (opposite == null) {
 327             return null;
 328         }
 329 
 330         return (SunToolkit.targetToAppContext(opposite) ==
 331                 AppContext.getAppContext())
 332             ? opposite
 333             : null;
 334     }
 335 
 336     /**
 337      * Returns a parameter string identifying this event.
 338      * This method is useful for event-logging and for debugging.
 339      *
 340      * @return a string identifying the event and its attributes
 341      */
 342     public String paramString() {
 343         String typeStr;
 344         switch(id) {
 345           case FOCUS_GAINED:
 346               typeStr = "FOCUS_GAINED";
 347               break;
 348           case FOCUS_LOST:
 349               typeStr = "FOCUS_LOST";
 350               break;
 351           default:
 352               typeStr = "unknown type";
 353         }
 354         return typeStr + (temporary ? ",temporary" : ",permanent") +
 355             ",opposite=" + getOppositeComponent() + ",cause=" + getCause();
 356     }
 357 
 358     /**
 359      * Returns the event cause.
 360      *
 361      * @return one of {@link Cause} values
 362      * @since 9
 363      */
 364     public final Cause getCause() {
 365         return cause;
 366     }
 367 
 368     // Ensure that the deserialized object is compatible
 369     @SuppressWarnings("serial")
 370     Object readResolve() throws ObjectStreamException {
 371         if (cause != null) {
 372             return this;
 373         }
 374         FocusEvent focusEvent = new FocusEvent(new Component(){}, getID(),
 375                 isTemporary(), getOppositeComponent());
 376         focusEvent.setSource(null);
 377         focusEvent.consumed = consumed;
 378 
 379         AWTAccessor.AWTEventAccessor accessor =
 380                 AWTAccessor.getAWTEventAccessor();
 381         accessor.setBData(focusEvent, accessor.getBData(this));
 382         return focusEvent;
 383     }
 384 
 385 
 386 }