JDK-4476300 : Various dangerous and inconsistent focus-related APIs should be deprecated
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.0
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2001-06-29
  • Updated: 2001-09-20
  • Resolved: 2001-08-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 beta2Fixed
Description
   * <code>DefaultFocusTraversalPolicy</code>.
     *
     * @see java.awt.DefaultFocusTraversalPolicy
     * @see java.awt.KeyboardFocusManager#setDefaultFocusTraversalPolicy
     * @deprecated as of 1.4, replaced by <code>KeyboardFocusManager.setDefaultFocusTraversalPolicy(FocusTraversalPolicy)</code>.
     */
    public static void disableSwingFocusManager();

    /**
     * Returns whether the application has invoked
     * <code>disableSwingFocusManager()</code>.
     *
     * @see #disableSwingFocusManager
     * @deprecated As of 1.4, replaced by
     *   <code>KeyboardFocusManager.getDefaultFocusTraversalPolicy()</code>.
     */
    public static boolean isFocusManagerEnabled();

    /**
     * Requests focus on this <code>JComponent</code>'s
     * <code>FocusTraversalPolicy</code>'s default <code>Component</code>. If
     * this <code>JComponent</code> is a focus cycle root, then its
     * <code>FocusTraversalPolicy</code> is used. Otherwise, the
     * <code>FocusTraversalPolicy</code> of this <code>JComponent</code>'s
     * focus-cycle-root ancestor is used.
     *
     * @see java.awt.FocusTraversalPolicy#getDefaultComponent
     * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy.getDefaultComponent(Container).requestFocus()</code>.
     */
    public boolean requestDefaultFocus();

    /**
     * Changes this <code>JComponent</code>'s focus traversal keys to CTRL+TAB
     * and CTRL+SHIFT+TAB. Also prevents
     * <code>SortingFocusTraversalPolicy</code> from considering descendants of
     * this JComponent when computing a focus traversal cycle.
     *
     * @see java.awt.Component#setFocusTraversalKeys
     * @see SortingFocusTraversalPolicy
     * @deprecated As of 1.4, replaced by
     *   <code>Component.setFocusTraversalKeys(int, Set)</code> and
     *   <code>Container.setFocusCycleRoot(boolean)</code>.
     */
    public boolean isManagingFocus();

    /**
     * Overrides the default <code>FocusTraversalPolicy</code> for this
     * <code>JComponent</code>'s focus traversal cycle by unconditionally
     * setting the specified <code>Component</code> as the next
     * <code>Component</code> in the cycle, and this <code>JComponent</code> as
     * the specified <code>Component</code>'s previous <code>Component</code>
     * in the cycle.
     *
     * @param aComponent the <code>Component</code> that should follow this
     *        <code>JComponent</code> in the focus traversal cycle
     *
     * @see #getNextFocusableComponent
     * @see java.awt.FocusTraversalPolicy
     * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code>.
     */
    public void setNextFocusableComponent(Component aComponent);

    /**
     * Returns the <code>Component</code> set by a prior call to
     * <code>setNextFocusableComponent(Component)</code> on this
     * <code>JComponent</code>.
     *
     * @return the <code>Component</code> that will follow this
     *        <code>JComponent</code> in the focus traversal cycle, or
     *        <code>null</code> if none has been explicitly specified
     *
     * @see #setNextFocusableComponent
     * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code>.
     */
    public Component getNextFocusableComponent();

    /**
     * Returns whether this <code>Component</code> can become the focus owner.
     *
     * @return <code>true</code> if this <code>Component</code> is focusable;
     *         <code>false</code> otherwise
     * @see #setFocusable
     * @since JDK1.1
     * @deprecated As of 1.4, replaced by <code>isFocusable()</code>.
     */
    public boolean isFocusTraversable();

    /**
     * Returns <code>true</code> if this <code>Component</code> is the focus
     * owner.
     *
     * @return <code>true</code> if this <code>Component</code> is the focus
               owner
     * @since 1.2
     * @deprecated As of 1.4, replaced by <code>isFocusOwner()</code>.
     */
    public boolean hasFocus();

    /**
     * Return the child <code>Component</code> of the specified
     * <code>Component</code> that is the focus owner, if any.
     *
     * @param comp the root of the <code>Component</code> hierarchy to search
     *        for the focus owner
     * @return the focus owner, or <code>null</code> if there is no focus
     *         owner, or if the focus owner is not <code>comp</code>, or a
     *         descendant of <code>comp</code>
     *
     * @see java.awt.KeyboardFocusManager#getFocusOwner
     * @deprecated As of 1.4, replaced by
     *   <code>KeyboardFocusManager.getFocusOwner()</code>.
     */
    public static Component findFocusOwner(Component comp);


API reviewed and approved by:

awt-core@eng swing-eng@eng


Implementation:
   - Engineer who made (or will make) the changes: David Mendenhall
   - Date at which changes will be complete: Immediately
   - Number of lines of new or modified code:
        + Java: None
        + Native: None
   - Code reviewed (or will be reviewed) by: N/A


Risk assessment:

Despite the deprecation, we will continue to support all of the APIs
except for FOCUS_MANAGER_CLASS_PROPERTY. They have already been
reimplemented in terms of the new focus architecture. Otherwise, there
is only the standard deprecation risk of annoying our customers.


SQE (product testing) impact:

TBD


JCK (compatibility testing) impact:

TBD


Doc impact:

javadoc changes only.


Localization impact:

None.


Internationalization impact:

None.


Security impact:

None.


Legal impact:

None.


For feature changes, Product Marketing approval:

N/A
Release: merlin-beta-refresh

Problem: (BugID 4476300)
  Various dangerous and inconsistent focus-related APIs should be deprecated

The Merlin Focus Enhancements project (RFE 4290675) introduced a new,
public architecture and a new terminology for handling keyboard focus
in sophisticated AWT and Swing applications. Prior to this project,
many of the focus-related APIs were inconsistent in usage and
terminology, were improperly documented, and led to poorly designed
UIs. Now that a viable alternative is available, we propose to
deprecate the most egregious of these APIs, discouraging developers
from ever using them again.

We recognize that deprecation has become the proverbial nuclear weapon
of the Java class libraries, and thus have curbed our desire to
deprecate anything that is only marginally obscene. We feel that the
nine methods and one field listed in this proposal have strong cases
for deprecation, and we make that case for each one. Even so, we
understand that the CCC may agree with some of our arguments, but not
others. Therefore, we ask that the CCC consider and approve each of
the proposed changes separately. (We refrained from submitting
separate requests in the interests of paperwork reduction.)


1. javax.swing.FocusManager.FOCUS_MANAGER_CLASS_PROPERTY

This field allowed an application to specify the class name of a
subclass of javax.swing.FocusManager that should be instantiated as
the default FocusManager. To do this, the application would call
UIManager.getDefaults().put(FocusManager.FOCUS_MANAGER_CLASS_PROPERTY,
"<class name>"). Because this was a String based API, there was
obviously no compile-time type checking of <class name>, and any
instantiation problems would be reported only at runtime. All known,
real-world applications avoided this approach, and instead simply
called FocusManager.setCurrentManager(FocusManager). This approach was
completely type-safe and was essentially equivalent in behavior.

With the adoption of the Merlin Focus Enhancements project, the
current FocusManager can no longer be considered a property of the UI;
its role has been substantially expanded, and it is now clearly
designed to be a property of the application. In fact, in terms of
implementation, the FocusManager was *always* a property of the
application. The old design merely made it look as though it were
associated with the PLAF. Continuing to allow developers to refer to
the current FocusManager via the UI maligns the basic focus
architecture, and blurs the line between Swing and the underlying
AWT. Given that no known developers are even using this field, and
that there is a simple replacement API, this field should be
deprecated so that future developers can more rapidly focus on the
salient points of the architecture.


2. javax.swing.FocusManager.disableSwingFocusManager() and
   javax.swing.FocusManager.isFocusManagerEnabled()

These two methods should be considered together, as we do not
recommend deprecating one, but not the other.

Prior to the Merlin Focus Enhancements, any Swing application
effectively had two focus managers. One was an instance of
javax.swing.FocusManager, and the other was woven into the
implementation of the AWT. Applications that mixed heavyweight AWT
Components, or non-Swing lightweight Components, with JComponents
experienced bizarre focus behavior unless they called
disableSwingFocusManager(). This prevented the two focus managers from
fighting against each other, and allowed AWT to manage all keyboard
traversal alone. Unfortunately, this also rendered useless all of the
Swing APIs related to keyboard traversal.

In merlin, there is only one focus manager: an instance of
java.awt.KeyboardFocusManager. Swing and AWT are designed to work in
concert, so there will never be a need to disable the "Swing" focus
manager. Indeed, such a concept doesn't even make sense. As with (1),
continuing to allow developers to make a distinction between a Swing
focus manager and an AWT focus manager maligns the basic
architecture. In addition, we cannot exactly replicate the behavior of
disableSwingFocusManager() under the new architecture. The current
implementation changes the default FocusTraversalPolicy from Swing's
LayoutFocusTraversalPolicy to AWT's DefaultFocusTraversalPolicy, which
is pretty close. However, the Swing APIs related to keyboard traversal
are no longer disabled, and there are other, subtle and unavoidable
differences.


3. javax.swing.JComponent.requestDefaultFocus()

This method was intended to provide a quick and convenient mechanism
for setting focus to the default Component of a container. For
example, this method could be used to move focus to the "OK" button of
a JDialog. However, the default implementation merely moved focus to
the first focus traversable Component.

This was a poor implementation for two significant reasons. First, the
Component chosen by the default implementation was often the wrong
Component for a given application. Therefore, applications had to
customize this "default" Component. But since there was no
'setDefaultComponent' method, developers had to subclass the container
and override 'requestDefaultFocus()'. Even worse, because
'requestDefaultFocus()' is invoked recursively by default, it was
sometimes necessary to subclass every Component in the
hierarchy. Second, this implementation relies upon the
'isFocusTraversable()' method, which we propose to deprecate in (6).

There is an additional, subtle reason why this method is badly
designed. Swing (and, starting in 1.4, AWT) allows a developer to
divide the Component hierarchy into a hierarchy of focus traversal
cycles, each of which has a default Component. The 1.3.1
implementation of 'requestDefaultFocus()' ignored this feature, but
the 1.4 implementation attempts to handle it. The problem is that
containers which are the roots of inferior focus traversal cycles
actually belong to two cycles: the one that they root, and the one of
their focus-cycle-root ancestor. There is no way to indicate when
calling this method on such a container which default Component (that
is, which focus traversal cycle's default Component) should be
focused. In writing the new implementation, we had to choose
arbitrarily, and developers will have to refer to the javadoc in order
to recall which one will be used.

For all of these reasons, and because there is a fairly simple
replacement, we propose to discourage developers from ever using this
method again.


4. javax.swing.JComponent.isManagingFocus()

The name for this method implies that it distinguishes whether the
Swing FocusManager (see (2)) interacts with the JComponent or not.
The 1.3.1 javadoc for this method reads differently, however:

    /**
     * Override this method and return true if your JComponent manages focus.
     * If your component manages focus, the focus manager will handle your
     * component's children. All key event will be sent to your key listener
     * including TAB and SHIFT+TAB. CONTROL+TAB and CONTROL+SHIFT+TAB
     * will move the focus to the next or previous component.
     */

The javadoc is, in fact, an oxymoron. CONTROL+TAB and
CONTROL+SHIFT+TAB are certainly KeyEvents, yet they will not be sent
to any KeyListeners, ever, even if this method returns 'true'.

In addition, as the name implies, this method does affect the behavior
of the JComponent when interacting with the FocusManager. If a Swing
application uses DefaultFocusManager (as most do), isManagingFocus()
affects the behavior of DefaultFocusManager.getNextComponent (but not
getPreviousComponent). The behavior of JTextAreas and JEditorPanes is
also subtly modified. None of these additional behaviors is
documented. And as a final insult, there is no
'setManagingFocus(boolean)' method. Developers must subclass
JComponent and override the method to return 'true'.

This method is, quite simply, a complete disaster. In the new
architecture, there are much better, documented mechanisms for
effecting all of these behaviors. More importantly, these mechanisms
are separated, so it is not necessary to use all of them or
none. There is no reason to encourage developers to continue to use
this method, and doing so would only perpetuate reliance on
undocumented, nonsensical behavior.


5. javax.swing.JComponent.setNextFocusableComponent(Component) and
   javax.swing.JComponent.getNextFocusableComponent()

These two methods should be considered together, as we do not
recommend deprecating one, but not the other.

Prior to merlin, there existed two primary mechanisms for customizing
keyboard traversal in a Swing application. One option was to replace
DefaultFocusManager. This was a heavyweight approach, but allowed the
developer to express the keyboard traversal behavior of the
application algorithmically. The more common approach was to leave
DefaultFocusManager alone, and instead use the methods above.

These methods required developers to hard code the traversal policy,
JComponent by JComponent. If a developer later added a JComponent to
the GUI, he would have to return to this code, and manually insert the
new JComponent into the traversal cycle. Developers often forgot to do
this, thus creating an incomplete cycle. During testing, few
developers verify that all Component are reachable via keyboard
traversal; instead, they typically use the mouse to focus a Component.
As discussed in (6), this is fine for sighted users, but prevents
blind users from using the application in a comparable, accessible
way.

Another subtle problem with these methods is that there is no
'setPreviousFocusableComponent(Component)' method. Instead,
setNextFocusableComponent establishes mappings in both directions.
Consider the following case:

  a.setNextFocusableComponent(c);
  b.setNextFocusableComponent(c);

Following execution of these methods, forward traversal from 'b' will
reach 'c', and backward traversal from 'c' will reach 'b'. However,
forward traversal from 'a' will also reach 'c'. Forward and backward
traversal among 'a', 'b', and 'c' is thus asymmetric. Starting from
'a', the user would expect that a forward traversal followed by a
backward traversal would return focus to 'a'. However, it moves focus
to 'b'.

We must strongly discourage developers from using these methods, as
they often lead to inadvertently inaccessible applications, and
asymmetric focus traversal cycles. The new FocusTraversalPolicy class
allows developers to express traversal algorithmically, but is more
lightweight than the DefaultFocusManager approach.


6. java.awt.Component.isFocusTraversable()

Prior to merlin, Swing and the AWT made a distinction between a
Component's ability to become the focus owner ("focusability") and its
participation in keyboard focus traversal ("focus
traversability"). This distinction led to GUIs that were not
accessible. Sighted users could set focus to a Component by clicking
on it with the mouse. Blind users who relied on screen readers,
however, could never reach the Component via keyboard traversal, and
thus could not use the application in a comparable way. The Merlin
Focus Enhancements eliminated this distinction, and unified both
concepts under a single 'java.awt.Component.isFocusable()' method.
'isFocusTraversable()' should be deprecated to discourage developers
from unknowingly creating inaccessible applications.


7. java.awt.Component.hasFocus()

This method has been replaced by 'java.awt.Component.isFocusOwner()'.
The new name is vastly preferable because it distinguishes between the
concept of the "focus owner" and the "focused Window". If we fail to
migrate developers to the new name, we are passively encouraging them
to write code that is non-obvious. Sustaining engineers will need to
refer to the documentation to understand what a call to 'hasFocus()'
means. In contrast, the name 'isFocusOwner()' is unambiguous to any
developer familiar with the standardized terminology of the Merlin
Focus Enhancements project.


8. javax.swing.SwingUtilities.findFocusOwner(Component)

One of the cornerstone RFEs implemented in the Merlin Focus
Enhancements project was a single API for querying the current focus
owner. Implementing this RFE was not a matter of simply adding a
method to return a state variable. This information was simply not
tracked by the AWT prior to merlin, and substantial architectural
work was required in order to start tracking it.

Without such a method, developers often resorted to writing utility
methods that searched the Component hierarchy for a Component whose
hasFocus() method (see (7)) returned 'true'. 'findFocusOwner()' is one
such method.

While it is trivial to reimplement 'findFocusOwner()' to invoke the
new method, 'findFocusOwner()' attempted to optimize the search by
taking a Component as the root of the hierarchy to search. If the
focus owner was not a descendant of the specified Component, even if
there existed a focus owner elsewhere in the application, 'null' was
returned.

What was an optimization prior to merlin is now a hindrance. After
performing a constant time operation to determine the current focus
owner, the new implementation of 'findFocusOwner()' must perform a
non-constant time search of the Component hierarchy to verify that the
focus owner is a descendant of the specified Component. No application
should incur this penalty. Consequently, this method should be
deprecated so that developers immediately switch to the new, constant
time method.


Requesters:

AWT Core (David Mendenhall and Hania Gajewska)


Proposed API change:

Deprecate the following:
  javax.swing.FocusManager.FOCUS_MANAGER_CLASS_PROPERTY
  javax.swing.FocusManager.disableSwingFocusManager()
  javax.swing.FocusManager.isFocusManagerEnabled()
  javax.swing.JComponent.requestDefaultFocus()
  javax.swing.JComponent.isManagingFocus()
  javax.swing.JComponent.setNextFocusableComponent(Component)
  javax.swing.JComponent.getNextFocusableComponent()
  java.awt.Component.isFocusTraversable()
  java.awt.Component.hasFocus()
  javax.swing.SwingUtilities.findFocusOwner(Component)

The javadoc for these APIs will be rewritten as follows:

    /** 
     * This field has been deprecated because its specification is incompatible
     * with the 1.4 focus APIs. Use of this field is no longer supported. See
     * the Focus Specification for more information.
     *
     * @see java.awt.KeyboardFocusManager#getCurrentKeyboardFocusManager
     * @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
     * @deprecated As of 1.4, with no replacement. The current FocusManager is
     *    no longer a property of the UI. Client code must query for the
     *    current FocusManager using
     *    <code>KeyboardFocusManager.getCurrentKeyboardFocusManager()</code>.
     */
    public static final String FOCUS_MANAGER_CLASS_PROPERTY;

    /**
     * Changes the current <code>KeyboardFocusManager</code>'s default
     * <code>FocusTraversalPolicy</code> to
  

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta2 FIXED IN: merlin-beta2 INTEGRATED IN: merlin-beta2 VERIFIED IN: merlin-beta3
14-06-2004

EVALUATION Committing to merlin-beta2. API change which must be considered before merlin ships. david.mendenhall@east 2001-06-28 Issues #1 and #7 were not deprecated. Instead, the APIs were obsoleted, and a migration path was provided. eric.hawkes@eng 2001-08-04 ========================== Verified in Merlin-beta3 (Build 80 ) .This mentioned methods are deprecated . ###@###.### 2001-09-20
04-08-2001