JDK-4532893 : Certain actions implicitly generate focus events in the new focus model
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.0
  • Priority: P5
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2001-11-29
  • Updated: 2014-07-22
  • Resolved: 2002-03-14
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 Other
1.4.0_01 01Fixed 1.4.1Fixed
Related Reports
Relates :  
Description
Name: pa48320			Date: 11/29/2001

(this bug is to track the JInitiator Replacement Project. please direct
any questions to Peter Allenbach. Thank you)

Implicit focus transfers in the AWT classes appear to combine
with the new focus model in JDK 1.4 to cause several bugs
encountered during the certification of Oracle Applications
11i on the JDK 1.4 platform.

Even if complete workarounds for these issues prove to be
feasible, it looks like they will fall under the category of
rearchitecting rather than bug fixing, so we would very much
like to search for solutions to better preserve compatibility
between 1.1.8 and 1.4.

There are a set of  "focus sensitive" actions the JDK allows on
UI components, which are sensitive in the sense that if the
component on which we?re performing them currently has focus,
they implicitly generate focus changes. Examples of these
behaviors include disabling, hiding, or removing a focused
component from its container, all of which will cause the JDK to
request focus on some other component.

Performing these actions on components which currently have focus
is a requirement for us because we are a tool which allows
application developers to declaratively design a UI and set of
behaviors the UI should have in response to user events. For
example, within our model it is a completely valid UI design
to respond to a user mouse click by disabling the button which
has focus, just so long as focus is set on some other component.

When it is time for us to actually implement this sort of
sensitive action on a component at the java level, the question
becomes how we can use java to accomplish that action and ensure
focus ends up in the correct component, all within our event
listener where we process the user action.

In the context of JDK 1.1.8, our solution was to set focus to
some other component (the ultimate recipient if it is already
a valid focus recipient, or some temporary component otherwise)
before performing the  sensitive action. Since focus requests
were resolved synchronously, this would avoid any focus transfers
on the part of the JDK since by the time we performed the sensitive
action, that target component was not currently the focus owner.
We could then request focus to the correct component at the end
of our processing, and all of this could happen in one block of
code within a single event listener method.

In JDK 1.4 this strategy no longer works, since requesting focus
to another component no longer prevents the JDK from transferring
focus, and because the order of focus requests is (1) Forms
followed by (2) the JDK, focus will end up in the wrong component
once both requests are resolved.


The FocusTest testcase:
-----------------------
The FocusTest testcase contains a Frame with a Button and two
TextFields. The Button starts with the focus, and when the user
clicks it the application is designed to disable the button and
set focus to the second TextField (TextField2). This demonstrates
the issue described above.

Our JDK 1.1.8 strategy for this is to requestFocus on the desired
component (TextField2) and then disable the Button. Since focus
requests are processed synchronously in 1.1.8, the sequence of
events are as follows:

1. TextField2 requests focus
2. TextField2 receives focus
3. Button calls setEnabled(false)
4. Button becomes disabled

If that same code is run in JDK 1.4 where focus requests happen
asynchronously, the sequence of events is a little bit more
complex, and runs as follows:

1. TextField2 requests focus
2. TextField2?s focus request (1) is queued
3. Button calls setEnabled(false)
4. _autoTransferFocus requests focus on TextField1 (the next
   focusable component)
5. TextField1?s focus request (2) is queued
6. Button becomes disabled
7. The first focus request (1) is processed and TextField2
   receives focus
8. The second focus request (2) is processed and TextField1
   receives focus
 
[FocusTest.java]
----------------

import java.awt.*;
import java.awt.event.*;

public class FocusTest extends Frame implements ActionListener
{
    Panel panel = new Panel();
    MyButton    button1  = new MyButton("Push!");
    MyTextField field1   = new MyTextField(" Field 1");
    MyTextField field2   = new MyTextField(" Field 2");

    FocusTest()
    {
        add(panel);
        addWindowListener(
            new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    System.exit(0); } } );
        button1.addActionListener(this);
        panel.add(button1);
        panel.add(field1);
        panel.add(field2);
        pack();
    }

    public void actionPerformed(ActionEvent event)
    {
        if ( event.getSource() == button1 )
        {
            field2.requestFocus();
            button1.setEnabled(false);
        }
    }

    static public void main(String[] args)
    {
        (new FocusTest()).setVisible(true);
    }
}

class MyTextField extends TextField implements FocusListener
{

    MyTextField(String s)
    {
        super(s);
        addFocusListener(this);
    }

    public void requestFocus()
    {
        System.out.println("[MyTextField] requestFocus() from "+
                            this.getText());
        super.requestFocus();
    }

    public void focusGained(FocusEvent e)
    {
        System.out.println("[MyTextField] focusGained on " +
                            ((MyTextField)(e.getComponent())).getText());
    }

    public void focusLost(FocusEvent e)
    {
        System.out.println("[MyTextField] focusLost on " +
                            ((MyTextField)(e.getComponent())).getText());
    }
}

class MyButton extends Button implements FocusListener
{
    MyButton(String s)
    {
        super(s);
        addFocusListener(this);
    }

    public void requestFocus()
    {
        System.out.println("[MyButton] requestFocus() from " +
                            this.getLabel());
        super.requestFocus();
    }

    public void focusGained(FocusEvent e)
    {
        System.out.println("[MyButton] focusGained on " +
                            ((MyButton)(e.getComponent())).getLabel());
    }

    public void focusLost(FocusEvent e)
    {
        System.out.println("[MyButton] focusLost on " +
                            ((MyButton)(e.getComponent())).getLabel());
    }
}
(Review ID: 135397) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.0_01 hopper FIXED IN: 1.4.0_01 hopper INTEGRATED IN: 1.4.0_01 hopper VERIFIED IN: hopper-beta
24-08-2004

WORK AROUND Name: pa48320 Date: 11/29/2001 Possible Oracle Forms workarounds: ---------------------------------- If we stick with the general concept of moving the focus before we perform sensitive actions in order to avoid extra focus transfers to arbitrary components, then the JDK 1.4 focus model forces us to adopt a very different approach with our application logic. Rather than put all our logic into one event listener method, we need to execute all logic up through a requestFocus call, store our state and return, and then perform the rest of our logic in the focusGained method of that component once focus actually arrives there. While for a small testcase like this one that seems reasonable enough, it?s not clear that this is a scalable model for a complex application, nor that it?s ideal to have to spread one code flow over more than one listener. In addition to the question of the feasibility of rewriting our code in this way, another issue with this strategy is how we would know when to resume processing and give up if a focus event was not delivered. Another possibility is for us to abandon the concept of moving the focus before performing sensitive actions, and concentrate on setting focus afterward. This should theoretically cause focus to end up in the correct component once all requests are resolved. The complexity here is that it?s difficult for us to actually know where focus is during these operations. That means it is possible for other implicit focus transfers to occur, and during a series of sensitive operations (like disabling every item on the current canvas) many of our listeners may receive focus events we were not expecting. This opens up the problem that we need to be able to ignore a number of transitory focus events, which in turn implies somehow differentiating them from real user events. Possible JDK changes: --------------------- Before adding a JDK internal requestFocus call to the queue, the KeyboardFocusManager could check to see if there are pending requests initiated by the application which have not yet been processed (assuming those two can be differentiated). If so, then the JDK?s internal request should be denied since the application has already specified where the focus should end up and it is therefore not necessary for the JDK to default the focus. ======================================================================
24-08-2004

EVALUATION Commit to fix in Hopper (Oracle work). ###@###.### 2002-02-12 Oracle focus project. ###@###.### 2002-03-07 Verified on Hopper b14. ###@###.### 2002-06-17
12-02-2002