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)
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., 51 Franklin Street, Fifth Floor, Boston, MA
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
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. */
41 import java
.io
.Serializable
;
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)
63 public class ContainerOrderFocusTraversalPolicy
extends FocusTraversalPolicy
64 implements Serializable
67 * Compatible to JDK 1.4+
69 static final long serialVersionUID
= 486933713763926351L;
72 * True if implicit down cycling is enabled.
74 private boolean implicitDownCycleTraversal
= true;
77 * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object.
79 public ContainerOrderFocusTraversalPolicy ()
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
)
100 throw new IllegalArgumentException ("focus cycle root is 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
116 if (ancestor
!= root
)
117 throw new IllegalArgumentException ("the given container is not"
118 + " a focus cycle root of the"
119 + " current component");
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
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
)
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
]);
164 && implicitDownCycleTraversal
)
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
);
178 * Returns the Component that should receive the focus before
179 * <code>current</code>. <code>root</code> must be a focus cycle
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
)
194 throw new IllegalArgumentException ("focus cycle root is 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
210 if (ancestor
!= root
)
211 throw new IllegalArgumentException ("the given container is not"
212 + " a focus cycle root of the"
213 + " current component");
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
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
)
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
]);
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
);
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
)
283 throw new IllegalArgumentException ();
285 if (!root
.isVisible ()
286 || !root
.isDisplayable ())
292 Component
[] componentArray
= root
.getComponents ();
294 for (int i
= 0; i
< componentArray
.length
; i
++)
296 Component component
= componentArray
[i
];
298 if (accept (component
))
301 if (component
instanceof Container
)
303 Component result
= getFirstComponent ((Container
) component
);
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
)
326 throw new IllegalArgumentException ();
328 if (!root
.isVisible ()
329 || !root
.isDisplayable ())
335 Component
[] componentArray
= root
.getComponents ();
337 for (int i
= componentArray
.length
- 1; i
>= 0; i
--)
339 Component component
= componentArray
[i
];
341 if (accept (component
))
344 if (component
instanceof Container
)
346 Component result
= getLastComponent ((Container
) component
);
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
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 ()
411 && current
.focusable
);