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: * @author Alexander T. Simbirtsev
019: * @version $Revision$
020: */package javax.swing.plaf.basic;
021:
022: import java.awt.Component;
023: import java.awt.KeyboardFocusManager;
024: import java.awt.event.KeyEvent;
025: import java.awt.event.KeyListener;
026:
027: import javax.swing.JPopupMenu;
028: import javax.swing.JRootPane;
029: import javax.swing.MenuElement;
030: import javax.swing.MenuSelectionManager;
031: import javax.swing.SwingUtilities;
032: import javax.swing.event.ChangeEvent;
033: import javax.swing.event.ChangeListener;
034:
035: import org.apache.harmony.x.swing.Utilities;
036:
037: class RootPaneFocusHandler implements ChangeListener {
038: private static RootPaneFocusHandler sharedInstance;
039: private static int numInstallations;
040: private static Component previousFocusOwner;
041: private static Component focusedRootPane;
042:
043: private KeyListener rootPaneKeyListener;
044:
045: private RootPaneFocusHandler() {
046: }
047:
048: public static void attach() {
049: if (sharedInstance == null) {
050: sharedInstance = new RootPaneFocusHandler();
051: }
052: if (numInstallations == 0) {
053: MenuSelectionManager.defaultManager().addChangeListener(
054: sharedInstance);
055: }
056: numInstallations++;
057: }
058:
059: public static void detach() {
060: if (numInstallations == 1) {
061: MenuSelectionManager.defaultManager().removeChangeListener(
062: sharedInstance);
063: }
064: if (numInstallations > 0) {
065: numInstallations--;
066: }
067: }
068:
069: public void stateChanged(final ChangeEvent e) {
070: final MenuElement[] path = MenuSelectionManager
071: .defaultManager().getSelectedPath();
072: if (Utilities.isEmptyArray(path)) {
073: if (focusedRootPane != null) {
074: returnFocus();
075: }
076: } else {
077: if (focusedRootPane == null
078: && Utilities.isValidFirstPathElement(path[0])) {
079: grabFocus(path);
080: }
081: }
082: }
083:
084: private void grabFocus(final MenuElement[] path) {
085: for (int i = 0; i < path.length; i++) {
086: final MenuElement item = path[i];
087: if (i > 0 && !(item instanceof Component)) {
088: continue;
089: }
090: final JRootPane pane = SwingUtilities
091: .getRootPane(getRootPaneChild(item));
092: if (pane != null) {
093: Component focusOwner = getFocusManager()
094: .getFocusOwner();
095: if (pane.requestFocus(true)) {
096: previousFocusOwner = focusOwner;
097: focusedRootPane = pane;
098: MenuKeyBindingProcessor.attach();
099: if (pane.getJMenuBar() == null) {
100: pane
101: .addKeyListener(createRootPaneKeyListener());
102: }
103: }
104: break;
105: }
106: }
107: }
108:
109: private KeyListener createRootPaneKeyListener() {
110: return (rootPaneKeyListener != null) ? rootPaneKeyListener
111: : (rootPaneKeyListener = new KeyListener() {
112: public void keyPressed(KeyEvent event) {
113: MenuSelectionManager.defaultManager()
114: .processKeyEvent(event);
115: }
116:
117: public void keyReleased(KeyEvent event) {
118: MenuSelectionManager.defaultManager()
119: .processKeyEvent(event);
120: }
121:
122: public void keyTyped(KeyEvent event) {
123: MenuSelectionManager.defaultManager()
124: .processKeyEvent(event);
125: }
126: });
127: }
128:
129: private Component getRootPaneChild(final MenuElement item) {
130: return (item instanceof JPopupMenu) ? ((JPopupMenu) item)
131: .getInvoker() : (Component) item;
132: }
133:
134: private void returnFocus() {
135: if (isValidPreviusFocusOwner()) {
136: previousFocusOwner.requestFocusInWindow();
137: } else {
138: getFocusManager().focusNextComponent();
139: }
140: focusedRootPane.removeKeyListener(rootPaneKeyListener);
141: focusedRootPane = null;
142: MenuKeyBindingProcessor.detach();
143: }
144:
145: private KeyboardFocusManager getFocusManager() {
146: return KeyboardFocusManager.getCurrentKeyboardFocusManager();
147: }
148:
149: private boolean isValidPreviusFocusOwner() {
150: return previousFocusOwner != null
151: && previousFocusOwner.isFocusable()
152: && previousFocusOwner.isVisible()
153: && previousFocusOwner.isEnabled();
154: }
155: }
|