123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- /* KeyboardFocusManager.java -- manage component focusing via the keyboard
- Copyright (C) 2002 Free Software Foundation
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package java.awt;
- import java.awt.event.KeyEvent;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeSupport;
- import java.beans.PropertyVetoException;
- import java.beans.VetoableChangeListener;
- import java.beans.VetoableChangeSupport;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Set;
- /**
- *
- * @author Eric Blake <ebb9@email.byu.edu>
- * @since 1.4
- * @status partially updated to 1.4, needs documentation.
- */
- public abstract class KeyboardFocusManager
- implements KeyEventDispatcher, KeyEventPostProcessor
- {
- public static final int FORWARD_TRAVERSAL_KEYS = 0;
- public static final int BACKWARD_TRAVERSAL_KEYS = 1;
- public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
- public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
- private static final Set DEFAULT_FORWARD_KEYS;
- private static final Set DEFAULT_BACKWARD_KEYS;
- static
- {
- Set s = new HashSet();
- s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0));
- s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
- KeyEvent.CTRL_DOWN_MASK));
- DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s);
- s = new HashSet();
- s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
- KeyEvent.SHIFT_DOWN_MASK));
- s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
- KeyEvent.SHIFT_DOWN_MASK
- | KeyEvent.CTRL_DOWN_MASK));
- DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s);
- }
- private static KeyboardFocusManager current
- = new DefaultKeyboardFocusManager();
- // XXX Not implemented correctly. I think a good implementation here may
- // be to have permanentFocusOwner be null, and fall back to focusOwner,
- // unless a temporary focus change is in effect.
- private static Component focusOwner;
- private static Component permanentFocusOwner;
- private static Window focusedWindow;
- private static Window activeWindow;
- private static Container focusCycleRoot;
- private FocusTraversalPolicy defaultPolicy;
- private Set[] defaultFocusKeys = new Set[] {
- DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
- Collections.EMPTY_SET, Collections.EMPTY_SET
- };
- private final PropertyChangeSupport propertyChangeSupport
- = new PropertyChangeSupport(this);
- private final VetoableChangeSupport vetoableChangeSupport
- = new VetoableChangeSupport(this);
- private final ArrayList keyEventDispatchers = new ArrayList();
- private final ArrayList keyEventPostProcessors = new ArrayList();
- public KeyboardFocusManager()
- {
- }
- public static KeyboardFocusManager getCurrentKeyboardFocusManager()
- {
- // XXX Need a way to divide this into contexts.
- return current;
- }
- public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager"));
- // XXX Need a way to divide this into contexts.
- current = m == null ? new DefaultKeyboardFocusManager() : m;
- }
- public Component getFocusOwner()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalFocusOwner();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
- protected Component getGlobalFocusOwner()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusOwner;
- }
- protected void setGlobalFocusOwner(Component owner)
- {
- // XXX Should this send focus events to the components involved?
- if (owner == null || owner.focusable)
- {
- firePropertyChange("focusOwner", focusOwner, owner);
- try
- {
- fireVetoableChange("focusOwner", focusOwner, owner);
- focusOwner = owner;
- }
- catch (PropertyVetoException e)
- {
- }
- }
- }
- public void clearGlobalFocusOwner()
- {
- // XXX Is this enough?
- setGlobalFocusOwner(null);
- }
- public Component getPermanentFocusOwner()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalPermanentFocusOwner();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
- protected Component getGlobalPermanentFocusOwner()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return permanentFocusOwner == null ? focusOwner : permanentFocusOwner;
- }
- protected void setGlobalPermanentFocusOwner(Component focusOwner)
- {
- // XXX Should this send focus events to the components involved?
- if (focusOwner == null || focusOwner.focusable)
- {
- firePropertyChange("permanentFocusOwner", permanentFocusOwner,
- focusOwner);
- try
- {
- fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
- focusOwner);
- permanentFocusOwner = focusOwner;
- }
- catch (PropertyVetoException e)
- {
- }
- }
- }
- public Window getFocusedWindow()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalFocusedWindow();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
- protected Window getGlobalFocusedWindow()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusedWindow;
- }
- protected void setGlobalFocusedWindow(Window window)
- {
- // XXX Should this send focus events to the windows involved?
- if (window == null || window.focusable)
- {
- firePropertyChange("focusedWindow", focusedWindow, window);
- try
- {
- fireVetoableChange("focusedWindow", focusedWindow, window);
- focusedWindow = window;
- }
- catch (PropertyVetoException e)
- {
- }
- }
- }
- public Window getActiveWindow()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalActiveWindow();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
- protected Window getGlobalActiveWindow()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return activeWindow;
- }
- protected void setGlobalActiveWindow(Window window)
- {
- // XXX Should this send focus events to the windows involved?
- firePropertyChange("activeWindow", activeWindow, window);
- try
- {
- fireVetoableChange("activeWindow", activeWindow, window);
- activeWindow = window;
- }
- catch (PropertyVetoException e)
- {
- }
- }
- public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
- {
- if (defaultPolicy == null)
- defaultPolicy = new DefaultFocusTraversalPolicy();
- return defaultPolicy;
- }
- public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
- {
- if (policy == null)
- throw new IllegalArgumentException();
- firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
- defaultPolicy = policy;
- }
- public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
- {
- if (keystrokes == null)
- throw new IllegalArgumentException();
- Set sa;
- Set sb;
- Set sc;
- String type;
- switch (id)
- {
- case FORWARD_TRAVERSAL_KEYS:
- sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
- sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
- sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
- type = "forwardDefaultFocusTraversalKeys";
- break;
- case BACKWARD_TRAVERSAL_KEYS:
- sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
- sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
- sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
- type = "backwardDefaultFocusTraversalKeys";
- break;
- case UP_CYCLE_TRAVERSAL_KEYS:
- sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
- sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
- sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
- type = "upCycleDefaultFocusTraversalKeys";
- break;
- case DOWN_CYCLE_TRAVERSAL_KEYS:
- sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
- sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
- sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
- type = "downCycleDefaultFocusTraversalKeys";
- break;
- default:
- throw new IllegalArgumentException();
- }
- int i = keystrokes.size();
- Iterator iter = keystrokes.iterator();
- while (--i >= 0)
- {
- Object o = iter.next();
- if (! (o instanceof AWTKeyStroke)
- || sa.contains(o) || sb.contains(o) || sc.contains(o)
- || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
- throw new IllegalArgumentException();
- }
- keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
- firePropertyChange(type, defaultFocusKeys[id], keystrokes);
- defaultFocusKeys[id] = keystrokes;
- }
- public Set getDefaultFocusTraversalKeys(int id)
- {
- if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
- throw new IllegalArgumentException();
- return defaultFocusKeys[id];
- }
- public Container getCurrentFocusCycleRoot()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalCurrentFocusCycleRoot();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
- protected Container getGlobalCurrentFocusCycleRoot()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusCycleRoot;
- }
- protected void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
- {
- firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
- focusCycleRoot = cycleRoot;
- }
- public void addPropertyChangeListener(PropertyChangeListener l)
- {
- if (l != null)
- propertyChangeSupport.addPropertyChangeListener(l);
- }
- public void removePropertyChangeListener(PropertyChangeListener l)
- {
- if (l != null)
- propertyChangeSupport.removePropertyChangeListener(l);
- }
- public PropertyChangeListener[] getPropertyChangeListeners()
- {
- return propertyChangeSupport.getPropertyChangeListeners();
- }
- public void addPropertyChangeListener(String name, PropertyChangeListener l)
- {
- if (l != null)
- propertyChangeSupport.addPropertyChangeListener(name, l);
- }
- public void removePropertyChangeListener(String name,
- PropertyChangeListener l)
- {
- if (l != null)
- propertyChangeSupport.removePropertyChangeListener(name, l);
- }
- public PropertyChangeListener[] getPropertyChangeListeners(String name)
- {
- return propertyChangeSupport.getPropertyChangeListeners(name);
- }
- protected void firePropertyChange(String name, Object o, Object n)
- {
- propertyChangeSupport.firePropertyChange(name, o, n);
- }
- public void addVetoableChangeListener(VetoableChangeListener l)
- {
- if (l != null)
- vetoableChangeSupport.addVetoableChangeListener(l);
- }
- public void removeVetoableChangeListener(VetoableChangeListener l)
- {
- if (l != null)
- vetoableChangeSupport.removeVetoableChangeListener(l);
- }
- public VetoableChangeListener[] getVetoableChangeListeners()
- {
- return vetoableChangeSupport.getVetoableChangeListeners();
- }
- public void addVetoableChangeListener(String name, VetoableChangeListener l)
- {
- if (l != null)
- vetoableChangeSupport.addVetoableChangeListener(name, l);
- }
- public void removeVetoableChangeListener(String name,
- VetoableChangeListener l)
- {
- if (l != null)
- vetoableChangeSupport.removeVetoableChangeListener(name, l);
- }
- public VetoableChangeListener[] getVetoableChangeListeners(String name)
- {
- return vetoableChangeSupport.getVetoableChangeListeners(name);
- }
- protected void fireVetoableChange(String name, Object o, Object n)
- throws PropertyVetoException
- {
- vetoableChangeSupport.fireVetoableChange(name, o, n);
- }
- public void addKeyEventDispatcher(KeyEventDispatcher dispatcher)
- {
- if (dispatcher != null)
- keyEventDispatchers.add(dispatcher);
- }
- public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher)
- {
- keyEventDispatchers.remove(dispatcher);
- }
- protected List getKeyEventDispatchers()
- {
- return (List) keyEventDispatchers.clone();
- }
- public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
- {
- if (postProcessor != null)
- keyEventPostProcessors.add(postProcessor);
- }
- public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
- {
- keyEventPostProcessors.remove(postProcessor);
- }
- protected List getKeyEventPostProcessors()
- {
- return (List) keyEventPostProcessors.clone();
- }
- public abstract boolean dispatchEvent(AWTEvent e);
- public final void redispatchEvent(Component target, AWTEvent e)
- {
- throw new Error("not implemented");
- }
- public abstract boolean dispatchKeyEvent(KeyEvent e);
- public abstract boolean postProcessKeyEvent(KeyEvent e);
- public abstract void processKeyEvent(Component focused, KeyEvent e);
- protected abstract void enqueueKeyEvents(long after, Component untilFocused);
- protected abstract void dequeueKeyEvents(long after, Component untilFocused);
- protected abstract void discardKeyEvents(Component comp);
- public abstract void focusNextComponent(Component comp);
- public abstract void focusPreviousComponent(Component comp);
- public abstract void upFocusCycle(Component comp);
- public abstract void downFocusCycle(Container cont);
- public final void focusNextComponent()
- {
- focusNextComponent(focusOwner);
- }
- public final void focusPreviousComponent()
- {
- focusPreviousComponent(focusOwner);
- }
- public final void upFocusCycle()
- {
- upFocusCycle(focusOwner);
- }
- public final void downFocusCycle()
- {
- if (focusOwner instanceof Container
- && ((Container) focusOwner).isFocusCycleRoot())
- downFocusCycle((Container) focusOwner);
- }
- } // class KeyboardFocusManager
|