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(); AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)73 s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)); AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK)74 s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 75 KeyEvent.CTRL_DOWN_MASK)); 76 DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s); 77 s = new HashSet(); AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK)78 s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 79 KeyEvent.SHIFT_DOWN_MASK)); AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_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 KeyboardFocusManager()113 public KeyboardFocusManager() 114 { 115 } 116 getCurrentKeyboardFocusManager()117 public static KeyboardFocusManager getCurrentKeyboardFocusManager() 118 { 119 // XXX Need a way to divide this into contexts. 120 return current; 121 } 122 setCurrentKeyboardFocusManager(KeyboardFocusManager m)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 getFocusOwner()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 getGlobalFocusOwner()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 setGlobalFocusOwner(Component owner)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 clearGlobalFocusOwner()171 public void clearGlobalFocusOwner() 172 { 173 // XXX Is this enough? 174 setGlobalFocusOwner(null); 175 } 176 getPermanentFocusOwner()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 getGlobalPermanentFocusOwner()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 setGlobalPermanentFocusOwner(Component focusOwner)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 getFocusedWindow()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 getGlobalFocusedWindow()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 setGlobalFocusedWindow(Window window)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 getActiveWindow()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 getGlobalActiveWindow()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 setGlobalActiveWindow(Window window)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 getDefaultFocusTraversalPolicy()293 public FocusTraversalPolicy getDefaultFocusTraversalPolicy() 294 { 295 if (defaultPolicy == null) 296 defaultPolicy = new DefaultFocusTraversalPolicy(); 297 return defaultPolicy; 298 } 299 setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)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 setDefaultFocusTraversalKeys(int id, Set keystrokes)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 getDefaultFocusTraversalKeys(int id)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 getCurrentFocusCycleRoot()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 getGlobalCurrentFocusCycleRoot()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 setGlobalCurrentFocusCycleRoot(Container cycleRoot)389 public void setGlobalCurrentFocusCycleRoot(Container cycleRoot) 390 { 391 firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot); 392 focusCycleRoot = cycleRoot; 393 } 394 addPropertyChangeListener(PropertyChangeListener l)395 public void addPropertyChangeListener(PropertyChangeListener l) 396 { 397 if (l != null) 398 propertyChangeSupport.addPropertyChangeListener(l); 399 } 400 removePropertyChangeListener(PropertyChangeListener l)401 public void removePropertyChangeListener(PropertyChangeListener l) 402 { 403 if (l != null) 404 propertyChangeSupport.removePropertyChangeListener(l); 405 } 406 getPropertyChangeListeners()407 public PropertyChangeListener[] getPropertyChangeListeners() 408 { 409 return propertyChangeSupport.getPropertyChangeListeners(); 410 } 411 addPropertyChangeListener(String name, PropertyChangeListener l)412 public void addPropertyChangeListener(String name, PropertyChangeListener l) 413 { 414 if (l != null) 415 propertyChangeSupport.addPropertyChangeListener(name, l); 416 } 417 removePropertyChangeListener(String name, PropertyChangeListener l)418 public void removePropertyChangeListener(String name, 419 PropertyChangeListener l) 420 { 421 if (l != null) 422 propertyChangeSupport.removePropertyChangeListener(name, l); 423 } 424 getPropertyChangeListeners(String name)425 public PropertyChangeListener[] getPropertyChangeListeners(String name) 426 { 427 return propertyChangeSupport.getPropertyChangeListeners(name); 428 } 429 firePropertyChange(String name, Object o, Object n)430 protected void firePropertyChange(String name, Object o, Object n) 431 { 432 propertyChangeSupport.firePropertyChange(name, o, n); 433 } 434 addVetoableChangeListener(VetoableChangeListener l)435 public void addVetoableChangeListener(VetoableChangeListener l) 436 { 437 if (l != null) 438 vetoableChangeSupport.addVetoableChangeListener(l); 439 } 440 removeVetoableChangeListener(VetoableChangeListener l)441 public void removeVetoableChangeListener(VetoableChangeListener l) 442 { 443 if (l != null) 444 vetoableChangeSupport.removeVetoableChangeListener(l); 445 } 446 getVetoableChangeListeners()447 public VetoableChangeListener[] getVetoableChangeListeners() 448 { 449 return vetoableChangeSupport.getVetoableChangeListeners(); 450 } 451 addVetoableChangeListener(String name, VetoableChangeListener l)452 public void addVetoableChangeListener(String name, VetoableChangeListener l) 453 { 454 if (l != null) 455 vetoableChangeSupport.addVetoableChangeListener(name, l); 456 } 457 removeVetoableChangeListener(String name, VetoableChangeListener l)458 public void removeVetoableChangeListener(String name, 459 VetoableChangeListener l) 460 { 461 if (l != null) 462 vetoableChangeSupport.removeVetoableChangeListener(name, l); 463 } 464 getVetoableChangeListeners(String name)465 public VetoableChangeListener[] getVetoableChangeListeners(String name) 466 { 467 return vetoableChangeSupport.getVetoableChangeListeners(name); 468 } 469 fireVetoableChange(String name, Object o, Object n)470 protected void fireVetoableChange(String name, Object o, Object n) 471 throws PropertyVetoException 472 { 473 vetoableChangeSupport.fireVetoableChange(name, o, n); 474 } 475 addKeyEventDispatcher(KeyEventDispatcher dispatcher)476 public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) 477 { 478 if (dispatcher != null) 479 keyEventDispatchers.add(dispatcher); 480 } 481 removeKeyEventDispatcher(KeyEventDispatcher dispatcher)482 public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) 483 { 484 keyEventDispatchers.remove(dispatcher); 485 } 486 getKeyEventDispatchers()487 protected List getKeyEventDispatchers() 488 { 489 return (List) keyEventDispatchers.clone(); 490 } 491 addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)492 public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor) 493 { 494 if (postProcessor != null) 495 keyEventPostProcessors.add(postProcessor); 496 } 497 removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)498 public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor) 499 { 500 keyEventPostProcessors.remove(postProcessor); 501 } 502 getKeyEventPostProcessors()503 protected List getKeyEventPostProcessors() 504 { 505 return (List) keyEventPostProcessors.clone(); 506 } 507 dispatchEvent(AWTEvent e)508 public abstract boolean dispatchEvent(AWTEvent e); 509 redispatchEvent(Component target, AWTEvent e)510 public final void redispatchEvent(Component target, AWTEvent e) 511 { 512 throw new Error("not implemented"); 513 } 514 dispatchKeyEvent(KeyEvent e)515 public abstract boolean dispatchKeyEvent(KeyEvent e); 516 postProcessKeyEvent(KeyEvent e)517 public abstract boolean postProcessKeyEvent(KeyEvent e); 518 processKeyEvent(Component focused, KeyEvent e)519 public abstract void processKeyEvent(Component focused, KeyEvent e); 520 enqueueKeyEvents(long after, Component untilFocused)521 protected abstract void enqueueKeyEvents(long after, Component untilFocused); 522 dequeueKeyEvents(long after, Component untilFocused)523 protected abstract void dequeueKeyEvents(long after, Component untilFocused); 524 discardKeyEvents(Component comp)525 protected abstract void discardKeyEvents(Component comp); 526 focusNextComponent(Component comp)527 public abstract void focusNextComponent(Component comp); 528 focusPreviousComponent(Component comp)529 public abstract void focusPreviousComponent(Component comp); 530 upFocusCycle(Component comp)531 public abstract void upFocusCycle(Component comp); 532 downFocusCycle(Container cont)533 public abstract void downFocusCycle(Container cont); 534 focusNextComponent()535 public final void focusNextComponent() 536 { 537 focusNextComponent(focusOwner); 538 } 539 focusPreviousComponent()540 public final void focusPreviousComponent() 541 { 542 focusPreviousComponent(focusOwner); 543 } 544 upFocusCycle()545 public final void upFocusCycle() 546 { 547 upFocusCycle(focusOwner); 548 } 549 downFocusCycle()550 public final void downFocusCycle() 551 { 552 if (focusOwner instanceof Container 553 && ((Container) focusOwner).isFocusCycleRoot()) 554 downFocusCycle((Container) focusOwner); 555 } 556 } // class KeyboardFocusManager 557