OSDN Git Service

Fix "make dvi"
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / ContainerOrderFocusTraversalPolicy.java
1 /* ContainerOrderFocusTraversalPolicy.java -- 
2    Copyright (C) 2002, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 package java.awt;
40
41 import java.io.Serializable;
42
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.
49  *
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.
54  *
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.
58  *
59  * @author Michael Koch
60  * @author Thomas Fitzsimmons (fitzsim@redhat.com)
61  * @since 1.4
62  */
63 public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy
64   implements Serializable
65 {
66   /**
67    * Compatible to JDK 1.4+
68    */
69   static final long serialVersionUID = 486933713763926351L;
70
71   /**
72    * True if implicit down cycling is enabled.
73    */
74   private boolean implicitDownCycleTraversal = true;
75
76   /**
77    * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object.
78    */
79   public ContainerOrderFocusTraversalPolicy ()
80   {
81     // Nothing to do here
82   }
83
84   /**
85    * Returns the Component that should receive the focus after current.
86    * root must be a focus cycle root of current.
87    *
88    * @param root a focus cycle root of current
89    * @param current a (possibly indirect) child of root, or root itself
90    *
91    * @return the next Component in the focus traversal order for root,
92    * or null if no acceptable Component exists.
93    *
94    * @exception IllegalArgumentException If root is not a focus cycle
95    * root of current, or if either root or current is null.
96    */
97   public Component getComponentAfter (Container root, Component current)
98   {
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");
103
104     if (!root.isFocusCycleRoot ())
105       throw new IllegalArgumentException ("root is not a focus cycle root");
106
107     Container ancestor = current.getFocusCycleRootAncestor ();
108     Container prevAncestor = ancestor;
109     while (ancestor != root)
110       {
111         ancestor = current.getFocusCycleRootAncestor ();
112         if (ancestor == prevAncestor)
113           {
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;
122           }
123         prevAncestor = ancestor;
124       }
125
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 ();
131
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);
137
138     Container parent = current.getParent ();
139
140     synchronized (parent.getTreeLock ())
141       {
142         Component[] components = parent.getComponents ();
143         int componentIndex = 0;
144         int numComponents = parent.getComponentCount ();
145
146         // Find component's index.
147         for (int i = 0; i < numComponents; i++)
148           {
149             if (components[i] == current)
150               componentIndex = i;
151           }
152
153         // Search forward for the next acceptable component.
154         for (int i = componentIndex + 1; i < numComponents; i++)
155           {
156             if (accept (components[i]))
157               return components[i];
158
159             if (components[i] instanceof Container)
160               {
161                 Component result = getFirstComponent ((Container) components[i]);
162
163                 if (result != null
164                     && implicitDownCycleTraversal)
165                   return result;
166               }
167           }
168
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);
172
173         return result;
174       }
175   }
176
177   /**
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.
181    *
182    * @param root a focus cycle root of current
183    * @param current a (possibly indirect) child of root, or root itself
184    *
185    * @return the previous Component in the focus traversal order for
186    * root, or null if no acceptable Component exists.
187    *
188    * @exception IllegalArgumentException If root is not a focus cycle
189    * root of current, or if either root or current is null.
190    */
191   public Component getComponentBefore (Container root, Component current)
192   {
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");
197
198     if (!root.isFocusCycleRoot ())
199       throw new IllegalArgumentException ("root is not a focus cycle root");
200
201     Container ancestor = current.getFocusCycleRootAncestor ();
202     Container prevAncestor = ancestor;
203     while (ancestor != root)
204       {
205         ancestor = current.getFocusCycleRootAncestor ();
206         if (ancestor == prevAncestor)
207           {
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;
216           }
217         prevAncestor = ancestor;
218       }
219
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 ();
225
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);
231
232     Container parent = current.getParent ();
233
234     synchronized (parent.getTreeLock ())
235       {
236         Component[] components = parent.getComponents ();
237         int componentIndex = 0;
238         int numComponents = parent.getComponentCount ();
239
240         // Find component's index.
241         for (int i = 0; i < numComponents; i++)
242           {
243             if (components[i] == current)
244               componentIndex = i;
245           }
246
247         // Search backward for the next acceptable component.
248         for (int i = componentIndex - 1; i >= 0; i--)
249           {
250             if (accept (components[i]))
251               return components[i];
252
253             if (components[i] instanceof Container)
254               {
255                 Component result = getLastComponent ((Container) components[i]);
256
257                 if (result != null)
258                   return result;
259               }
260           }
261
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);
265
266         return result;
267       }
268   }
269
270   /**
271    * Returns the first Component of root that should receive the focus.
272    *
273    * @param root a focus cycle root
274    *
275    * @return the first Component in the focus traversal order for
276    * root, or null if no acceptable Component exists.
277    *
278    * @exception IllegalArgumentException If root is null.
279    */
280   public Component getFirstComponent(Container root)
281   {
282     if (root == null)
283       throw new IllegalArgumentException ();
284
285     if (!root.isVisible ()
286         || !root.isDisplayable ())
287       return null;
288
289     if (accept (root))
290       return root;
291
292     Component[] componentArray = root.getComponents ();
293     
294     for (int i = 0; i < componentArray.length; i++)
295       {
296         Component component = componentArray [i];
297         
298         if (accept (component))
299           return component;
300
301         if (component instanceof Container)
302           {
303             Component result = getFirstComponent ((Container) component);
304
305             if (result != null)
306               return result;
307           }
308       }
309
310     return null;
311   }
312
313   /**
314    * Returns the last Component of root that should receive the focus.
315    *
316    * @param root a focus cycle root
317    *
318    * @return the last Component in the focus traversal order for
319    * root, or null if no acceptable Component exists.
320    *
321    * @exception IllegalArgumentException If root is null.
322    */
323   public Component getLastComponent (Container root)
324   {
325     if (root == null)
326       throw new IllegalArgumentException ();
327
328     if (!root.isVisible ()
329         || !root.isDisplayable ())
330       return null;
331
332     if (accept (root))
333       return root;
334
335     Component[] componentArray = root.getComponents ();
336     
337     for (int i = componentArray.length - 1; i >= 0; i--)
338       {
339         Component component = componentArray [i];
340         
341         if (accept (component))
342           return component;
343
344         if (component instanceof Container)
345           {
346             Component result = getLastComponent ((Container) component);
347
348             if (result != null)
349               return result;
350           }
351       }
352
353     return null;
354   }
355
356   /**
357    * Returns the default Component of root that should receive the focus.
358    *
359    * @param root a focus cycle root
360    *
361    * @return the default Component in the focus traversal order for
362    * root, or null if no acceptable Component exists.
363    *
364    * @exception IllegalArgumentException If root is null.
365    */
366   public Component getDefaultComponent (Container root)
367   {
368     return getFirstComponent (root);
369   }
370
371   /**
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.
376    *
377    * @param value the setting for implicit down cycling
378    */
379   public void setImplicitDownCycleTraversal (boolean value)
380   {
381     implicitDownCycleTraversal = value;
382   }
383
384   /**
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.
389    *
390    * @return true if the focus will be transferred down-cycle
391    * implicitly
392    */
393   public boolean getImplicitDownCycleTraversal ()
394   {
395     return implicitDownCycleTraversal;
396   }
397
398   /**
399    * Check whether the given Component is an acceptable target for the
400    * keyboard input focus.
401    *
402    * @param current the Component to check
403    *
404    * @return true if current is acceptable, false otherwise
405    */
406   protected boolean accept (Component current)
407   {
408     return (current.visible
409             && current.isDisplayable ()
410             && current.enabled
411             && current.focusable);
412   }
413 }