001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.awt;
019:
020: import java.awt.event.FocusEvent;
021: import java.awt.event.InputEvent;
022: import java.awt.event.KeyEvent;
023: import java.awt.event.WindowEvent;
024: import java.beans.PropertyChangeListener;
025: import java.beans.PropertyChangeSupport;
026: import java.beans.PropertyVetoException;
027: import java.beans.VetoableChangeListener;
028: import java.beans.VetoableChangeSupport;
029: import java.util.ArrayList;
030: import java.util.Collections;
031: import java.util.LinkedHashSet;
032: import java.util.List;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.Vector;
036:
037: import org.apache.harmony.awt.internal.nls.Messages;
038:
039: public abstract class KeyboardFocusManager implements
040: KeyEventDispatcher, KeyEventPostProcessor {
041: public static final int FORWARD_TRAVERSAL_KEYS = 0;
042:
043: public static final int BACKWARD_TRAVERSAL_KEYS = 1;
044:
045: public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
046:
047: public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
048:
049: final static int[] compTraversalIDs = { FORWARD_TRAVERSAL_KEYS,
050: BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS };
051:
052: final static int[] contTraversalIDs = { FORWARD_TRAVERSAL_KEYS,
053: BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS,
054: DOWN_CYCLE_TRAVERSAL_KEYS };
055:
056: private FocusTraversalPolicy defaultFocusTraversalPolicy = new DefaultFocusTraversalPolicy();
057:
058: // focus state is static, i. e. 1 per class loader:
059: static Component focusOwner;
060:
061: static Component actualFocusOwner;
062:
063: private static Component actualPrevFocusOwner;
064:
065: private static Component permanentFocusOwner;
066:
067: private static Container currentFocusCycleRoot;
068:
069: static Window activeWindow;
070:
071: private static Window actualActiveWindow;
072:
073: static Window focusedWindow;
074:
075: static Window actualFocusedWindow;
076:
077: static final Set<AWTKeyStroke> DEFAULT_FWD_KS;
078:
079: static final Set<AWTKeyStroke> DEFAULT_BWD_KS;
080:
081: static final Set<AWTKeyStroke> EMPTY_UNMOD_SET;
082:
083: static final String TK_NAMES[] = {
084: "forwardDefaultFocusTraversalKeys", //$NON-NLS-1$
085: "backwardDefaultFocusTraversalKeys", //$NON-NLS-1$
086: "upCycleDefaultFocusTraversalKeys", //$NON-NLS-1$
087: "downCycleDefaultFocusTraversalKeys" }; //$NON-NLS-1$
088:
089: private static Window prevFocusedWindow;
090:
091: private final Vector<KeyEventDispatcher> keyEventDispatchers = new Vector<KeyEventDispatcher>();
092:
093: private final Vector<KeyEventPostProcessor> keyEventPostProcessors = new Vector<KeyEventPostProcessor>();
094:
095: private PropertyChangeSupport propertyChangeSupport;
096:
097: private VetoableChangeSupport vetoableChangeSupport;
098:
099: private final Set<AWTKeyStroke>[] traversalKeys;
100:
101: static {
102: Set<AWTKeyStroke> s = Collections.emptySet();
103:
104: EMPTY_UNMOD_SET = Collections.unmodifiableSet(s);
105:
106: s = new LinkedHashSet<AWTKeyStroke>();
107: s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0));
108: s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
109: InputEvent.CTRL_DOWN_MASK));
110: DEFAULT_FWD_KS = Collections.unmodifiableSet(s);
111:
112: s = new LinkedHashSet<AWTKeyStroke>();
113: s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
114: InputEvent.SHIFT_DOWN_MASK));
115: s
116: .add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
117: InputEvent.SHIFT_DOWN_MASK
118: | InputEvent.CTRL_DOWN_MASK));
119: DEFAULT_BWD_KS = Collections.unmodifiableSet(s);
120: }
121:
122: public KeyboardFocusManager() {
123: traversalKeys = new Set[4];
124: traversalKeys[0] = DEFAULT_FWD_KS;
125: traversalKeys[1] = DEFAULT_BWD_KS;
126: traversalKeys[2] = EMPTY_UNMOD_SET;
127: traversalKeys[3] = EMPTY_UNMOD_SET;
128: }
129:
130: public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) {
131: keyEventDispatchers.add(dispatcher);
132: }
133:
134: public void addKeyEventPostProcessor(KeyEventPostProcessor processor) {
135: keyEventPostProcessors.add(processor);
136: }
137:
138: public void addPropertyChangeListener(String propertyName,
139: PropertyChangeListener listener) {
140: getPropertyChangeSupport().addPropertyChangeListener(
141: propertyName, listener);
142: }
143:
144: public void addPropertyChangeListener(
145: PropertyChangeListener listener) {
146: getPropertyChangeSupport().addPropertyChangeListener(listener);
147: }
148:
149: public void addVetoableChangeListener(
150: VetoableChangeListener listener) {
151: getVetoableChangeSupport().addVetoableChangeListener(listener);
152: }
153:
154: public void addVetoableChangeListener(String propertyName,
155: VetoableChangeListener listener) {
156: getVetoableChangeSupport().addVetoableChangeListener(
157: propertyName, listener);
158: }
159:
160: public void clearGlobalFocusOwner() {
161: if (focusOwner != null) {
162: setFocus(focusOwner, focusOwner.getWindowAncestor(), false,
163: null, false, true);
164: }
165: }
166:
167: protected abstract void dequeueKeyEvents(long a0, Component a1);
168:
169: protected abstract void discardKeyEvents(Component a0);
170:
171: public abstract boolean dispatchEvent(AWTEvent a0);
172:
173: public abstract boolean dispatchKeyEvent(KeyEvent a0);
174:
175: public final void downFocusCycle() {
176: if (focusOwner instanceof Container) {
177: Container root = (Container) focusOwner;
178: downFocusCycle(root);
179: }
180: }
181:
182: public abstract void downFocusCycle(Container a0);
183:
184: protected abstract void enqueueKeyEvents(long a0, Component a1);
185:
186: protected void firePropertyChange(String propertyName,
187: Object oldValue, Object newValue) {
188: getPropertyChangeSupport().firePropertyChange(propertyName,
189: oldValue, newValue);
190: }
191:
192: protected void fireVetoableChange(String propertyName,
193: Object oldValue, Object newValue)
194: throws PropertyVetoException {
195: getVetoableChangeSupport().fireVetoableChange(propertyName,
196: oldValue, newValue);
197: }
198:
199: public final void focusNextComponent() {
200: focusNextComponent(getFocusOwner());
201: }
202:
203: public abstract void focusNextComponent(Component a0);
204:
205: public final void focusPreviousComponent() {
206: focusPreviousComponent(getFocusOwner());
207: }
208:
209: public abstract void focusPreviousComponent(Component a0);
210:
211: public Window getActiveWindow() {
212: return activeWindow;
213: }
214:
215: public Container getCurrentFocusCycleRoot() {
216: return currentFocusCycleRoot;
217: }
218:
219: public static KeyboardFocusManager getCurrentKeyboardFocusManager() {
220: final Toolkit toolkit = Toolkit.getDefaultToolkit();
221: toolkit.lockAWT();
222: try {
223: if (toolkit.currentKeyboardFocusManager == null) {
224: setCurrentKeyboardFocusManager(null);
225: }
226: return toolkit.currentKeyboardFocusManager;
227: } finally {
228: toolkit.unlockAWT();
229: }
230: }
231:
232: @SuppressWarnings("unchecked")
233: public Set<AWTKeyStroke> getDefaultFocusTraversalKeys(int id) {
234: checkTraversalKeyId(id, 3);
235:
236: return traversalKeys[id];
237: }
238:
239: public FocusTraversalPolicy getDefaultFocusTraversalPolicy() {
240: return defaultFocusTraversalPolicy;
241: }
242:
243: public Component getFocusOwner() {
244: return focusOwner;
245: }
246:
247: public Window getFocusedWindow() {
248: return focusedWindow;
249: }
250:
251: protected Window getGlobalActiveWindow() throws SecurityException {
252: checkInstance();
253: // TODO: get global active window somehow
254: // (not the active window from the current class loader)
255: return activeWindow;
256: }
257:
258: protected Container getGlobalCurrentFocusCycleRoot()
259: throws SecurityException {
260: checkInstance();
261: // TODO: get global current focus cycle root somehow
262: // (not from the current class loader)
263: return currentFocusCycleRoot;
264: }
265:
266: protected Component getGlobalFocusOwner() throws SecurityException {
267: checkInstance();
268: // TODO: get global focus owner somehow
269: // (not from the current class loader)
270: return focusOwner;
271: }
272:
273: /**
274: * This method will throw a SecurityException if this KeyboardFocusManager
275: * is not the current KeyboardFocusManager for the calling thread's context.
276: *
277: * @throws SecurityException
278: */
279: private void checkInstance() throws SecurityException {
280: if (getCurrentKeyboardFocusManager() != this ) {
281: // awt.7C=this KeyboardFocusManager is not installed in the current thread's context
282: throw new SecurityException(Messages.getString("awt.7C")); //$NON-NLS-1$
283: }
284: }
285:
286: protected Window getGlobalFocusedWindow() throws SecurityException {
287: checkInstance();
288: // TODO: get global focused window somehow
289: // (not from the current class loader)
290: return focusedWindow;
291: }
292:
293: protected Component getGlobalPermanentFocusOwner()
294: throws SecurityException {
295: checkInstance();
296: // TODO: get global permanent focus owner somehow
297: // (not from the current class loader)
298: return permanentFocusOwner;
299: }
300:
301: protected List<KeyEventDispatcher> getKeyEventDispatchers() {
302: return new ArrayList<KeyEventDispatcher>(keyEventDispatchers);
303: }
304:
305: protected List<KeyEventPostProcessor> getKeyEventPostProcessors() {
306: return new ArrayList<KeyEventPostProcessor>(
307: keyEventPostProcessors);
308: }
309:
310: public Component getPermanentFocusOwner() {
311: // TODO: return null if the permanent focus owner is not a member of the
312: // calling thread's context
313: return permanentFocusOwner;
314: }
315:
316: public PropertyChangeListener[] getPropertyChangeListeners() {
317: return getPropertyChangeSupport().getPropertyChangeListeners();
318: }
319:
320: public PropertyChangeListener[] getPropertyChangeListeners(
321: String propertyName) {
322: return getPropertyChangeSupport().getPropertyChangeListeners(
323: propertyName);
324: }
325:
326: public VetoableChangeListener[] getVetoableChangeListeners(
327: String propertyName) {
328: return getVetoableChangeSupport().getVetoableChangeListeners(
329: propertyName);
330: }
331:
332: public VetoableChangeListener[] getVetoableChangeListeners() {
333: return getVetoableChangeSupport().getVetoableChangeListeners();
334: }
335:
336: public abstract boolean postProcessKeyEvent(KeyEvent a0);
337:
338: public abstract void processKeyEvent(Component a0, KeyEvent a1);
339:
340: public final void redispatchEvent(Component target, AWTEvent e) {
341: e.dispatchedByKFM = true;
342: target.dispatchEvent(e);
343: }
344:
345: public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) {
346: keyEventDispatchers.remove(dispatcher);
347: }
348:
349: public void removeKeyEventPostProcessor(
350: KeyEventPostProcessor processor) {
351: keyEventPostProcessors.remove(processor);
352: }
353:
354: public void removePropertyChangeListener(String propertyName,
355: PropertyChangeListener listener) {
356: getPropertyChangeSupport().removePropertyChangeListener(
357: propertyName, listener);
358: }
359:
360: public void removePropertyChangeListener(
361: PropertyChangeListener listener) {
362: getPropertyChangeSupport().removePropertyChangeListener(
363: listener);
364: }
365:
366: public void removeVetoableChangeListener(
367: VetoableChangeListener listener) {
368: getVetoableChangeSupport().removeVetoableChangeListener(
369: listener);
370: }
371:
372: public void removeVetoableChangeListener(String propertyName,
373: VetoableChangeListener listener) {
374: getVetoableChangeSupport().removeVetoableChangeListener(
375: propertyName, listener);
376: }
377:
378: public static void setCurrentKeyboardFocusManager(
379: KeyboardFocusManager newManager) throws SecurityException {
380: KeyboardFocusManager oldManager;
381: final Toolkit toolkit = Toolkit.getDefaultToolkit();
382: toolkit.lockAWT();
383: try {
384: SecurityManager secMan = System.getSecurityManager();
385: String permission = "replaceKeyboardFocusManager"; //$NON-NLS-1$
386: if (secMan != null) {
387: secMan.checkPermission(new AWTPermission(permission));
388: }
389: oldManager = toolkit.currentKeyboardFocusManager;
390: toolkit.currentKeyboardFocusManager = ((newManager != null) ? newManager
391: : new DefaultKeyboardFocusManager());
392: } finally {
393: toolkit.unlockAWT();
394: }
395: if (oldManager == newManager) {
396: return;
397: }
398: String propName = "managingFocus"; //$NON-NLS-1$
399: if (oldManager != null) {
400: oldManager.firePropertyChange(propName, Boolean.TRUE,
401: Boolean.FALSE);
402: }
403: newManager.firePropertyChange(propName, Boolean.FALSE,
404: Boolean.TRUE);
405: }
406:
407: public void setDefaultFocusTraversalKeys(int id,
408: Set<? extends AWTKeyStroke> keystrokes) {
409: final Set<AWTKeyStroke> old;
410:
411: checkTraversalKeyId(id, 3);
412:
413: if (keystrokes == null) {
414: throw new IllegalArgumentException(Messages.getString(
415: "awt.01", "keystrokes")); //$NON-NLS-1$ //$NON-NLS-2$
416: }
417:
418: old = traversalKeys[id];
419: setFocusTraversalKeys(id, keystrokes, traversalKeys);
420: firePropertyChange(TK_NAMES[id], old, keystrokes);
421: }
422:
423: public void setDefaultFocusTraversalPolicy(
424: FocusTraversalPolicy defaultPolicy) {
425: if (defaultPolicy == null) {
426: // awt.77=default focus traversal policy cannot be null
427: throw new IllegalArgumentException(Messages
428: .getString("awt.77")); //$NON-NLS-1$
429: }
430: FocusTraversalPolicy oldPolicy = defaultFocusTraversalPolicy;
431: defaultFocusTraversalPolicy = defaultPolicy;
432: firePropertyChange("defaultFocusTraversalPolicy", oldPolicy, //$NON-NLS-1$
433: defaultFocusTraversalPolicy);
434: }
435:
436: protected void setGlobalActiveWindow(Window activeWindow) {
437: String propName = "activeWindow"; //$NON-NLS-1$
438: // fire Vetoable change[before it is reflected in Java focus state],
439: // catch veto exception
440: try {
441: fireVetoableChange(propName,
442: KeyboardFocusManager.activeWindow, activeWindow);
443: } catch (PropertyVetoException e) {
444: // abort the change, i. e.
445: // don't reflect the change in KFM, don't report to property change
446: // listeners
447: return;
448: }
449: Window oldActiveWindow = KeyboardFocusManager.activeWindow;
450: KeyboardFocusManager.activeWindow = activeWindow;
451: firePropertyChange(propName, oldActiveWindow,
452: KeyboardFocusManager.activeWindow);
453: }
454:
455: public void setGlobalCurrentFocusCycleRoot(
456: Container newFocusCycleRoot) {
457: Container oldFocusCycleRoot = currentFocusCycleRoot;
458: currentFocusCycleRoot = newFocusCycleRoot;
459: firePropertyChange(
460: "currentFocusCycleRoot", oldFocusCycleRoot, currentFocusCycleRoot); //$NON-NLS-1$
461: }
462:
463: protected void setGlobalFocusOwner(Component focusOwner) {
464: String propName = "focusOwner"; //$NON-NLS-1$
465: // fire Vetoable change[before it is reflected in Java focus state],
466: // catch veto exception
467: try {
468: fireVetoableChange(propName,
469: KeyboardFocusManager.focusOwner, focusOwner);
470: } catch (PropertyVetoException e) {
471: // abort the change, i. e.
472: // don't reflect the change in KFM, don't report to property change
473: // listeners
474: return;
475: }
476: Component oldFocusOwner = KeyboardFocusManager.focusOwner;
477: if ((focusOwner == null) || focusOwner.isFocusable()) {
478: KeyboardFocusManager.focusOwner = focusOwner;
479: if ((focusOwner != null)
480: && focusOwner != getCurrentFocusCycleRoot()) {
481: //don't clear current focus cycle root every time a component
482: //is losing focus
483: //TODO: do it[clear] somewhere else(maybe Window.dispose()??)
484: Container root = ((focusOwner instanceof Window) ? (Window) focusOwner
485: : focusOwner.getFocusCycleRootAncestor());
486: if (root == null || root.isFocusCycleRoot()) {
487: setGlobalCurrentFocusCycleRoot(root);
488: }
489: }
490: }
491: firePropertyChange(propName, oldFocusOwner,
492: KeyboardFocusManager.focusOwner);
493: }
494:
495: protected void setGlobalFocusedWindow(Window focusedWindow) {
496: String propName = "focusedWindow"; //$NON-NLS-1$
497: // fire Vetoable change[before it is reflected in Java focus state],
498: // catch veto exception
499: try {
500: fireVetoableChange(propName,
501: KeyboardFocusManager.focusedWindow, focusedWindow);
502: } catch (PropertyVetoException e) {
503: // abort the change, i. e.
504: // don't reflect the change in KFM, don't report to property change
505: // listeners
506: return;
507: }
508: Window oldFocusedWindow = KeyboardFocusManager.focusedWindow;
509: if (focusedWindow == null || focusedWindow.isFocusableWindow()) {
510: KeyboardFocusManager.focusedWindow = focusedWindow;
511: }
512: firePropertyChange(propName, oldFocusedWindow,
513: KeyboardFocusManager.focusedWindow);
514: }
515:
516: protected void setGlobalPermanentFocusOwner(
517: Component permanentFocusOwner) {
518: String propName = "permanentFocusOwner"; //$NON-NLS-1$
519: // fire Vetoable change[before it is reflected in Java focus state],
520: // catch veto exception
521: try {
522: fireVetoableChange(propName,
523: KeyboardFocusManager.permanentFocusOwner,
524: permanentFocusOwner);
525: } catch (PropertyVetoException e) {
526: // abort the change, i. e.
527: // don't reflect the change in KFM,
528: // don't report to property change listeners
529: return;
530: }
531: Component oldPermanentFocusOwner = KeyboardFocusManager.permanentFocusOwner;
532: if ((permanentFocusOwner == null)
533: || permanentFocusOwner.isFocusable()) {
534: KeyboardFocusManager.permanentFocusOwner = permanentFocusOwner;
535: setGlobalFocusOwner(permanentFocusOwner);
536: }
537: firePropertyChange(propName, oldPermanentFocusOwner,
538: KeyboardFocusManager.permanentFocusOwner);
539: }
540:
541: public final void upFocusCycle() {
542: upFocusCycle(getFocusOwner());
543: }
544:
545: public abstract void upFocusCycle(Component a0);
546:
547: static void checkTraversalKeysID(Map<?, ?> keysMap, Integer id) {
548: if (!keysMap.containsKey(id)) {
549: // awt.78=invalid focus traversal key identifier
550: throw new IllegalArgumentException(Messages
551: .getString("awt.78")); //$NON-NLS-1$
552: }
553: }
554:
555: static void checkKeyStrokes(int[] traversalIDs,
556: Map<Integer, Set<? extends AWTKeyStroke>> traversalKeys,
557: Integer kId, Set<? extends AWTKeyStroke> keystrokes) {
558: if (keystrokes == null || keystrokes.isEmpty()) {
559: return;
560: }
561: for (AWTKeyStroke key : keystrokes) {
562: if (key == null) {
563: // awt.79=cannot set null focus traversal key
564: throw new IllegalArgumentException(Messages
565: .getString("awt.79")); //$NON-NLS-1$
566: } // actually throw ClassCastException ??
567: if (key.getKeyEventType() == KeyEvent.KEY_TYPED) {
568: // awt.7A=focus traversal keys cannot map to KEY_TYPED events
569: throw new IllegalArgumentException(Messages
570: .getString("awt.7A")); //$NON-NLS-1$
571: }
572: // throw exception if such a KeyStroke is already present for
573: // another id
574: for (int element : traversalIDs) {
575: Integer theID = Integer.valueOf(element);
576: Set<? extends AWTKeyStroke> val = traversalKeys
577: .get(theID);
578: if ((!theID.equals(kId)) && val != null
579: && val.contains(key)) {
580: // awt.7B=focus traversal keys must be unique for a Component
581: throw new IllegalArgumentException(Messages
582: .getString("awt.7B")); //$NON-NLS-1$
583: }
584: }
585: }
586: }
587:
588: static void checkTraversalKeyId(final int id, final int maxValue) {
589: if ((id < 0) || (id > maxValue)) {
590: // awt.78=invalid focus traversal key identifier
591: throw new IllegalArgumentException(Messages
592: .getString("awt.78")); //$NON-NLS-1$
593: }
594: }
595:
596: static void setFocusTraversalKeys(final int id,
597: final Set<? extends AWTKeyStroke> keystrokes,
598: final Set<AWTKeyStroke>[] traversalKeys) {
599: for (AWTKeyStroke ks : keystrokes) {
600: if (ks == null) {
601: // awt.79=cannot set null focus traversal key
602: throw new IllegalArgumentException(Messages
603: .getString("awt.79")); //$NON-NLS-1$
604: }
605:
606: if (ks.getKeyEventType() == KeyEvent.KEY_TYPED) {
607: // awt.7A=focus traversal keys cannot map to KEY_TYPED
608: // events
609: throw new IllegalArgumentException(Messages
610: .getString("awt.7A")); //$NON-NLS-1$
611: }
612:
613: for (int i = 0; i < traversalKeys.length; i++) {
614: if ((i != id) && traversalKeys[i].contains(ks)) {
615: // awt.7B=focus traversal keys must be unique for a
616: // Component
617: throw new IllegalArgumentException(Messages
618: .getString("awt.7B")); //$NON-NLS-1$
619: }
620: }
621: }
622:
623: traversalKeys[id] = Collections.unmodifiableSet(keystrokes);
624: }
625:
626: boolean requestFocus(Component c, boolean temporary,
627: boolean crossWindow, boolean callCB) {
628: Window wnd = ((c != null) ? c.getWindowAncestor() : null);
629: return requestFocus(c, wnd, temporary, crossWindow, callCB);
630: }
631:
632: /**
633: * internal "requestFocus": posts all necessary Focus & focus-related Window
634: * events to eventQueue and updates internal focus state. When called from
635: * Component's request focus callCB is set to true, when called directly
636: * from native event dispatching code - to false.
637: */
638: boolean requestFocus(Component c, Window wnd, boolean temporary,
639: boolean crossWindow, boolean callCB) {
640: Window focusedWnd = actualFocusedWindow;
641: Window activeWnd = actualActiveWindow;
642: // don't take focus from other applications:
643: // change active window from null only if native
644: // event is received(i. e. callCB is false)
645: if (callCB && activeWnd == null) {
646: if (crossWindow && (wnd != null) && (c != null)) {
647: // remember the request to grant it when
648: // window is later focused by the user
649: wnd.setRequestedFocus(c);
650: }
651: return false;
652: }
653: if (callCB && !checkWindow(wnd)) {
654: return false;
655: }
656: setFocus(actualFocusOwner, wnd, false, c, temporary, callCB);
657: // in case of cross-window focus transfer
658: // remember that this component had requested focus in that window
659: if (crossWindow && (focusedWnd != wnd)) {
660: wnd.setRequestedFocus(c);
661: wnd.behaviour.setFocus(true, focusedWnd); // try to change
662: // focusedWindow(?)
663: }
664: // if (!wnd.isFocused()) {
665: // return false; //async focus - wait until window actually gains
666: // // focus
667: // }
668: wnd.setRequestedFocus(c);
669: setFocus(c, wnd, true, actualPrevFocusOwner, temporary, callCB);
670: if (wnd != null) {
671: wnd.setFocusOwner(c);
672: wnd.setRequestedFocus(null);
673: }
674: return true;
675: }
676:
677: /**
678: * Perform additional checks to determine if a Window can
679: * become focused
680: * @param wnd
681: * @return
682: */
683: private boolean checkWindow(Window wnd) {
684: if (wnd == null) {
685: return false;
686: }
687: if (wnd instanceof EmbeddedWindow) {
688: // TODO: query state of EmbeddedWindow's owner
689: return true;
690: }
691: // FIXME: explicitly deny focus requests for components
692: // inside iconified/shaded windows:
693: if ((getOwningFrame(wnd).getExtendedState() & Frame.ICONIFIED) != 0) {
694: return false;
695: }
696: return true;
697: }
698:
699: Frame getOwningFrame(Window w) {
700: Window wnd;
701: for (wnd = w; (wnd != null) && !(wnd instanceof Frame); wnd = wnd
702: .getOwner()) {
703: ;
704: }
705: return (Frame) wnd;
706: }
707:
708: /**
709: * all focus related events are posted to EventQueue and internal(non-Java)
710: * focus state is updated to be able to post some events correctly As
711: * opposed to focus spec user-defined KeyboardFocusManager doesn't
712: * have to take care about proper event ordering: events are posted in
713: * proper order
714: */
715: void setFocus(Component c, Window wnd, boolean focus,
716: Component opposite, boolean temporary, boolean callCB) {
717: Window focusedWnd = actualFocusedWindow;
718: Window oppositeAncestorWnd = ((opposite != null) ? opposite
719: .getWindowAncestor() : (focus ? focusedWnd : null));
720: Window ancestorWnd = (!focus ? focusedWnd : wnd);
721: if (!focus && (ancestorWnd == null)) {
722: ancestorWnd = actualActiveWindow;
723: }
724: if (focus) {
725: postWindowEvent(ancestorWnd, oppositeAncestorWnd, focus);
726: }
727: if (c != null) {
728: // when losing focus to some component in other window
729: // post temporary event:
730: if (!focus && (opposite != null) && !callCB) {
731: temporary = (c.getWindowAncestor() != opposite
732: .getWindowAncestor());
733: }
734: FocusEvent newEvent = new FocusEvent(c,
735: focus ? FocusEvent.FOCUS_GAINED
736: : FocusEvent.FOCUS_LOST, temporary,
737: opposite);
738: // remember previous focus owner to be able to post it as opposite
739: // later
740: // [when opposite component gains focus]
741: // but clear it if application loses focus
742: if (!focus) {
743: actualPrevFocusOwner = ((opposite != null) ? actualFocusOwner
744: : null);
745: }
746: actualFocusOwner = (focus ? c
747: : ((c == actualFocusOwner) ? null
748: : actualFocusOwner));
749: c.postEvent(newEvent);
750: }
751: // post window events when losing focus only if
752: // there's opposite component or
753: // events come from native layer[if opposite is null],
754: // i. e. don't post them if called from clearGlobalFocusOwner()
755: if (!focus && ((opposite != null) || !callCB)) {
756: prevFocusedWindow = (c == null ? actualFocusedWindow : null);
757: postWindowEvent(ancestorWnd, oppositeAncestorWnd, focus);
758: }
759: if (focus && callCB) {
760: c.behaviour.setFocus(focus, opposite);
761: }
762: }
763:
764: /**
765: * set focus to the appropriate child Component of the given Window
766: * as if it is the focused Window
767: */
768: boolean requestFocusInWindow(Window wnd, boolean callCB) {
769: if (wnd == null) {
770: return false;
771: }
772: Component lastReqFocus = wnd.getRequestedFocus();
773: if ((lastReqFocus != null)
774: && (lastReqFocus.getWindowAncestor() != wnd)) {
775: lastReqFocus = null;
776: wnd.setRequestedFocus(null);
777: }
778: Component lastFocusOwner = wnd.getMostRecentFocusOwner();
779: if ((lastFocusOwner != null)
780: && lastFocusOwner.getWindowAncestor() != wnd) {
781: lastFocusOwner = null;
782: }
783: Component compToFocus = ((lastReqFocus != null) ? lastReqFocus
784: : lastFocusOwner);
785: if (compToFocus != null) {
786: return requestFocus(compToFocus, wnd, false, false, callCB);
787: }
788: // even if there's no component to focus
789: // we can try to focus window itself
790: return requestFocus(wnd, wnd, false, false, callCB);
791: }
792:
793: /**
794: * all focus related WindowEvents are posted to EventQueue
795: * and internal(non-Java) focus state is immediately updated
796: * (Java focus state is updated only right before actually
797: * dispatching these events to components)
798: * Activation events are also posted from here, so
799: * KeyboardFocusManager(if replaced by user) doesn't have to care about
800: * "synthesizing" them, as opposed to focus spec.
801: * @return - true if focused Window changed
802: */
803: boolean postWindowEvent(Window wnd, Window opposite, boolean focus) {
804: Window focusedWnd = actualFocusedWindow;
805: Window decorWnd = ((wnd != null) ? wnd.getFrameDialogOwner()
806: : null);
807: int focusEventId = (focus ? WindowEvent.WINDOW_GAINED_FOCUS
808: : WindowEvent.WINDOW_LOST_FOCUS);
809: int activationEventId = (focus ? WindowEvent.WINDOW_ACTIVATED
810: : WindowEvent.WINDOW_DEACTIVATED);
811: if ((opposite == null) && (prevFocusedWindow != null)) {
812: opposite = prevFocusedWindow;
813: }
814: Window oppositeDecorWnd = ((opposite != null) ? opposite
815: .getFrameDialogOwner() : null);
816: boolean focusedWindowChanged = ((wnd != null) && (focus ? focusedWnd != wnd
817: : opposite != wnd));
818: boolean activeWindowChanged = ((decorWnd != null) && (focus ? actualActiveWindow != decorWnd
819: : oppositeDecorWnd != decorWnd));
820: WindowEvent activationEvent = (activeWindowChanged ? new WindowEvent(
821: decorWnd, activationEventId, oppositeDecorWnd)
822: : null);
823: if (activeWindowChanged && focus) {
824: decorWnd.postEvent(activationEvent);
825: actualActiveWindow = decorWnd;
826: }
827: if (focusedWindowChanged) {
828: wnd.postEvent(new WindowEvent(wnd, focusEventId, opposite));
829: actualFocusedWindow = (focus ? wnd : null);
830: }
831: if (activeWindowChanged && !focus) {
832: decorWnd.postEvent(activationEvent);
833: actualActiveWindow = null;
834: }
835: return focusedWindowChanged;
836: }
837:
838: private PropertyChangeSupport getPropertyChangeSupport() {
839: if (propertyChangeSupport == null) {
840: propertyChangeSupport = new PropertyChangeSupport(this );
841: }
842: return propertyChangeSupport;
843: }
844:
845: private VetoableChangeSupport getVetoableChangeSupport() {
846: if (vetoableChangeSupport == null) {
847: vetoableChangeSupport = new VetoableChangeSupport(this);
848: }
849: return vetoableChangeSupport;
850: }
851: }
|