Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4238972

DefaultFocusManager can infinite-loop

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 1.2.0, 1.2.2, 1.2.2_005
    • client-libs
    • generic, sparc
    • generic, solaris_2.6

      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)
      ======================================================================

            hgajewsksunw Hania Gajewska (Inactive)
            hgajewsksunw Hania Gajewska (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: