1/*
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.apple.laf;
27
28import java.awt.*;
29import java.awt.event.KeyEvent;
30
31import javax.swing.*;
32
33import com.apple.laf.AquaUtils.RecyclableSingleton;
34import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
35
36public class AquaMnemonicHandler {
37    private static final RecyclableSingleton<AltProcessor> altProcessor = new RecyclableSingletonFromDefaultConstructor<AltProcessor>(AltProcessor.class);
38    public static KeyEventPostProcessor getInstance() {
39        return altProcessor.get();
40    }
41
42    protected static boolean isMnemonicHidden = true; // true by default
43
44    public static void setMnemonicHidden(final boolean hide) {
45        if (UIManager.getBoolean("Button.showMnemonics")) {
46            // Do not hide mnemonics if the UI defaults do not support this
47            isMnemonicHidden = false;
48        } else {
49            isMnemonicHidden = hide;
50        }
51    }
52
53    /**
54     * Gets the state of the hide mnemonic flag. This only has meaning if this feature is supported by the underlying OS.
55     *
56     * @return true if mnemonics are hidden, otherwise, false
57     * @see #setMnemonicHidden
58     * @since 1.4
59     */
60    public static boolean isMnemonicHidden() {
61        if (UIManager.getBoolean("Button.showMnemonics")) {
62            // Do not hide mnemonics if the UI defaults do not support this
63            isMnemonicHidden = false;
64        }
65        return isMnemonicHidden;
66    }
67
68    static class AltProcessor implements KeyEventPostProcessor {
69        public boolean postProcessKeyEvent(final KeyEvent ev) {
70            if (ev.getKeyCode() != KeyEvent.VK_ALT) {
71                return false;
72            }
73
74            final JRootPane root = SwingUtilities.getRootPane(ev.getComponent());
75            final Window winAncestor = (root == null ? null : SwingUtilities.getWindowAncestor(root));
76
77            switch(ev.getID()) {
78                case KeyEvent.KEY_PRESSED:
79                    setMnemonicHidden(false);
80                    break;
81                case KeyEvent.KEY_RELEASED:
82                    setMnemonicHidden(true);
83                    break;
84            }
85
86            repaintMnemonicsInWindow(winAncestor);
87
88            return false;
89        }
90    }
91
92    /*
93     * Repaints all the components with the mnemonics in the given window and all its owned windows.
94     */
95    static void repaintMnemonicsInWindow(final Window w) {
96        if (w == null || !w.isShowing()) {
97            return;
98        }
99
100        final Window[] ownedWindows = w.getOwnedWindows();
101        for (final Window element : ownedWindows) {
102            repaintMnemonicsInWindow(element);
103        }
104
105        repaintMnemonicsInContainer(w);
106    }
107
108    /*
109     * Repaints all the components with the mnemonics in container.
110     * Recursively searches for all the subcomponents.
111     */
112    static void repaintMnemonicsInContainer(final Container cont) {
113        for (int i = 0; i < cont.getComponentCount(); i++) {
114            final Component c = cont.getComponent(i);
115            if (c == null || !c.isVisible()) {
116                continue;
117            }
118
119            if (c instanceof AbstractButton && ((AbstractButton)c).getMnemonic() != '\0') {
120                c.repaint();
121                continue;
122            }
123
124            if (c instanceof JLabel && ((JLabel)c).getDisplayedMnemonic() != '\0') {
125                c.repaint();
126                continue;
127            }
128
129            if (c instanceof Container) {
130                repaintMnemonicsInContainer((Container)c);
131            }
132        }
133    }
134}
135