This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 58126
Collapse All | Expand All

(-)a/core.output2/nbproject/project.xml (+8 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.core.output2</code-name-base>
50
            <code-name-base>org.netbeans.core.output2</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.modules.options.keymap</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <specification-version>1.17</specification-version>
58
                    </run-dependency>
59
                </dependency>
60
                <dependency>
53
                    <code-name-base>org.openide.actions</code-name-base>
61
                    <code-name-base>org.openide.actions</code-name-base>
54
                    <build-prerequisite/>
62
                    <build-prerequisite/>
55
                    <compile-dependency/>
63
                    <compile-dependency/>
(-)a/core.output2/src/org/netbeans/core/output2/OutputTab.java (-9 / +115 lines)
Lines 61-66 Link Here
61
import java.io.File;
61
import java.io.File;
62
import java.io.IOException;
62
import java.io.IOException;
63
import java.util.ArrayList;
63
import java.util.ArrayList;
64
import java.util.Arrays;
64
import java.util.EnumMap;
65
import java.util.EnumMap;
65
import java.util.List;
66
import java.util.List;
66
import java.util.Map;
67
import java.util.Map;
Lines 82-87 Link Here
82
import javax.swing.event.PopupMenuEvent;
83
import javax.swing.event.PopupMenuEvent;
83
import javax.swing.event.PopupMenuListener;
84
import javax.swing.event.PopupMenuListener;
84
import javax.swing.text.Document;
85
import javax.swing.text.Document;
86
import org.netbeans.core.options.keymap.api.ShortcutAction;
87
import org.netbeans.core.options.keymap.api.ShortcutsFinder;
85
import org.netbeans.core.output2.Controller.ControllerOutputEvent;
88
import org.netbeans.core.output2.Controller.ControllerOutputEvent;
86
import org.netbeans.core.output2.ui.AbstractOutputPane;
89
import org.netbeans.core.output2.ui.AbstractOutputPane;
87
import org.netbeans.core.output2.ui.AbstractOutputTab;
90
import org.netbeans.core.output2.ui.AbstractOutputTab;
Lines 99-105 Link Here
99
import org.openide.xml.XMLUtil;
102
import org.openide.xml.XMLUtil;
100
103
101
import static org.netbeans.core.output2.OutputTab.ACTION.*;
104
import static org.netbeans.core.output2.OutputTab.ACTION.*;
102
import org.openide.windows.IOProvider;
105
import org.netbeans.core.output2.ui.OutputKeymapManager;
106
import org.netbeans.core.output2.ui.KeyStrokeNameSupport;
107
import org.openide.util.Lookup;
103
108
104
109
105
/**
110
/**
Lines 782-791 Link Here
782
        TabAction(ACTION action, String bundleKey) {
787
        TabAction(ACTION action, String bundleKey) {
783
            if (bundleKey != null) {
788
            if (bundleKey != null) {
784
                String name = NbBundle.getMessage(OutputTab.class, bundleKey);
789
                String name = NbBundle.getMessage(OutputTab.class, bundleKey);
785
                KeyStroke accelerator = getAcceleratorFor(bundleKey);
790
                KeyStroke[] accels = getAcceleratorFor(action);
786
                this.action = action;
791
                this.action = action;
787
                putValue(NAME, name);
792
                putValue(NAME, name);
788
                putValue(ACCELERATOR_KEY, accelerator);
793
                if (accels != null && accels.length > 0) {
794
                    putValue(ACCELERATORS_KEY, accels);
795
                    putValue(ACCELERATOR_KEY, getAccelForPopUp(accels));
796
                }
789
            }
797
            }
790
        }
798
        }
791
799
Lines 814-828 Link Here
814
         * Get a keyboard accelerator from the resource bundle, with special handling
822
         * Get a keyboard accelerator from the resource bundle, with special handling
815
         * for the mac keyboard layout.
823
         * for the mac keyboard layout.
816
         *
824
         *
817
         * @param name The bundle key prefix
825
         * @param action Action to get accelerator for.
818
         * @return A keystroke
826
         * @return A keystroke
819
         */
827
         */
820
        private KeyStroke getAcceleratorFor(String name) {
828
        private KeyStroke[] getAcceleratorFor(ACTION action) {
821
            String key = name + ".accel"; //NOI18N
829
            switch (action) {
822
            if (Utilities.isMac()) {
830
                case COPY:
823
                key += ".mac"; //NOI18N
831
                    return getKeyStrokeForAction(
832
                            "copy-to-clipboard");                       //NOI18N
833
                case PASTE:
834
                    return getKeyStrokeForAction(
835
                            "paste-from-clipboard");                    //NOI18N
836
                case SAVEAS:
837
                    return getKeyStrokeForAction(
838
                            OutputKeymapManager.SAVE_AS_ACTION_ID);
839
                case CLOSE:
840
                    return getKeyStrokeForAction(
841
                            OutputKeymapManager.CLOSE_ACTION_ID);
842
                case NEXT_ERROR:
843
                    return getKeyStrokeForAction("next-error");         //NOI18N
844
                case PREV_ERROR:
845
                    return getKeyStrokeForAction("previous-error");     //NOI18N
846
                case SELECT_ALL:
847
                    return getKeyStrokeForAction("select-all");         //NOI18N
848
                case FIND:
849
                    return getKeyStrokeForAction(
850
                            "incremental-search-forward");              //NOI18N
851
                case FIND_NEXT:
852
                    return getKeyStrokeForAction("find-next");          //NOI18N
853
                case FIND_PREVIOUS:
854
                    return getKeyStrokeForAction("find-previous");      //NOI18N
855
                case FILTER:
856
                    return getKeyStrokeForAction(
857
                            OutputKeymapManager.FILTER_ACTION_ID);
858
                case LARGER_FONT:
859
                    return getKeyStrokeForAction(
860
                            OutputKeymapManager.LARGER_FONT_ACTION_ID);
861
                case SMALLER_FONT:
862
                    return getKeyStrokeForAction(
863
                            OutputKeymapManager.SMALLER_FONT_ACTION_ID);
864
                case FONT_TYPE:
865
                    return getKeyStrokeForAction(
866
                            OutputKeymapManager.FONT_TYPE_ACTION_ID);
867
                case CLEAR:
868
                    return getKeyStrokeForAction(
869
                            OutputKeymapManager.CLEAR_ACTION_ID);
870
                case WRAP:
871
                    return getKeyStrokeForAction(
872
                            OutputKeymapManager.WRAP_ACTION_ID);
873
                default:
874
                    return null;
824
            }
875
            }
825
            return Utilities.stringToKey(NbBundle.getMessage(OutputTab.class, key));
876
        }
877
878
        private KeyStroke[] getKeyStrokeForAction(String actionId) {
879
            for (ShortcutsFinder sf : Lookup.getDefault().lookupAll(
880
                    ShortcutsFinder.class)) {
881
                ShortcutAction sa = sf.findActionForId(actionId);
882
                if (sa != null) {
883
                    String[] shortcuts = sf.getShortcuts(sa);
884
                    if (shortcuts != null && shortcuts.length > 0) {
885
                        KeyStroke[] ks = new KeyStroke[shortcuts.length];
886
                        int valid = 0;
887
                        for (int i = 0; i < shortcuts.length; i++) {
888
                            if (shortcuts[i] != null) {
889
                                KeyStroke s = humanStringToStroke(shortcuts[i]);
890
                                if (s != null) {
891
                                    ks[valid++] = s;
892
                                }
893
                            }
894
                        }
895
                        return Arrays.copyOfRange(ks, 0, valid);
896
                    }
897
                }
898
            }
899
            return null;
900
        }
901
902
        private KeyStroke humanStringToStroke(String s) {
903
            if (s == null) {
904
                return null;
905
            }
906
            KeyStroke[] strokes = KeyStrokeNameSupport.stringToKeyStrokes(s);
907
            if (strokes.length > 0) {
908
                return strokes[0];
909
            } else {
910
                return null;
911
            }
912
        }
913
914
        /**
915
         * Get the most appropriate accelerator for pop-up menu.
916
         */
917
        public KeyStroke getAccelForPopUp(KeyStroke[] keystrokes) {
918
            KeyStroke best = null;
919
            boolean isSolaris =
920
                    Utilities.getOperatingSystem() == Utilities.OS_SOLARIS;
921
            for (KeyStroke ks : keystrokes) {
922
                boolean solarisKey = ks.getKeyCode() >= KeyEvent.VK_STOP
923
                        && ks.getKeyCode() <= KeyEvent.VK_CUT;
924
                if (isSolaris == solarisKey
925
                        && (best == null
926
                        || best.getKeyCode() > ks.getKeyCode())) {
927
                    //Solaris key on solaris OS or other key on other OS.
928
                    best = ks;
929
                }
930
            }
931
            return best == null ? keystrokes[0] : best;
826
        }
932
        }
827
933
828
        public ACTION getAction() {
934
        public ACTION getAction() {
(-)a/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputTab.java (-13 / +20 lines)
Lines 68-73 Link Here
68
    private boolean inputVisible = false;
68
    private boolean inputVisible = false;
69
    private AbstractOutputPane outputPane;
69
    private AbstractOutputPane outputPane;
70
    private Action[] actions = new Action[0];  
70
    private Action[] actions = new Action[0];  
71
    protected static final String ACCELERATORS_KEY = "ACCELERATORS_KEY";//NOI18N
71
72
72
    private Component toFocus;
73
    private Component toFocus;
73
    
74
    
Lines 191-212 Link Here
191
            //It is a Controller.ControllerAction - don't create a memory leak by listening to it
192
            //It is a Controller.ControllerAction - don't create a memory leak by listening to it
192
            a = new WeakAction(a);
193
            a = new WeakAction(a);
193
        }
194
        }
194
        KeyStroke accel = null;
195
        KeyStroke[] accels = null;
195
        String name;
196
        String name;
196
        Object o = a.getValue (Action.ACCELERATOR_KEY);
197
        Object o = a.getValue(ACCELERATORS_KEY);
197
        if (o instanceof KeyStroke) {
198
        if (o instanceof KeyStroke[]) {
198
            accel = (KeyStroke) o;
199
            accels = (KeyStroke[]) o;
199
        }
200
        }
200
        name = (String) a.getValue(Action.NAME);
201
        name = (String) a.getValue(Action.NAME);
201
        if (accel != null) {
202
        if (accels != null) {
202
            if (Controller.LOG) Controller.log ("Installed action " + name + " on " + accel);
203
            for (KeyStroke accel : accels) {
203
            // if the logic here changes, check the popup escaping hack in Controller
204
                if (Controller.LOG) {
204
            // it temporarily removes the VK_ESCAPE from input maps..
205
                    Controller.log("Installed action " //NOI18N
205
            JComponent c = getOutputPane().textView;
206
                            + name + " on " + accel);                   //NOI18N
206
            c.getInputMap().put(accel, name);
207
                }
207
            c.getActionMap().put(name, a);
208
                // if the logic here changes, check the popup escaping hack in
208
            getInputMap (WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put (accel, name);
209
                // Controller it temporarily removes the VK_ESCAPE from input
209
            getActionMap().put(name, a);
210
                // maps..
211
                JComponent c = getOutputPane().textView;
212
                c.getInputMap().put(accel, name);
213
                c.getActionMap().put(name, a);
214
                getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(accel, name);
215
                getActionMap().put(name, a);
216
            }
210
        }
217
        }
211
    }
218
    }
212
219
(-)a/editor.settings.storage/src/org/netbeans/modules/editor/settings/storage/spi/support/StorageSupport.java (-97 / +9 lines)
Lines 41-149 Link Here
41
 * Version 2 license, then the option applies only if the new code is
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
42
 * made subject to such option by the copyright holder.
43
 */
43
 */
44
package org.netbeans.modules.editor.settings.storage.spi.support;
44
package org.netbeans.core.output2.ui;
45
45
46
import java.awt.event.InputEvent;
46
import java.awt.event.InputEvent;
47
import java.awt.event.KeyEvent;
47
import java.awt.event.KeyEvent;
48
import java.lang.reflect.Field;
48
import java.lang.reflect.Field;
49
import java.lang.reflect.Modifier;
49
import java.lang.reflect.Modifier;
50
import java.util.ArrayList;
50
import java.util.ArrayList;
51
import java.util.Collection;
52
import java.util.HashMap;
51
import java.util.HashMap;
53
import java.util.Iterator;
54
import java.util.List;
52
import java.util.List;
55
import java.util.Map;
53
import java.util.Map;
56
import java.util.StringTokenizer;
54
import java.util.StringTokenizer;
57
import java.util.logging.Level;
55
import java.util.logging.Level;
58
import java.util.logging.Logger;
56
import java.util.logging.Logger;
59
import javax.swing.KeyStroke;
57
import javax.swing.KeyStroke;
60
import org.netbeans.modules.editor.settings.storage.*;
61
import org.openide.filesystems.FileObject;
62
import org.openide.util.Utilities;
58
import org.openide.util.Utilities;
63
59
64
public final class StorageSupport {
60
public final class KeyStrokeNameSupport {
65
61
66
    private static final Logger LOG = Logger.getLogger(StorageSupport.class.getName());
62
    private static final Logger LOG = Logger.getLogger(KeyStrokeNameSupport.class.getName());
67
    private static Map<String, Integer> names;
63
    private static Map<String, Integer> names;
68
64
69
    private StorageSupport() {
65
    private KeyStrokeNameSupport() {
70
66
71
    }
67
    }
72
68
73
    public static String getLocalizingBundleMessage(FileObject fo, String key, String defaultValue) {
74
        return Utils.getLocalizedName(fo, key, defaultValue, false);
75
    }
76
77
    /**
78
     * Converts a list of <code>KeyStroke</code>s to its textual representation. There
79
     * are two available formats for the textual representation:
80
     * 
81
     * <li><b>Human readable</b> - this format encodes a <code>KeyStroke</code> to
82
     *   a string that looks like for example 'Ctrl+A' or 'Alt+Shift+M'.
83
     * <li><b>Emacs style</b> - this format encodes a <code>KeyStroke</code> to
84
     *   a string that's known from Emacs and that looks like for example 'C-A' or 'AS-M'.
85
     *   It uses methods from <code>org.openide.util.Utilities</code>, which take
86
     *   care of Mac OS specifics and use 'D' and 'O' wildcards for encoding 'Ctrl'
87
     *   and 'Alt' keys.
88
     * 
89
     * @param keys The <code>KeyStrokes</code> to convert.
90
     * @param emacsStyle If <code>true</code> the returned string will be in so called
91
     *   Emacs style, ortherwise it will be in human readable format.
92
     * 
93
     * @return The textual representation of <code>KeyStroke</code>s passed in.
94
     * @since 1.16
95
     */
96
    public static String keyStrokesToString(Collection<? extends KeyStroke> keys, boolean emacsStyle) {
97
        StringBuilder sb = new StringBuilder();
98
99
        for (Iterator<? extends KeyStroke> it = keys.iterator(); it.hasNext(); ) {
100
            KeyStroke keyStroke = it.next();
101
            if (emacsStyle) {
102
                sb.append(Utilities.keyToString(keyStroke, true));
103
                if (it.hasNext()) {
104
                    sb.append('$'); //NOI18N
105
                }
106
            } else {
107
                sb.append(keyStrokeToHumanReadableString(keyStroke));
108
                if (it.hasNext()) {
109
                    sb.append(' '); //NOI18N
110
                }
111
            }
112
        }
113
114
        return sb.toString();
115
    }
116
117
    /**
69
    /**
118
     * Converts a textual representation of key strokes to an array of <code>KeyStroke</code>
70
     * Converts a textual representation of key strokes to an array of <code>KeyStroke</code>
119
     * objects. Please see {@link #keyStrokesToString(Collection<KeyStroke>, boolean)}
71
     * objects.
120
     * ror details about the available formats.
121
     * 
72
     * 
122
     * @param key The textual representation of keystorkes to convert. Its format
73
     * @param key The textual representation of keystorkes to convert.
123
     *   depends on the value of <code>emacsStyle</code> parameter.
124
     * @param emacsStyle If <code>true</code> the <code>key</code> string is expected to be
125
     *   in so called emacs format, ortherwise it will be in human readable format.
126
     * 
127
     * @return The <code>KeyStroke</code>s that were represented by the <code>key</code>
74
     * @return The <code>KeyStroke</code>s that were represented by the <code>key</code>
128
     *   text or <code>null</code> if the textual representation was malformed.
75
     *   text or <code>null</code> if the textual representation was malformed.
129
     * @since 1.16
130
     */
76
     */
131
    public static KeyStroke[] stringToKeyStrokes(String key, boolean emacsStyle) {
77
    public static KeyStroke[] stringToKeyStrokes(String key) {
132
        assert key != null : "The parameter key must not be null"; //NOI18N
78
        assert key != null : "The parameter key must not be null"; //NOI18N
133
        
79
        
134
        List<KeyStroke> result = new ArrayList<KeyStroke>();
80
        List<KeyStroke> result = new ArrayList<KeyStroke>();
135
        String delimiter = emacsStyle ? "$" : " "; //NOI18N
81
        String delimiter = " ";                                         //NOI18N
136
        
82
        
137
        for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N
83
        for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N
138
            String ks = st.nextToken().trim();
84
            String ks = st.nextToken().trim();
139
            KeyStroke keyStroke;
85
            KeyStroke keyStroke = humanReadableStringToKeyStroke(ks);
140
            
141
            if (emacsStyle) {
142
                keyStroke = Utilities.stringToKey(ks);
143
            } else {
144
                keyStroke = humanReadableStringToKeyStroke(ks);
145
            }
146
            
147
            if (keyStroke != null) {
86
            if (keyStroke != null) {
148
                result.add(keyStroke);
87
                result.add(keyStroke);
149
            } else {
88
            } else {
Lines 210-240 Link Here
210
            return names;
149
            return names;
211
        }
150
        }
212
    }
151
    }
213
214
    private static String keyStrokeToHumanReadableString(KeyStroke keyStroke) {
215
        int modifiers = keyStroke.getModifiers();
216
        StringBuilder sb = new StringBuilder();
217
        if ((modifiers & InputEvent.CTRL_DOWN_MASK) > 0) {
218
            sb.append(EMACS_CTRL);
219
        }
220
        if ((modifiers & InputEvent.ALT_DOWN_MASK) > 0) {
221
            sb.append(EMACS_ALT);
222
        }
223
        if ((modifiers & InputEvent.SHIFT_DOWN_MASK) > 0) {
224
            sb.append(EMACS_SHIFT);
225
        }
226
        if ((modifiers & InputEvent.META_DOWN_MASK) > 0) {
227
            sb.append(EMACS_META);
228
        }
229
        if (keyStroke.getKeyCode() != KeyEvent.VK_SHIFT &&
230
                keyStroke.getKeyCode() != KeyEvent.VK_CONTROL &&
231
                keyStroke.getKeyCode() != KeyEvent.VK_META &&
232
                keyStroke.getKeyCode() != KeyEvent.VK_ALT &&
233
                keyStroke.getKeyCode() != KeyEvent.VK_ALT_GRAPH
234
        ) {
235
            sb.append(Utilities.keyToString(KeyStroke.getKeyStroke(keyStroke.getKeyCode(), 0)));
236
        }
237
        return sb.toString();
238
    }
239
    
240
}
152
}
(-)a/core.output2/src/org/netbeans/core/output2/ui/OutputKeymapManager.java (+334 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2012 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.core.output2.ui;
43
44
import java.io.IOException;
45
import java.util.Collections;
46
import java.util.Enumeration;
47
import java.util.HashMap;
48
import java.util.HashSet;
49
import java.util.List;
50
import java.util.Map;
51
import java.util.Set;
52
import java.util.logging.Level;
53
import java.util.logging.Logger;
54
import org.netbeans.core.options.keymap.api.ShortcutAction;
55
import org.netbeans.core.options.keymap.spi.KeymapManager;
56
import org.netbeans.core.output2.NbIOProvider;
57
import org.openide.filesystems.FileObject;
58
import org.openide.filesystems.FileUtil;
59
import org.openide.util.NbBundle;
60
import org.openide.util.Utilities;
61
import org.openide.util.lookup.ServiceProvider;
62
63
/**
64
 *
65
 * @author jhavlin
66
 */
67
@ServiceProvider(service = KeymapManager.class)
68
public class OutputKeymapManager extends KeymapManager {
69
70
    private static final Logger LOG = Logger.getLogger(
71
            OutputKeymapManager.class.getName());
72
    private static final String CATEGORY_NAME = NbBundle.getMessage(
73
            NbIOProvider.class, "OpenIDE-Module-Name");                 //NOI18N
74
    /**
75
     * ID of actions in keymap settings panel.
76
     */
77
    public static final String CLEAR_ACTION_ID =
78
            "output-window-clear";                                      //NOI18N
79
    public static final String FILTER_ACTION_ID =
80
            "output-window-filter";                                     //NOI18N
81
    public static final String LARGER_FONT_ACTION_ID =
82
            "output-window-larger-font";                                //NOI18N
83
    public static final String SMALLER_FONT_ACTION_ID =
84
            "output-window-smaller-font";                               //NOI18N
85
    public static final String CLOSE_ACTION_ID =
86
            "output-window-close";                                      //NOI18N
87
    public static final String FONT_TYPE_ACTION_ID =
88
            "output-window-font-type";                                  //NOI18N
89
    public static final String SAVE_AS_ACTION_ID =
90
            "output-window-save-as";                                    //NOI18N
91
    public static final String WRAP_ACTION_ID =
92
            "output-window-wrap";                                       //NOI18N
93
    /**
94
     * Constants for persistence.
95
     */
96
    public static final String STORAGE_DIR =
97
            "org-netbeans-core-output2/actions/";                       //NOI18N
98
    public static final String SHORTCUT_PREFIX = "sc";                  //NOI18N
99
    /**
100
     * Actions
101
     */
102
    private final OutWinShortCutAction wrap = new OutWinShortCutAction(
103
            WRAP_ACTION_ID, "ACTION_WRAP");                             //NOI18N
104
    private final OutWinShortCutAction clear = new OutWinShortCutAction(
105
            CLEAR_ACTION_ID, "ACTION_CLEAR");                           //NOI18N
106
    private final OutWinShortCutAction filter = new OutWinShortCutAction(
107
            FILTER_ACTION_ID, "ACTION_FILTER");                         //NOI18N
108
    private final OutWinShortCutAction largerFont = new OutWinShortCutAction(
109
            LARGER_FONT_ACTION_ID, "ACTION_LARGER_FONT");               //NOI18N
110
    private final OutWinShortCutAction smallerFont = new OutWinShortCutAction(
111
            SMALLER_FONT_ACTION_ID, "ACTION_SMALLER_FONT");             //NOI18N
112
    private final OutWinShortCutAction closeWindow = new OutWinShortCutAction(
113
            CLOSE_ACTION_ID, "ACTION_CLOSE");                           //NOI18N
114
    private final OutWinShortCutAction fontType = new OutWinShortCutAction(
115
            FONT_TYPE_ACTION_ID, "ACTION_FONT_TYPE");                   //NOI18N
116
    private final OutWinShortCutAction saveAs = new OutWinShortCutAction(
117
            SAVE_AS_ACTION_ID, "ACTION_SAVEAS");                        //NOI18N
118
    /**
119
     * Map of keymaps. Keys are profile names.
120
     */
121
    Map<String, Map<ShortcutAction, Set<String>>> keymaps =
122
            new HashMap<String, Map<ShortcutAction, Set<String>>>();
123
    /**
124
     * The default keymap. Used if keys for a profile are not set.
125
     */
126
    Map<ShortcutAction, Set<String>> defaultKeymap =
127
            new HashMap<ShortcutAction, Set<String>>();
128
    /**
129
     * List of all actions.
130
     */
131
    private final Set<OutWinShortCutAction> allActions =
132
            new HashSet<OutWinShortCutAction>();
133
    /**
134
     * Map of actions of categories. There is only one category in this case.
135
     */
136
    Map<String, Set<ShortcutAction>> actions =
137
            new HashMap<String, Set<ShortcutAction>>();
138
139
    public OutputKeymapManager() {
140
        super("OutputWindowKeymapManager");                             //NOI18N
141
        actions = new HashMap<String, Set<ShortcutAction>>();
142
        Collections.addAll(allActions, wrap, clear, filter, largerFont,
143
                smallerFont, closeWindow, fontType, saveAs);
144
        Set<ShortcutAction> set = new HashSet<ShortcutAction>();
145
        set.addAll(allActions);
146
        actions.put(CATEGORY_NAME, set);
147
        fillDefaultKeyMap();
148
        loadShortCuts();
149
    }
150
151
    private void fillDefaultKeyMap() {
152
        for (OutWinShortCutAction a : allActions) {
153
            String dflt = a.getDefaultShortcut();
154
            defaultKeymap.put(a, (dflt != null && !dflt.isEmpty())
155
                    ? Collections.singleton(dflt)
156
                    : Collections.<String>emptySet());
157
        }
158
    }
159
160
    @Override
161
    public Map<String, Set<ShortcutAction>> getActions() {
162
        return actions;
163
    }
164
165
    @Override
166
    public void refreshActions() {
167
    }
168
169
    @Override
170
    public Map<ShortcutAction, Set<String>> getKeymap(String profileName) {
171
        Map<ShortcutAction, Set<String>> km = keymaps.get(profileName);
172
        if (km == null) {
173
            km = new HashMap<ShortcutAction, Set<String>>(defaultKeymap);
174
            keymaps.put(profileName, km);
175
        }
176
        return km;
177
    }
178
179
    @Override
180
    public Map<ShortcutAction, Set<String>> getDefaultKeymap(
181
            String profileName) {
182
        return defaultKeymap;
183
    }
184
185
    @Override
186
    public void saveKeymap(String profileName,
187
            Map<ShortcutAction, Set<String>> actionToShortcuts) {
188
189
        Map<ShortcutAction, Set<String>> newShortcuts =
190
                new HashMap<ShortcutAction, Set<String>>();
191
        keymaps.put(profileName, newShortcuts);
192
        for (OutWinShortCutAction owsa : allActions) {
193
            Set<String> shortcuts = actionToShortcuts.get(owsa);
194
            if (shortcuts == null) {
195
                shortcuts = Collections.<String>emptySet();
196
            }
197
            newShortcuts.put(owsa, shortcuts);
198
        }
199
        storeShortCuts(profileName);
200
    }
201
202
    @Override
203
    public List<String> getProfiles() {
204
        return null;
205
    }
206
207
    @Override
208
    public String getCurrentProfile() {
209
        return null;
210
    }
211
212
    @Override
213
    public void setCurrentProfile(String profileName) {
214
    }
215
216
    @Override
217
    public void deleteProfile(String profileName) {
218
    }
219
220
    @Override
221
    public boolean isCustomProfile(String profileName) {
222
        return false;
223
    }
224
225
    private class OutWinShortCutAction implements ShortcutAction {
226
227
        private String id;
228
        private String bundleKey;
229
        private String displayName;
230
        private String defaultShortcut;
231
232
        public OutWinShortCutAction(String id, String bundleKey) {
233
            this.id = id;
234
            this.bundleKey = bundleKey;
235
            this.displayName = NbBundle.getMessage(
236
                    NbIOProvider.class, bundleKey);
237
            String nbKeysBundleKey = Utilities.isMac()
238
                    ? bundleKey + ".accel.mac" //NOI18N
239
                    : bundleKey + ".accel";                             //NOI18N
240
            String nbKeys = NbBundle.getMessage(NbIOProvider.class,
241
                    nbKeysBundleKey);
242
            this.defaultShortcut = nbKeys;
243
        }
244
245
        public String getId() {
246
            return id;
247
        }
248
249
        public String getBundleKey() {
250
            return bundleKey;
251
        }
252
253
        public String getDisplayName() {
254
            return displayName;
255
        }
256
257
        public String getDefaultShortcut() {
258
            return defaultShortcut;
259
        }
260
261
        @Override
262
        public String getDelegatingActionId() {
263
            return null;
264
        }
265
266
        @Override
267
        public ShortcutAction getKeymapManagerInstance(
268
                String keymapManagerName) {
269
            return null;
270
        }
271
    }
272
273
    private void storeShortCuts(String profileName) {
274
        FileObject root = FileUtil.getConfigRoot();
275
        try {
276
            FileObject actionsDir = FileUtil.createFolder(
277
                    root, STORAGE_DIR + profileName);
278
            for (OutWinShortCutAction a : allActions) {
279
                FileObject data = actionsDir.getFileObject(a.getId());
280
                if (data == null) {
281
                    data = actionsDir.createData(a.getId());
282
                } else if (data.isFolder()) {
283
                    throw new IOException(data + " is a folder.");      //NOI18N
284
                }
285
                Enumeration<String> atts = data.getAttributes();
286
                while (atts.hasMoreElements()) {
287
                    String attName = atts.nextElement();
288
                    data.setAttribute(attName, null);
289
                }
290
                int index = 1;
291
                if (keymaps.get(profileName).get(a) == null) {
292
                    continue;
293
                }
294
                for (String shortCut : keymaps.get(profileName).get(a)) {
295
                    data.setAttribute(SHORTCUT_PREFIX + index++, shortCut);
296
                }
297
            }
298
        } catch (IOException e) {
299
            LOG.log(Level.WARNING, "Cannot create folder", e);          //NOI18N
300
        }
301
    }
302
303
    private void loadShortCuts() {
304
        FileObject root = FileUtil.getConfigRoot();
305
        FileObject actionsDir = root.getFileObject(STORAGE_DIR);
306
        if (actionsDir == null) {
307
            return;
308
        }
309
        for (FileObject profileDir : actionsDir.getChildren()) {
310
            if (!profileDir.isFolder()) {
311
                continue;
312
            }
313
            Map<ShortcutAction, Set<String>> keymap =
314
                    new HashMap<ShortcutAction, Set<String>>();
315
            keymaps.put(profileDir.getName(), keymap);
316
            for (OutWinShortCutAction a : allActions) {
317
                FileObject actionFile = profileDir.getFileObject(a.getId());
318
                if (actionFile == null || !actionFile.isData()) {
319
                    keymap.put(a, Collections.<String>emptySet());
320
                    continue;
321
                }
322
                Enumeration<String> atts = actionFile.getAttributes();
323
                Set<String> strokes = new HashSet<String>();
324
                while (atts.hasMoreElements()) {
325
                    String att = atts.nextElement();
326
                    if (att.startsWith(SHORTCUT_PREFIX)) {
327
                        strokes.add((String) actionFile.getAttribute(att));
328
                    }
329
                }
330
                keymap.put(a, strokes);
331
            }
332
        }
333
    }
334
}
(-)a/options.keymap/nbproject/project.xml (+1 lines)
Lines 152-157 Link Here
152
                </test-type>
152
                </test-type>
153
            </test-dependencies>
153
            </test-dependencies>
154
            <friend-packages>
154
            <friend-packages>
155
                <friend>org.netbeans.core.output2</friend>
155
                <friend>org.netbeans.modules.editor.macros</friend>
156
                <friend>org.netbeans.modules.editor.macros</friend>
156
                <friend>org.netbeans.modules.jumpto</friend>
157
                <friend>org.netbeans.modules.jumpto</friend>
157
                <friend>org.netbeans.modules.jvi</friend>
158
                <friend>org.netbeans.modules.jvi</friend>

Return to bug 58126