Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / awt / ContainerOrderFocusTraversalPolicy.java
blob91153e69935c5c4432068b7a87002262cd220ffe
1 /* ContainerOrderFocusTraversalPolicy.java --
2 Copyright (C) 2002, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.awt;
41 import java.io.Serializable;
43 /**
44 * ContainerOrderFocusTraversalPolicy defines a focus traversal order
45 * based on the order in which Components were packed in a Container.
46 * This policy performs a pre-order traversal of the Component
47 * hierarchy starting from a given focus cycle root. Portions of the
48 * hierarchy that are not visible and displayable are skipped.
50 * By default, this policy transfers focus down-cycle implicitly.
51 * That is, if a forward traversal is requested on a focus cycle root
52 * and the focus cycle root has focusable children, the focus will
53 * automatically be transfered down to the lower focus cycle.
55 * The default implementation of accept accepts only Components that
56 * are visible, displayable, enabled and focusable. Derived classes
57 * can override these acceptance criteria by overriding accept.
59 * @author Michael Koch
60 * @author Thomas Fitzsimmons (fitzsim@redhat.com)
61 * @since 1.4
63 public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy
64 implements Serializable
66 /**
67 * Compatible to JDK 1.4+
69 static final long serialVersionUID = 486933713763926351L;
71 /**
72 * True if implicit down cycling is enabled.
74 private boolean implicitDownCycleTraversal = true;
76 /**
77 * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object.
79 public ContainerOrderFocusTraversalPolicy ()
81 // Nothing to do here
84 /**
85 * Returns the Component that should receive the focus after current.
86 * root must be a focus cycle root of current.
88 * @param root a focus cycle root of current
89 * @param current a (possibly indirect) child of root, or root itself
91 * @return the next Component in the focus traversal order for root,
92 * or null if no acceptable Component exists.
94 * @exception IllegalArgumentException If root is not a focus cycle
95 * root of current, or if either root or current is null.
97 public Component getComponentAfter (Container root, Component current)
99 if (root == null)
100 throw new IllegalArgumentException ("focus cycle root is null");
101 if (current == null)
102 throw new IllegalArgumentException ("current component is null");
104 if (!root.isFocusCycleRoot ())
105 throw new IllegalArgumentException ("root is not a focus cycle root");
107 Container ancestor = current.getFocusCycleRootAncestor ();
108 Container prevAncestor = ancestor;
109 while (ancestor != root)
111 ancestor = current.getFocusCycleRootAncestor ();
112 if (ancestor == prevAncestor)
114 // We've reached the top focus cycle root ancestor. Check
115 // if it is root.
116 if (ancestor != root)
117 throw new IllegalArgumentException ("the given container is not"
118 + " a focus cycle root of the"
119 + " current component");
120 else
121 break;
123 prevAncestor = ancestor;
126 // FIXME: is this the right thing to do here? It moves the context
127 // for traversal up one focus traversal cycle. We'll need a test
128 // for this.
129 if ((Component) root == current)
130 root = current.getFocusCycleRootAncestor ();
132 // Check if we've reached the top of the component hierarchy. If
133 // so then we want to loop around to the first component in the
134 // focus traversal cycle.
135 if (current instanceof Window)
136 return getFirstComponent ((Container) current);
138 Container parent = current.getParent ();
140 synchronized (parent.getTreeLock ())
142 Component[] components = parent.getComponents ();
143 int componentIndex = 0;
144 int numComponents = parent.getComponentCount ();
146 // Find component's index.
147 for (int i = 0; i < numComponents; i++)
149 if (components[i] == current)
150 componentIndex = i;
153 // Search forward for the next acceptable component.
154 for (int i = componentIndex + 1; i < numComponents; i++)
156 if (accept (components[i]))
157 return components[i];
159 if (components[i] instanceof Container)
161 Component result = getFirstComponent ((Container) components[i]);
163 if (result != null
164 && implicitDownCycleTraversal)
165 return result;
169 // No focusable components after current in its Container. So go
170 // to the next Component after current's Container (parent).
171 Component result = getComponentAfter (root, parent);
173 return result;
178 * Returns the Component that should receive the focus before
179 * <code>current</code>. <code>root</code> must be a focus cycle
180 * root of current.
182 * @param root a focus cycle root of current
183 * @param current a (possibly indirect) child of root, or root itself
185 * @return the previous Component in the focus traversal order for
186 * root, or null if no acceptable Component exists.
188 * @exception IllegalArgumentException If root is not a focus cycle
189 * root of current, or if either root or current is null.
191 public Component getComponentBefore (Container root, Component current)
193 if (root == null)
194 throw new IllegalArgumentException ("focus cycle root is null");
195 if (current == null)
196 throw new IllegalArgumentException ("current component is null");
198 if (!root.isFocusCycleRoot ())
199 throw new IllegalArgumentException ("root is not a focus cycle root");
201 Container ancestor = current.getFocusCycleRootAncestor ();
202 Container prevAncestor = ancestor;
203 while (ancestor != root)
205 ancestor = current.getFocusCycleRootAncestor ();
206 if (ancestor == prevAncestor)
208 // We've reached the top focus cycle root ancestor. Check
209 // if it is root.
210 if (ancestor != root)
211 throw new IllegalArgumentException ("the given container is not"
212 + " a focus cycle root of the"
213 + " current component");
214 else
215 break;
217 prevAncestor = ancestor;
220 // FIXME: is this the right thing to do here? It moves the context
221 // for traversal up one focus traversal cycle. We'll need a test
222 // for this.
223 if ((Component) root == current)
224 root = current.getFocusCycleRootAncestor ();
226 // Check if we've reached the top of the component hierarchy. If
227 // so then we want to loop around to the last component in the
228 // focus traversal cycle.
229 if (current instanceof Window)
230 return getLastComponent ((Container) current);
232 Container parent = current.getParent ();
234 synchronized (parent.getTreeLock ())
236 Component[] components = parent.getComponents ();
237 int componentIndex = 0;
238 int numComponents = parent.getComponentCount ();
240 // Find component's index.
241 for (int i = 0; i < numComponents; i++)
243 if (components[i] == current)
244 componentIndex = i;
247 // Search backward for the next acceptable component.
248 for (int i = componentIndex - 1; i >= 0; i--)
250 if (accept (components[i]))
251 return components[i];
253 if (components[i] instanceof Container)
255 Component result = getLastComponent ((Container) components[i]);
257 if (result != null)
258 return result;
262 // No focusable components before current in its Container. So go
263 // to the previous Component before current's Container (parent).
264 Component result = getComponentBefore (root, parent);
266 return result;
271 * Returns the first Component of root that should receive the focus.
273 * @param root a focus cycle root
275 * @return the first Component in the focus traversal order for
276 * root, or null if no acceptable Component exists.
278 * @exception IllegalArgumentException If root is null.
280 public Component getFirstComponent(Container root)
282 if (root == null)
283 throw new IllegalArgumentException ();
285 if (!root.isVisible ()
286 || !root.isDisplayable ())
287 return null;
289 if (accept (root))
290 return root;
292 Component[] componentArray = root.getComponents ();
294 for (int i = 0; i < componentArray.length; i++)
296 Component component = componentArray [i];
298 if (accept (component))
299 return component;
301 if (component instanceof Container)
303 Component result = getFirstComponent ((Container) component);
305 if (result != null)
306 return result;
310 return null;
314 * Returns the last Component of root that should receive the focus.
316 * @param root a focus cycle root
318 * @return the last Component in the focus traversal order for
319 * root, or null if no acceptable Component exists.
321 * @exception IllegalArgumentException If root is null.
323 public Component getLastComponent (Container root)
325 if (root == null)
326 throw new IllegalArgumentException ();
328 if (!root.isVisible ()
329 || !root.isDisplayable ())
330 return null;
332 if (accept (root))
333 return root;
335 Component[] componentArray = root.getComponents ();
337 for (int i = componentArray.length - 1; i >= 0; i--)
339 Component component = componentArray [i];
341 if (accept (component))
342 return component;
344 if (component instanceof Container)
346 Component result = getLastComponent ((Container) component);
348 if (result != null)
349 return result;
353 return null;
357 * Returns the default Component of root that should receive the focus.
359 * @param root a focus cycle root
361 * @return the default Component in the focus traversal order for
362 * root, or null if no acceptable Component exists.
364 * @exception IllegalArgumentException If root is null.
366 public Component getDefaultComponent (Container root)
368 return getFirstComponent (root);
372 * Set whether or not implicit down cycling is enabled. If it is,
373 * then initiating a forward focus traversal operation onto a focus
374 * cycle root, the focus will be implicitly transferred into the
375 * root container's focus cycle.
377 * @param value the setting for implicit down cycling
379 public void setImplicitDownCycleTraversal (boolean value)
381 implicitDownCycleTraversal = value;
385 * Check whether or not implicit down cycling is enabled. If it is,
386 * then initiating a forward focus traversal operation onto a focus
387 * cycle root, the focus will be implicitly transferred into the
388 * root container's focus cycle.
390 * @return true if the focus will be transferred down-cycle
391 * implicitly
393 public boolean getImplicitDownCycleTraversal ()
395 return implicitDownCycleTraversal;
399 * Check whether the given Component is an acceptable target for the
400 * keyboard input focus.
402 * @param current the Component to check
404 * @return true if current is acceptable, false otherwise
406 protected boolean accept (Component current)
408 return (current.visible
409 && current.isDisplayable ()
410 && current.enabled
411 && current.focusable);