diff options
Diffstat (limited to 'libjava/java/awt/ContainerOrderFocusTraversalPolicy.java')
-rw-r--r-- | libjava/java/awt/ContainerOrderFocusTraversalPolicy.java | 275 |
1 files changed, 242 insertions, 33 deletions
diff --git a/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java b/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java index ce4bdf8..fa7ab4a 100644 --- a/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -41,7 +41,23 @@ package java.awt; import java.io.Serializable; /** + * ContainerOrderFocusTraversalPolicy defines a focus traversal order + * based on the order in which Components were packed in a Container. + * This policy performs a pre-order traversal of the Component + * hierarchy starting from a given focus cycle root. Portions of the + * hierarchy that are not visible and displayable are skipped. + * + * By default, this policy transfers focus down-cycle implicitly. + * That is, if a forward traversal is requested on a focus cycle root + * and the focus cycle root has focusable children, the focus will + * automatically be transfered down to the lower focus cycle. + * + * The default implementation of accept accepts only Components that + * are visible, displayable, enabled and focusable. Derived classes + * can override these acceptance criteria by overriding accept. + * * @author Michael Koch + * @author Thomas Fitzsimmons <fitzsim@redhat.com> * @since 1.4 */ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy @@ -52,12 +68,15 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy */ static final long serialVersionUID = 486933713763926351L; + /** + * True if implicit down cycling is enabled. + */ private boolean implicitDownCycleTraversal = true; /** * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object. */ - public ContainerOrderFocusTraversalPolicy() + public ContainerOrderFocusTraversalPolicy () { // Nothing to do here } @@ -66,37 +85,196 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy * Returns the Component that should receive the focus after current. * root must be a focus cycle root of current. * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the next Component in the focus traversal order for root, + * or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is not a focus cycle * root of current, or if either root or current is null. */ - public Component getComponentAfter(Container root, Component current) + public Component getComponentAfter (Container root, Component current) { - if (root == null - || current == null) - throw new IllegalArgumentException (); - - return null; + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the first component in the + // focus traversal cycle. + if (current instanceof Window) + return getFirstComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search forward for the next acceptable component. + for (int i = componentIndex + 1; i < numComponents; i++) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getFirstComponent ((Container) components[i]); + + if (result != null + && implicitDownCycleTraversal) + return result; + } + } + + // No focusable components after current in its Container. So go + // to the next Component after current's Container (parent). + Component result = getComponentAfter (root, parent); + + return result; + } } /** - * Returns the Component that should receive the focus before current. - * root must be a focus cycle root of current. + * Returns the Component that should receive the focus before + * <code>current</code>. <code>root</code> must be a focus cycle + * root of current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the previous Component in the focus traversal order for + * root, or null if no acceptable Component exists. * * @exception IllegalArgumentException If root is not a focus cycle * root of current, or if either root or current is null. */ - public Component getComponentBefore(Container root, Component current) + public Component getComponentBefore (Container root, Component current) { - if (root == null - || current == null) - throw new IllegalArgumentException (); + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); - return null; + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the last component in the + // focus traversal cycle. + if (current instanceof Window) + return getLastComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search backward for the next acceptable component. + for (int i = componentIndex - 1; i >= 0; i--) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getLastComponent ((Container) components[i]); + + if (result != null) + return result; + } + } + + // No focusable components before current in its Container. So go + // to the previous Component before current's Container (parent). + Component result = getComponentBefore (root, parent); + + return result; + } } /** * Returns the first Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the first Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ public Component getFirstComponent(Container root) @@ -117,18 +295,16 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy { Component component = componentArray [i]; + if (accept (component)) + return component; + if (component instanceof Container) { - Component result = getLastComponent ((Container) component); + Component result = getFirstComponent ((Container) component); if (result != null) return result; } - else - { - if (accept (component)) - return component; - } } return null; @@ -137,9 +313,14 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy /** * Returns the last Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the last Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ - public Component getLastComponent(Container root) + public Component getLastComponent (Container root) { if (root == null) throw new IllegalArgumentException (); @@ -153,10 +334,13 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy Component[] componentArray = root.getComponents (); - for (int i = componentArray.length - 1; i >= 0; i++) + for (int i = componentArray.length - 1; i >= 0; i--) { Component component = componentArray [i]; + if (accept (component)) + return component; + if (component instanceof Container) { Component result = getLastComponent ((Container) component); @@ -164,11 +348,6 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy if (result != null) return result; } - else - { - if (accept (component)) - return component; - } } return null; @@ -177,28 +356,58 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy /** * Returns the default Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the default Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ - public Component getDefaultComponent(Container root) + public Component getDefaultComponent (Container root) { return getFirstComponent (root); } - public void setImplicitDownCycleTraversal(boolean value) + /** + * Set whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @param value the setting for implicit down cycling + */ + public void setImplicitDownCycleTraversal (boolean value) { implicitDownCycleTraversal = value; } - public boolean getImplicitDownCycleTraversal() + /** + * Check whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @return true if the focus will be transferred down-cycle + * implicitly + */ + public boolean getImplicitDownCycleTraversal () { return implicitDownCycleTraversal; } - protected boolean accept(Component current) + /** + * Check whether the given Component is an acceptable target for the + * keyboard input focus. + * + * @param current the Component to check + * + * @return true if current is acceptable, false otherwise + */ + protected boolean accept (Component current) { return (current.visible - && current.isDisplayable() + && current.isDisplayable () && current.enabled && current.focusable); } -} // class ContainerOrderFocusTraversalPolicy +} |