aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/awt/ContainerOrderFocusTraversalPolicy.java')
-rw-r--r--libjava/java/awt/ContainerOrderFocusTraversalPolicy.java275
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
+}