FSF GCC merge 02/23/03
[official-gcc.git] / libjava / java / awt / KeyboardFocusManager.java
blob867316ba84314a75be7b9eff6e6d43d9c987e343
1 /* KeyboardFocusManager.java -- manage component focusing via the keyboard
2 Copyright (C) 2002 Free Software Foundation
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.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;
54 /**
56 * @author Eric Blake <ebb9@email.byu.edu>
57 * @since 1.4
58 * @status partially updated to 1.4, needs documentation.
60 public abstract class KeyboardFocusManager
61 implements KeyEventDispatcher, KeyEventPostProcessor
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;
68 private static final Set DEFAULT_FORWARD_KEYS;
69 private static final Set DEFAULT_BACKWARD_KEYS;
70 static
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);
86 private static KeyboardFocusManager current
87 = new DefaultKeyboardFocusManager();
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;
95 private static Window focusedWindow;
96 private static Window activeWindow;
97 private static Container focusCycleRoot;
99 private FocusTraversalPolicy defaultPolicy;
100 private Set[] defaultFocusKeys = new Set[] {
101 DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
102 Collections.EMPTY_SET, Collections.EMPTY_SET
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();
113 public KeyboardFocusManager()
117 public static KeyboardFocusManager getCurrentKeyboardFocusManager()
119 // XXX Need a way to divide this into contexts.
120 return current;
123 public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
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;
132 public Component getFocusOwner()
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.
138 return getGlobalFocusOwner();
140 catch (SecurityException e)
142 return null;
146 protected Component getGlobalFocusOwner()
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;
154 protected void setGlobalFocusOwner(Component owner)
156 // XXX Should this send focus events to the components involved?
157 if (owner == null || owner.focusable)
159 firePropertyChange("focusOwner", focusOwner, owner);
162 fireVetoableChange("focusOwner", focusOwner, owner);
163 focusOwner = owner;
165 catch (PropertyVetoException e)
171 public void clearGlobalFocusOwner()
173 // XXX Is this enough?
174 setGlobalFocusOwner(null);
177 public Component getPermanentFocusOwner()
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.
183 return getGlobalPermanentFocusOwner();
185 catch (SecurityException e)
187 return null;
191 protected Component getGlobalPermanentFocusOwner()
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;
199 protected void setGlobalPermanentFocusOwner(Component focusOwner)
201 // XXX Should this send focus events to the components involved?
202 if (focusOwner == null || focusOwner.focusable)
204 firePropertyChange("permanentFocusOwner", permanentFocusOwner,
205 focusOwner);
208 fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
209 focusOwner);
210 permanentFocusOwner = focusOwner;
212 catch (PropertyVetoException e)
218 public Window getFocusedWindow()
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.
224 return getGlobalFocusedWindow();
226 catch (SecurityException e)
228 return null;
232 protected Window getGlobalFocusedWindow()
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;
240 protected void setGlobalFocusedWindow(Window window)
242 // XXX Should this send focus events to the windows involved?
243 if (window == null || window.focusable)
245 firePropertyChange("focusedWindow", focusedWindow, window);
248 fireVetoableChange("focusedWindow", focusedWindow, window);
249 focusedWindow = window;
251 catch (PropertyVetoException e)
257 public Window getActiveWindow()
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.
263 return getGlobalActiveWindow();
265 catch (SecurityException e)
267 return null;
271 protected Window getGlobalActiveWindow()
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;
279 protected void setGlobalActiveWindow(Window window)
281 // XXX Should this send focus events to the windows involved?
282 firePropertyChange("activeWindow", activeWindow, window);
285 fireVetoableChange("activeWindow", activeWindow, window);
286 activeWindow = window;
288 catch (PropertyVetoException e)
293 public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
295 if (defaultPolicy == null)
296 defaultPolicy = new DefaultFocusTraversalPolicy();
297 return defaultPolicy;
300 public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
302 if (policy == null)
303 throw new IllegalArgumentException();
304 firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
305 defaultPolicy = policy;
308 public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
310 if (keystrokes == null)
311 throw new IllegalArgumentException();
312 Set sa;
313 Set sb;
314 Set sc;
315 String type;
316 switch (id)
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();
345 int i = keystrokes.size();
346 Iterator iter = keystrokes.iterator();
347 while (--i >= 0)
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();
355 keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
356 firePropertyChange(type, defaultFocusKeys[id], keystrokes);
357 defaultFocusKeys[id] = keystrokes;
360 public Set getDefaultFocusTraversalKeys(int id)
362 if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
363 throw new IllegalArgumentException();
364 return defaultFocusKeys[id];
367 public Container getCurrentFocusCycleRoot()
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.
373 return getGlobalCurrentFocusCycleRoot();
375 catch (SecurityException e)
377 return null;
381 protected Container getGlobalCurrentFocusCycleRoot()
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;
389 public void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
391 firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
392 focusCycleRoot = cycleRoot;
395 public void addPropertyChangeListener(PropertyChangeListener l)
397 if (l != null)
398 propertyChangeSupport.addPropertyChangeListener(l);
401 public void removePropertyChangeListener(PropertyChangeListener l)
403 if (l != null)
404 propertyChangeSupport.removePropertyChangeListener(l);
407 public PropertyChangeListener[] getPropertyChangeListeners()
409 return propertyChangeSupport.getPropertyChangeListeners();
412 public void addPropertyChangeListener(String name, PropertyChangeListener l)
414 if (l != null)
415 propertyChangeSupport.addPropertyChangeListener(name, l);
418 public void removePropertyChangeListener(String name,
419 PropertyChangeListener l)
421 if (l != null)
422 propertyChangeSupport.removePropertyChangeListener(name, l);
425 public PropertyChangeListener[] getPropertyChangeListeners(String name)
427 return propertyChangeSupport.getPropertyChangeListeners(name);
430 protected void firePropertyChange(String name, Object o, Object n)
432 propertyChangeSupport.firePropertyChange(name, o, n);
435 public void addVetoableChangeListener(VetoableChangeListener l)
437 if (l != null)
438 vetoableChangeSupport.addVetoableChangeListener(l);
441 public void removeVetoableChangeListener(VetoableChangeListener l)
443 if (l != null)
444 vetoableChangeSupport.removeVetoableChangeListener(l);
447 public VetoableChangeListener[] getVetoableChangeListeners()
449 return vetoableChangeSupport.getVetoableChangeListeners();
452 public void addVetoableChangeListener(String name, VetoableChangeListener l)
454 if (l != null)
455 vetoableChangeSupport.addVetoableChangeListener(name, l);
458 public void removeVetoableChangeListener(String name,
459 VetoableChangeListener l)
461 if (l != null)
462 vetoableChangeSupport.removeVetoableChangeListener(name, l);
465 public VetoableChangeListener[] getVetoableChangeListeners(String name)
467 return vetoableChangeSupport.getVetoableChangeListeners(name);
470 protected void fireVetoableChange(String name, Object o, Object n)
471 throws PropertyVetoException
473 vetoableChangeSupport.fireVetoableChange(name, o, n);
476 public void addKeyEventDispatcher(KeyEventDispatcher dispatcher)
478 if (dispatcher != null)
479 keyEventDispatchers.add(dispatcher);
482 public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher)
484 keyEventDispatchers.remove(dispatcher);
487 protected List getKeyEventDispatchers()
489 return (List) keyEventDispatchers.clone();
492 public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
494 if (postProcessor != null)
495 keyEventPostProcessors.add(postProcessor);
498 public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
500 keyEventPostProcessors.remove(postProcessor);
503 protected List getKeyEventPostProcessors()
505 return (List) keyEventPostProcessors.clone();
508 public abstract boolean dispatchEvent(AWTEvent e);
510 public final void redispatchEvent(Component target, AWTEvent e)
512 throw new Error("not implemented");
515 public abstract boolean dispatchKeyEvent(KeyEvent e);
517 public abstract boolean postProcessKeyEvent(KeyEvent e);
519 public abstract void processKeyEvent(Component focused, KeyEvent e);
521 protected abstract void enqueueKeyEvents(long after, Component untilFocused);
523 protected abstract void dequeueKeyEvents(long after, Component untilFocused);
525 protected abstract void discardKeyEvents(Component comp);
527 public abstract void focusNextComponent(Component comp);
529 public abstract void focusPreviousComponent(Component comp);
531 public abstract void upFocusCycle(Component comp);
533 public abstract void downFocusCycle(Container cont);
535 public final void focusNextComponent()
537 focusNextComponent(focusOwner);
540 public final void focusPreviousComponent()
542 focusPreviousComponent(focusOwner);
545 public final void upFocusCycle()
547 upFocusCycle(focusOwner);
550 public final void downFocusCycle()
552 if (focusOwner instanceof Container
553 && ((Container) focusOwner).isFocusCycleRoot())
554 downFocusCycle((Container) focusOwner);
556 } // class KeyboardFocusManager