OSDN Git Service

2004-03-17 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / KeyboardFocusManager.java
1 /* KeyboardFocusManager.java -- manage component focusing via the keyboard
2    Copyright (C) 2002 Free Software Foundation
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.awt.event.KeyEvent;
42 import java.beans.PropertyChangeListener;
43 import java.beans.PropertyChangeSupport;
44 import java.beans.PropertyVetoException;
45 import java.beans.VetoableChangeListener;
46 import java.beans.VetoableChangeSupport;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Set;
53
54 /**
55  *
56  * @author Eric Blake <ebb9@email.byu.edu>
57  * @since 1.4
58  * @status partially updated to 1.4, needs documentation.
59  */
60 public abstract class KeyboardFocusManager
61   implements KeyEventDispatcher, KeyEventPostProcessor
62 {
63   public static final int FORWARD_TRAVERSAL_KEYS = 0;
64   public static final int BACKWARD_TRAVERSAL_KEYS = 1;
65   public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
66   public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
67
68   private static final Set DEFAULT_FORWARD_KEYS;
69   private static final Set DEFAULT_BACKWARD_KEYS;
70   static
71   {
72     Set s = new HashSet();
73     s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0));
74     s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
75                                        KeyEvent.CTRL_DOWN_MASK));
76     DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s);
77     s = new HashSet();
78     s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
79                                        KeyEvent.SHIFT_DOWN_MASK));
80     s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
81                                        KeyEvent.SHIFT_DOWN_MASK
82                                        | KeyEvent.CTRL_DOWN_MASK));
83     DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s);
84   }
85
86   private static KeyboardFocusManager current
87     = new DefaultKeyboardFocusManager();
88
89   // XXX Not implemented correctly. I think a good implementation here may
90   // be to have permanentFocusOwner be null, and fall back to focusOwner,
91   // unless a temporary focus change is in effect.
92   private static Component focusOwner;
93   private static Component permanentFocusOwner;
94
95   private static Window focusedWindow;
96   private static Window activeWindow;
97   private static Container focusCycleRoot;
98
99   private FocusTraversalPolicy defaultPolicy;
100   private Set[] defaultFocusKeys = new Set[] {
101     DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
102     Collections.EMPTY_SET, Collections.EMPTY_SET
103   };
104
105   private final PropertyChangeSupport propertyChangeSupport
106     = new PropertyChangeSupport(this);
107   private final VetoableChangeSupport vetoableChangeSupport
108     = new VetoableChangeSupport(this);
109   private final ArrayList keyEventDispatchers = new ArrayList();
110   private final ArrayList keyEventPostProcessors = new ArrayList();
111
112 \f
113   public KeyboardFocusManager()
114   {
115   }
116
117   public static KeyboardFocusManager getCurrentKeyboardFocusManager()
118   {
119     // XXX Need a way to divide this into contexts.
120     return current;
121   }
122
123   public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
124   {
125     SecurityManager sm = System.getSecurityManager();
126     if (sm != null)
127       sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager"));
128     // XXX Need a way to divide this into contexts.
129     current = m == null ? new DefaultKeyboardFocusManager() : m;
130   }
131
132   public Component getFocusOwner()
133   {
134     // XXX Need an easy way to test if this thread is in the context of the
135     // global focus owner, to avoid creating the exception in the first place.
136     try
137       {
138         return getGlobalFocusOwner();
139       }
140     catch (SecurityException e)
141       {
142         return null;
143       }
144   }
145
146   protected Component getGlobalFocusOwner()
147   {
148     // XXX Need a way to test if this thread is in the context of the focus
149     // owner, and throw a SecurityException if that is the case.
150     // XXX Implement.
151     return focusOwner;
152   }
153
154   protected void setGlobalFocusOwner(Component owner)
155   {
156     // XXX Should this send focus events to the components involved?
157     if (owner == null || owner.focusable)
158       {
159         firePropertyChange("focusOwner", focusOwner, owner);
160         try
161           {
162             fireVetoableChange("focusOwner", focusOwner, owner);
163             focusOwner = owner;
164           }
165         catch (PropertyVetoException e)
166           {
167           }
168       }
169   }
170
171   public void clearGlobalFocusOwner()
172   {
173     // XXX Is this enough?
174     setGlobalFocusOwner(null);
175   }
176
177   public Component getPermanentFocusOwner()
178   {
179     // XXX Need an easy way to test if this thread is in the context of the
180     // global focus owner, to avoid creating the exception in the first place.
181     try
182       {
183         return getGlobalPermanentFocusOwner();
184       }
185     catch (SecurityException e)
186       {
187         return null;
188       }
189   }
190
191   protected Component getGlobalPermanentFocusOwner()
192   {
193     // XXX Need a way to test if this thread is in the context of the focus
194     // owner, and throw a SecurityException if that is the case.
195     // XXX Implement.
196     return permanentFocusOwner == null ? focusOwner : permanentFocusOwner;
197   }
198
199   protected void setGlobalPermanentFocusOwner(Component focusOwner)
200   {
201     // XXX Should this send focus events to the components involved?
202     if (focusOwner == null || focusOwner.focusable)
203       {
204         firePropertyChange("permanentFocusOwner", permanentFocusOwner,
205                            focusOwner);
206         try
207           {
208             fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
209                                focusOwner);
210             permanentFocusOwner = focusOwner;
211           }
212         catch (PropertyVetoException e)
213           {
214           }
215       }
216   }
217
218   public Window getFocusedWindow()
219   {
220     // XXX Need an easy way to test if this thread is in the context of the
221     // global focus owner, to avoid creating the exception in the first place.
222     try
223       {
224         return getGlobalFocusedWindow();
225       }
226     catch (SecurityException e)
227       {
228         return null;
229       }
230   }
231
232   protected Window getGlobalFocusedWindow()
233   {
234     // XXX Need a way to test if this thread is in the context of the focus
235     // owner, and throw a SecurityException if that is the case.
236     // XXX Implement.
237     return focusedWindow;
238   }
239
240   protected void setGlobalFocusedWindow(Window window)
241   {
242     // XXX Should this send focus events to the windows involved?
243     if (window == null || window.focusable)
244       {
245         firePropertyChange("focusedWindow", focusedWindow, window);
246         try
247           {
248             fireVetoableChange("focusedWindow", focusedWindow, window);
249             focusedWindow = window;
250           }
251         catch (PropertyVetoException e)
252           {
253           }
254       }
255   }
256
257   public Window getActiveWindow()
258   {
259     // XXX Need an easy way to test if this thread is in the context of the
260     // global focus owner, to avoid creating the exception in the first place.
261     try
262       {
263         return getGlobalActiveWindow();
264       }
265     catch (SecurityException e)
266       {
267         return null;
268       }
269   }
270
271   protected Window getGlobalActiveWindow()
272   {
273     // XXX Need a way to test if this thread is in the context of the focus
274     // owner, and throw a SecurityException if that is the case.
275     // XXX Implement.
276     return activeWindow;
277   }
278
279   protected void setGlobalActiveWindow(Window window)
280   {
281     // XXX Should this send focus events to the windows involved?
282     firePropertyChange("activeWindow", activeWindow, window);
283     try
284       {
285         fireVetoableChange("activeWindow", activeWindow, window);
286         activeWindow = window;
287       }
288     catch (PropertyVetoException e)
289       {
290       }
291   }
292
293   public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
294   {
295     if (defaultPolicy == null)
296       defaultPolicy = new DefaultFocusTraversalPolicy();
297     return defaultPolicy;
298   }
299
300   public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
301   {
302     if (policy == null)
303       throw new IllegalArgumentException();
304     firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
305     defaultPolicy = policy;
306   }
307
308   public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
309   {
310     if (keystrokes == null)
311       throw new IllegalArgumentException();
312     Set sa;
313     Set sb;
314     Set sc;
315     String type;
316     switch (id)
317       {
318       case FORWARD_TRAVERSAL_KEYS:
319         sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
320         sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
321         sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
322         type = "forwardDefaultFocusTraversalKeys";
323         break;
324       case BACKWARD_TRAVERSAL_KEYS:
325         sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
326         sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
327         sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
328         type = "backwardDefaultFocusTraversalKeys";
329         break;
330       case UP_CYCLE_TRAVERSAL_KEYS:
331         sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
332         sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
333         sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
334         type = "upCycleDefaultFocusTraversalKeys";
335         break;
336       case DOWN_CYCLE_TRAVERSAL_KEYS:
337         sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
338         sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
339         sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
340         type = "downCycleDefaultFocusTraversalKeys";
341         break;
342       default:
343         throw new IllegalArgumentException();
344       }
345     int i = keystrokes.size();
346     Iterator iter = keystrokes.iterator();
347     while (--i >= 0)
348       {
349         Object o = iter.next();
350         if (! (o instanceof AWTKeyStroke)
351             || sa.contains(o) || sb.contains(o) || sc.contains(o)
352             || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
353           throw new IllegalArgumentException();
354       }
355     keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
356     firePropertyChange(type, defaultFocusKeys[id], keystrokes);
357     defaultFocusKeys[id] = keystrokes;
358   }
359
360   public Set getDefaultFocusTraversalKeys(int id)
361   {
362     if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
363       throw new IllegalArgumentException();
364     return defaultFocusKeys[id];
365   }
366
367   public Container getCurrentFocusCycleRoot()
368   {
369     // XXX Need an easy way to test if this thread is in the context of the
370     // global focus owner, to avoid creating the exception in the first place.
371     try
372       {
373         return getGlobalCurrentFocusCycleRoot();
374       }
375     catch (SecurityException e)
376       {
377         return null;
378       }
379   }
380
381   protected Container getGlobalCurrentFocusCycleRoot()
382   {
383     // XXX Need a way to test if this thread is in the context of the focus
384     // owner, and throw a SecurityException if that is the case.
385     // XXX Implement.
386     return focusCycleRoot;
387   }
388
389   public void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
390   {
391     firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
392     focusCycleRoot = cycleRoot;
393   }
394
395   public void addPropertyChangeListener(PropertyChangeListener l)
396   {
397     if (l != null)
398       propertyChangeSupport.addPropertyChangeListener(l);
399   }
400
401   public void removePropertyChangeListener(PropertyChangeListener l)
402   {
403     if (l != null)
404       propertyChangeSupport.removePropertyChangeListener(l);
405   }
406
407   public PropertyChangeListener[] getPropertyChangeListeners()
408   {
409     return propertyChangeSupport.getPropertyChangeListeners();
410   }
411
412   public void addPropertyChangeListener(String name, PropertyChangeListener l)
413   {
414     if (l != null)
415       propertyChangeSupport.addPropertyChangeListener(name, l);
416   }
417
418   public void removePropertyChangeListener(String name,
419                                            PropertyChangeListener l)
420   {
421     if (l != null)
422       propertyChangeSupport.removePropertyChangeListener(name, l);
423   }
424
425   public PropertyChangeListener[] getPropertyChangeListeners(String name)
426   {
427     return propertyChangeSupport.getPropertyChangeListeners(name);
428   }
429
430   protected void firePropertyChange(String name, Object o, Object n)
431   {
432     propertyChangeSupport.firePropertyChange(name, o, n);
433   }
434
435   public void addVetoableChangeListener(VetoableChangeListener l)
436   {
437     if (l != null)
438       vetoableChangeSupport.addVetoableChangeListener(l);
439   }
440
441   public void removeVetoableChangeListener(VetoableChangeListener l)
442   {
443     if (l != null)
444       vetoableChangeSupport.removeVetoableChangeListener(l);
445   }
446
447   public VetoableChangeListener[] getVetoableChangeListeners()
448   {
449     return vetoableChangeSupport.getVetoableChangeListeners();
450   }
451
452   public void addVetoableChangeListener(String name, VetoableChangeListener l)
453   {
454     if (l != null)
455       vetoableChangeSupport.addVetoableChangeListener(name, l);
456   }
457
458   public void removeVetoableChangeListener(String name,
459                                            VetoableChangeListener l)
460   {
461     if (l != null)
462       vetoableChangeSupport.removeVetoableChangeListener(name, l);
463   }
464
465   public VetoableChangeListener[] getVetoableChangeListeners(String name)
466   {
467     return vetoableChangeSupport.getVetoableChangeListeners(name);
468   }
469
470   protected void fireVetoableChange(String name, Object o, Object n)
471     throws PropertyVetoException
472   {
473     vetoableChangeSupport.fireVetoableChange(name, o, n);
474   }
475
476   public void addKeyEventDispatcher(KeyEventDispatcher dispatcher)
477   {
478     if (dispatcher != null)
479       keyEventDispatchers.add(dispatcher);
480   }
481
482   public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher)
483   {
484     keyEventDispatchers.remove(dispatcher);
485   }
486
487   protected List getKeyEventDispatchers()
488   {
489     return (List) keyEventDispatchers.clone();
490   }
491
492   public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
493   {
494     if (postProcessor != null)
495       keyEventPostProcessors.add(postProcessor);
496   }
497
498   public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
499   {
500     keyEventPostProcessors.remove(postProcessor);
501   }
502
503   protected List getKeyEventPostProcessors()
504   {
505     return (List) keyEventPostProcessors.clone();
506   }
507
508   public abstract boolean dispatchEvent(AWTEvent e);
509
510   public final void redispatchEvent(Component target, AWTEvent e)
511   {
512     throw new Error("not implemented");
513   }
514
515   public abstract boolean dispatchKeyEvent(KeyEvent e);
516
517   public abstract boolean postProcessKeyEvent(KeyEvent e);
518
519   public abstract void processKeyEvent(Component focused, KeyEvent e);
520
521   protected abstract void enqueueKeyEvents(long after, Component untilFocused);
522
523   protected abstract void dequeueKeyEvents(long after, Component untilFocused);
524
525   protected abstract void discardKeyEvents(Component comp);
526
527   public abstract void focusNextComponent(Component comp);
528
529   public abstract void focusPreviousComponent(Component comp);
530
531   public abstract void upFocusCycle(Component comp);
532
533   public abstract void downFocusCycle(Container cont);
534
535   public final void focusNextComponent()
536   {
537     focusNextComponent(focusOwner);
538   }
539
540   public final void focusPreviousComponent()
541   {
542     focusPreviousComponent(focusOwner);
543   }
544
545   public final void upFocusCycle()
546   {
547     upFocusCycle(focusOwner);
548   }
549
550   public final void downFocusCycle()
551   {
552     if (focusOwner instanceof Container
553         && ((Container) focusOwner).isFocusCycleRoot())
554       downFocusCycle((Container) focusOwner);
555   }
556 } // class KeyboardFocusManager