Swing Tabbed Borders

Turns out I needed to write a section on tab ordering for my book today, so I figured out a workaround for the problem of using Set Tabbing... in the VCE.

Import the following ContainerOrderFocusManager class into VisualAge (put it in whatever package you want) and add

FocusManager.setCurrentManager(new ContainerOrderFocusManager());

to your main() (or initialize() if you prefer) if you are using a Swing Container such as JPanel, JFrame...

(NOTE: If you have

import java.awt.*;

in your code you'll need to explicitly qualify the FocusManager as com.sun.java.swing.FocusManager or javax.swing.FocusManager, because AWT has its own FocusManager class...)

This is a Swing focus manager that determines the component order based on component order inside a Container.

This means you can use the Tab Ordering controls in the VCE for Swing containers that use a null layout (BAD IDEA!) or BorderLayout or GridBagLayout. Other layout managers, such as GridLayout and FlowLayout, use the component order to determine order of display, so the VCE won't let you rearrange their tabbing order.

I've only tested it for about 10 min right now, so there could be a bug lurking in there. If you find any problems or have a better solution, please let me know!

import com.sun.java.swing.DefaultFocusManager;

// OR import javax.swing.DefaultFocusManager;



import java.awt.Point;

import java.awt.Component;

import java.awt.Container;



/** A Simple Swing FocusManager that walks through components in the

 *    order they were added to containers, the same way AWT works

 *  NOTE: This code provided "as is", and has only undergone about

 *        10 minutes of testing

 *  ALSO: I'm sure this could be made slightly more efficient

 *        somewhere...

 */

public class ContainerOrderFocusManager extends DefaultFocusManager {

    /** Return order based on order in which

     *    components were added to containers

     */

    public boolean compareTabOrder(Component a,Component b) {

        // find a common container for the two components

        Container commonContainer;

        for(Component lookA = a; a != null; a = commonContainer) {

            commonContainer = lookA.getParent();

            for(Component lookB = b; b != null; b = b.getParent())

                if (commonContainer.isAncestorOf(b))

                    // determine which is found first

                    return (depthFindFirst(commonContainer, a, b) == 1);

        }



        // if neither share a parent container,

        //   do the normal focus search

        return super.compareTabOrder(a,b);

    }



    /** Helper method that walks through containers, depth-first,

     *  returning

     *    0: container doesn't contain either a or b

     *    1: found a first

     *    2: found b first

     */

    protected int depthFindFirst(Container c,

                                 Component a,

                                 Component b) {

        Component[] comps = c.getComponents();

        for(int i = 0; i < comps.length; i++)

            if (comps[i] == a)

                return 1;

            else if (comps[i] == b)

                return 2;

            else if (comps[i] instanceof Container) {

                int result = depthFindFirst((Container)comps[i], a, b);

                if (result > 0)

                    return result;

            }

        return 0;

    }

}