JDK-4238972 : DefaultFocusManager can infinite-loop
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.2.0,1.2.2,1.2.2_005
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic,solaris_2.6
  • CPU: generic,sparc
  • Submitted: 1999-05-17
  • Updated: 2001-01-11
  • Resolved: 2001-01-11
Related Reports
Duplicate :  
Description
Suppose that you have a container with one focusable component (but other non-focusable ones). Suppose that you try to transfer focus out of that component via the TAB. Suppose that as part of processing the TAB, the component is removed.

The focus manager will loop expecting to get back to the original component, which won't be there.


Name: skT88420			Date: 11/08/99


java version "1.2.2"
Classic VM (build JDK-1.2.2-W, native threads, symcjit)
This is related to 4238972 as it deals with infinite looping
in focus manager.

In class javax.swing.DefaultFocusManager,
the private (and somewhat strangely named) method
getFocusableComponentAfter(3)
will loop indefinitely under certain circumstances.
The problem is that there is no detection of cycles
unless they begin with what is here called initialComponent:

    private Component getFocusableComponentAfter(Component focusedComponent,
                                                 Container rootContainer,
                                                 boolean moveForward) {
        Component nextComponent;
        Component initialComponent;

        nextComponent = initialComponent = focusedComponent;
        do {
	    if(moveForward) {
	      
                nextComponent =
getNextComponent(nextComponent,rootContainer,true);
	    } else
                nextComponent =
getPreviousComponent(nextComponent,rootContainer);
            if(nextComponent == null)
                break;
            if(nextComponent == initialComponent)
                break;
        } while(!(nextComponent.isVisible() &&
                  nextComponent.isFocusTraversable() &&
                  nextComponent.isEnabled()));

        return nextComponent;
    }

now what getNextComponent and getPreviousComponent returns
depends on the settings of nextFocusableComponent in the
involved components themselves.

Suppose there are four components compA, ..., compD
and that
compA.getNextFocusableComponent() == compB
compB.getNextFocusableComponent() == compC
compC.getNextFocusableComponent() == compD
compD.getNextFocusableComponent() == compB
and further that neither comp is enabled, for instance.

if the above method is called with compA as the focusedComponent
then that's that. The while loop never terminates but keeps
moving nextComponent from compB to compC to CompD to CompB
and so on.

I encountered this problem and due to the privacy of the method
experimented with installing another FocusManager where the above
code is replaced by:

    private Component getFocusableComponentAfter(Component focusedComponent,
                                                 Container rootContainer,
                                                 boolean moveForward)
    {
        Component nextComponent = focusedComponent;
        Hashtable visitedComps = new Hashtable();
        Object nonNull = new Object();
        
        if (focusedComponent != null)
        {
            visitedComps.put(focusedComponent, nonNull);
        }
        do
        {
            nextComponent
                = moveForward
                  ? getNextComponent(nextComponent, rootContainer, true)
                  : getPreviousComponent(nextComponent, rootContainer);
            if (nextComponent == null)
            {
                break;
            }
            if (visitedComps.put(nextComponent, nonNull) != null)
            {
                // cycle detected, get out
                nextComponent = null;
                break;
            }
        }
        while(!(nextComponent.isVisible()
                &&
                nextComponent.isFocusTraversable()
                &&
                nextComponent.isEnabled()));
        visitedComps.clear();
        return nextComponent;
    }

This works. We use jdk1.2.2 but I have also "looked into" the 1.3beta
and there appears to be no cycle detection in the loop there either.
Hopefully you can fix this before you go final.

Regards,

Per Lindberger
(Review ID: 97575)
======================================================================

Comments
WORK AROUND Name: skT88420 Date: 11/08/99 Copy javax.swing.DefaultFocusManager.java to FixedFocusManager.java and replace the method getFocusableComponentAfter(3) as described above importing java.util.Hashtable. Then somewhere call FocusManager.setCurrentManager(new FixedFocusManager()); (Review ID: 97575) ======================================================================
11-06-2004

EVALUATION What she said. hania.gajewska@Eng 1999-09-20 This has been fixed by the merlin focus work. Closing as dup of 4290675: Focus Management Enhancements. hania.gajewska@Eng 2001-01-10
20-09-1999