KeyboardFocusManager.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /* KeyboardFocusManager.java -- manage component focusing via the keyboard
  2. Copyright (C) 2002 Free Software Foundation
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.awt;
  32. import java.awt.event.KeyEvent;
  33. import java.beans.PropertyChangeListener;
  34. import java.beans.PropertyChangeSupport;
  35. import java.beans.PropertyVetoException;
  36. import java.beans.VetoableChangeListener;
  37. import java.beans.VetoableChangeSupport;
  38. import java.util.ArrayList;
  39. import java.util.Collections;
  40. import java.util.HashSet;
  41. import java.util.Iterator;
  42. import java.util.List;
  43. import java.util.Set;
  44. /**
  45. *
  46. * @author Eric Blake <ebb9@email.byu.edu>
  47. * @since 1.4
  48. * @status partially updated to 1.4, needs documentation.
  49. */
  50. public abstract class KeyboardFocusManager
  51. implements KeyEventDispatcher, KeyEventPostProcessor
  52. {
  53. public static final int FORWARD_TRAVERSAL_KEYS = 0;
  54. public static final int BACKWARD_TRAVERSAL_KEYS = 1;
  55. public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
  56. public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
  57. private static final Set DEFAULT_FORWARD_KEYS;
  58. private static final Set DEFAULT_BACKWARD_KEYS;
  59. static
  60. {
  61. Set s = new HashSet();
  62. s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0));
  63. s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
  64. KeyEvent.CTRL_DOWN_MASK));
  65. DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s);
  66. s = new HashSet();
  67. s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
  68. KeyEvent.SHIFT_DOWN_MASK));
  69. s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
  70. KeyEvent.SHIFT_DOWN_MASK
  71. | KeyEvent.CTRL_DOWN_MASK));
  72. DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s);
  73. }
  74. private static KeyboardFocusManager current
  75. = new DefaultKeyboardFocusManager();
  76. // XXX Not implemented correctly. I think a good implementation here may
  77. // be to have permanentFocusOwner be null, and fall back to focusOwner,
  78. // unless a temporary focus change is in effect.
  79. private static Component focusOwner;
  80. private static Component permanentFocusOwner;
  81. private static Window focusedWindow;
  82. private static Window activeWindow;
  83. private static Container focusCycleRoot;
  84. private FocusTraversalPolicy defaultPolicy;
  85. private Set[] defaultFocusKeys = new Set[] {
  86. DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
  87. Collections.EMPTY_SET, Collections.EMPTY_SET
  88. };
  89. private final PropertyChangeSupport propertyChangeSupport
  90. = new PropertyChangeSupport(this);
  91. private final VetoableChangeSupport vetoableChangeSupport
  92. = new VetoableChangeSupport(this);
  93. private final ArrayList keyEventDispatchers = new ArrayList();
  94. private final ArrayList keyEventPostProcessors = new ArrayList();
  95. public KeyboardFocusManager()
  96. {
  97. }
  98. public static KeyboardFocusManager getCurrentKeyboardFocusManager()
  99. {
  100. // XXX Need a way to divide this into contexts.
  101. return current;
  102. }
  103. public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
  104. {
  105. SecurityManager sm = System.getSecurityManager();
  106. if (sm != null)
  107. sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager"));
  108. // XXX Need a way to divide this into contexts.
  109. current = m == null ? new DefaultKeyboardFocusManager() : m;
  110. }
  111. public Component getFocusOwner()
  112. {
  113. // XXX Need an easy way to test if this thread is in the context of the
  114. // global focus owner, to avoid creating the exception in the first place.
  115. try
  116. {
  117. return getGlobalFocusOwner();
  118. }
  119. catch (SecurityException e)
  120. {
  121. return null;
  122. }
  123. }
  124. protected Component getGlobalFocusOwner()
  125. {
  126. // XXX Need a way to test if this thread is in the context of the focus
  127. // owner, and throw a SecurityException if that is the case.
  128. // XXX Implement.
  129. return focusOwner;
  130. }
  131. protected void setGlobalFocusOwner(Component owner)
  132. {
  133. // XXX Should this send focus events to the components involved?
  134. if (owner == null || owner.focusable)
  135. {
  136. firePropertyChange("focusOwner", focusOwner, owner);
  137. try
  138. {
  139. fireVetoableChange("focusOwner", focusOwner, owner);
  140. focusOwner = owner;
  141. }
  142. catch (PropertyVetoException e)
  143. {
  144. }
  145. }
  146. }
  147. public void clearGlobalFocusOwner()
  148. {
  149. // XXX Is this enough?
  150. setGlobalFocusOwner(null);
  151. }
  152. public Component getPermanentFocusOwner()
  153. {
  154. // XXX Need an easy way to test if this thread is in the context of the
  155. // global focus owner, to avoid creating the exception in the first place.
  156. try
  157. {
  158. return getGlobalPermanentFocusOwner();
  159. }
  160. catch (SecurityException e)
  161. {
  162. return null;
  163. }
  164. }
  165. protected Component getGlobalPermanentFocusOwner()
  166. {
  167. // XXX Need a way to test if this thread is in the context of the focus
  168. // owner, and throw a SecurityException if that is the case.
  169. // XXX Implement.
  170. return permanentFocusOwner == null ? focusOwner : permanentFocusOwner;
  171. }
  172. protected void setGlobalPermanentFocusOwner(Component focusOwner)
  173. {
  174. // XXX Should this send focus events to the components involved?
  175. if (focusOwner == null || focusOwner.focusable)
  176. {
  177. firePropertyChange("permanentFocusOwner", permanentFocusOwner,
  178. focusOwner);
  179. try
  180. {
  181. fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
  182. focusOwner);
  183. permanentFocusOwner = focusOwner;
  184. }
  185. catch (PropertyVetoException e)
  186. {
  187. }
  188. }
  189. }
  190. public Window getFocusedWindow()
  191. {
  192. // XXX Need an easy way to test if this thread is in the context of the
  193. // global focus owner, to avoid creating the exception in the first place.
  194. try
  195. {
  196. return getGlobalFocusedWindow();
  197. }
  198. catch (SecurityException e)
  199. {
  200. return null;
  201. }
  202. }
  203. protected Window getGlobalFocusedWindow()
  204. {
  205. // XXX Need a way to test if this thread is in the context of the focus
  206. // owner, and throw a SecurityException if that is the case.
  207. // XXX Implement.
  208. return focusedWindow;
  209. }
  210. protected void setGlobalFocusedWindow(Window window)
  211. {
  212. // XXX Should this send focus events to the windows involved?
  213. if (window == null || window.focusable)
  214. {
  215. firePropertyChange("focusedWindow", focusedWindow, window);
  216. try
  217. {
  218. fireVetoableChange("focusedWindow", focusedWindow, window);
  219. focusedWindow = window;
  220. }
  221. catch (PropertyVetoException e)
  222. {
  223. }
  224. }
  225. }
  226. public Window getActiveWindow()
  227. {
  228. // XXX Need an easy way to test if this thread is in the context of the
  229. // global focus owner, to avoid creating the exception in the first place.
  230. try
  231. {
  232. return getGlobalActiveWindow();
  233. }
  234. catch (SecurityException e)
  235. {
  236. return null;
  237. }
  238. }
  239. protected Window getGlobalActiveWindow()
  240. {
  241. // XXX Need a way to test if this thread is in the context of the focus
  242. // owner, and throw a SecurityException if that is the case.
  243. // XXX Implement.
  244. return activeWindow;
  245. }
  246. protected void setGlobalActiveWindow(Window window)
  247. {
  248. // XXX Should this send focus events to the windows involved?
  249. firePropertyChange("activeWindow", activeWindow, window);
  250. try
  251. {
  252. fireVetoableChange("activeWindow", activeWindow, window);
  253. activeWindow = window;
  254. }
  255. catch (PropertyVetoException e)
  256. {
  257. }
  258. }
  259. public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
  260. {
  261. if (defaultPolicy == null)
  262. defaultPolicy = new DefaultFocusTraversalPolicy();
  263. return defaultPolicy;
  264. }
  265. public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
  266. {
  267. if (policy == null)
  268. throw new IllegalArgumentException();
  269. firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
  270. defaultPolicy = policy;
  271. }
  272. public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
  273. {
  274. if (keystrokes == null)
  275. throw new IllegalArgumentException();
  276. Set sa;
  277. Set sb;
  278. Set sc;
  279. String type;
  280. switch (id)
  281. {
  282. case FORWARD_TRAVERSAL_KEYS:
  283. sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
  284. sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
  285. sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
  286. type = "forwardDefaultFocusTraversalKeys";
  287. break;
  288. case BACKWARD_TRAVERSAL_KEYS:
  289. sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
  290. sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
  291. sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
  292. type = "backwardDefaultFocusTraversalKeys";
  293. break;
  294. case UP_CYCLE_TRAVERSAL_KEYS:
  295. sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
  296. sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
  297. sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS];
  298. type = "upCycleDefaultFocusTraversalKeys";
  299. break;
  300. case DOWN_CYCLE_TRAVERSAL_KEYS:
  301. sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS];
  302. sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS];
  303. sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS];
  304. type = "downCycleDefaultFocusTraversalKeys";
  305. break;
  306. default:
  307. throw new IllegalArgumentException();
  308. }
  309. int i = keystrokes.size();
  310. Iterator iter = keystrokes.iterator();
  311. while (--i >= 0)
  312. {
  313. Object o = iter.next();
  314. if (! (o instanceof AWTKeyStroke)
  315. || sa.contains(o) || sb.contains(o) || sc.contains(o)
  316. || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
  317. throw new IllegalArgumentException();
  318. }
  319. keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
  320. firePropertyChange(type, defaultFocusKeys[id], keystrokes);
  321. defaultFocusKeys[id] = keystrokes;
  322. }
  323. public Set getDefaultFocusTraversalKeys(int id)
  324. {
  325. if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
  326. throw new IllegalArgumentException();
  327. return defaultFocusKeys[id];
  328. }
  329. public Container getCurrentFocusCycleRoot()
  330. {
  331. // XXX Need an easy way to test if this thread is in the context of the
  332. // global focus owner, to avoid creating the exception in the first place.
  333. try
  334. {
  335. return getGlobalCurrentFocusCycleRoot();
  336. }
  337. catch (SecurityException e)
  338. {
  339. return null;
  340. }
  341. }
  342. protected Container getGlobalCurrentFocusCycleRoot()
  343. {
  344. // XXX Need a way to test if this thread is in the context of the focus
  345. // owner, and throw a SecurityException if that is the case.
  346. // XXX Implement.
  347. return focusCycleRoot;
  348. }
  349. protected void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
  350. {
  351. firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
  352. focusCycleRoot = cycleRoot;
  353. }
  354. public void addPropertyChangeListener(PropertyChangeListener l)
  355. {
  356. if (l != null)
  357. propertyChangeSupport.addPropertyChangeListener(l);
  358. }
  359. public void removePropertyChangeListener(PropertyChangeListener l)
  360. {
  361. if (l != null)
  362. propertyChangeSupport.removePropertyChangeListener(l);
  363. }
  364. public PropertyChangeListener[] getPropertyChangeListeners()
  365. {
  366. return propertyChangeSupport.getPropertyChangeListeners();
  367. }
  368. public void addPropertyChangeListener(String name, PropertyChangeListener l)
  369. {
  370. if (l != null)
  371. propertyChangeSupport.addPropertyChangeListener(name, l);
  372. }
  373. public void removePropertyChangeListener(String name,
  374. PropertyChangeListener l)
  375. {
  376. if (l != null)
  377. propertyChangeSupport.removePropertyChangeListener(name, l);
  378. }
  379. public PropertyChangeListener[] getPropertyChangeListeners(String name)
  380. {
  381. return propertyChangeSupport.getPropertyChangeListeners(name);
  382. }
  383. protected void firePropertyChange(String name, Object o, Object n)
  384. {
  385. propertyChangeSupport.firePropertyChange(name, o, n);
  386. }
  387. public void addVetoableChangeListener(VetoableChangeListener l)
  388. {
  389. if (l != null)
  390. vetoableChangeSupport.addVetoableChangeListener(l);
  391. }
  392. public void removeVetoableChangeListener(VetoableChangeListener l)
  393. {
  394. if (l != null)
  395. vetoableChangeSupport.removeVetoableChangeListener(l);
  396. }
  397. public VetoableChangeListener[] getVetoableChangeListeners()
  398. {
  399. return vetoableChangeSupport.getVetoableChangeListeners();
  400. }
  401. public void addVetoableChangeListener(String name, VetoableChangeListener l)
  402. {
  403. if (l != null)
  404. vetoableChangeSupport.addVetoableChangeListener(name, l);
  405. }
  406. public void removeVetoableChangeListener(String name,
  407. VetoableChangeListener l)
  408. {
  409. if (l != null)
  410. vetoableChangeSupport.removeVetoableChangeListener(name, l);
  411. }
  412. public VetoableChangeListener[] getVetoableChangeListeners(String name)
  413. {
  414. return vetoableChangeSupport.getVetoableChangeListeners(name);
  415. }
  416. protected void fireVetoableChange(String name, Object o, Object n)
  417. throws PropertyVetoException
  418. {
  419. vetoableChangeSupport.fireVetoableChange(name, o, n);
  420. }
  421. public void addKeyEventDispatcher(KeyEventDispatcher dispatcher)
  422. {
  423. if (dispatcher != null)
  424. keyEventDispatchers.add(dispatcher);
  425. }
  426. public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher)
  427. {
  428. keyEventDispatchers.remove(dispatcher);
  429. }
  430. protected List getKeyEventDispatchers()
  431. {
  432. return (List) keyEventDispatchers.clone();
  433. }
  434. public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
  435. {
  436. if (postProcessor != null)
  437. keyEventPostProcessors.add(postProcessor);
  438. }
  439. public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
  440. {
  441. keyEventPostProcessors.remove(postProcessor);
  442. }
  443. protected List getKeyEventPostProcessors()
  444. {
  445. return (List) keyEventPostProcessors.clone();
  446. }
  447. public abstract boolean dispatchEvent(AWTEvent e);
  448. public final void redispatchEvent(Component target, AWTEvent e)
  449. {
  450. throw new Error("not implemented");
  451. }
  452. public abstract boolean dispatchKeyEvent(KeyEvent e);
  453. public abstract boolean postProcessKeyEvent(KeyEvent e);
  454. public abstract void processKeyEvent(Component focused, KeyEvent e);
  455. protected abstract void enqueueKeyEvents(long after, Component untilFocused);
  456. protected abstract void dequeueKeyEvents(long after, Component untilFocused);
  457. protected abstract void discardKeyEvents(Component comp);
  458. public abstract void focusNextComponent(Component comp);
  459. public abstract void focusPreviousComponent(Component comp);
  460. public abstract void upFocusCycle(Component comp);
  461. public abstract void downFocusCycle(Container cont);
  462. public final void focusNextComponent()
  463. {
  464. focusNextComponent(focusOwner);
  465. }
  466. public final void focusPreviousComponent()
  467. {
  468. focusPreviousComponent(focusOwner);
  469. }
  470. public final void upFocusCycle()
  471. {
  472. upFocusCycle(focusOwner);
  473. }
  474. public final void downFocusCycle()
  475. {
  476. if (focusOwner instanceof Container
  477. && ((Container) focusOwner).isFocusCycleRoot())
  478. downFocusCycle((Container) focusOwner);
  479. }
  480. } // class KeyboardFocusManager