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 58-63 Link Here
58
                    </run-dependency>
58
                    </run-dependency>
59
                </dependency>
59
                </dependency>
60
                <dependency>
60
                <dependency>
61
                    <code-name-base>org.netbeans.modules.options.keymap</code-name-base>
62
                    <build-prerequisite/>
63
                    <compile-dependency/>
64
                    <run-dependency>
65
                        <specification-version>1.17</specification-version>
66
                    </run-dependency>
67
                </dependency>
68
                <dependency>
61
                    <code-name-base>org.openide.actions</code-name-base>
69
                    <code-name-base>org.openide.actions</code-name-base>
62
                    <build-prerequisite/>
70
                    <build-prerequisite/>
63
                    <compile-dependency/>
71
                    <compile-dependency/>
(-)a/core.output2/src/org/netbeans/core/output2/OutputTab.java (-9 / +70 lines)
Lines 82-87 Link Here
82
import javax.swing.event.PopupMenuEvent;
82
import javax.swing.event.PopupMenuEvent;
83
import javax.swing.event.PopupMenuListener;
83
import javax.swing.event.PopupMenuListener;
84
import javax.swing.text.Document;
84
import javax.swing.text.Document;
85
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
85
import org.netbeans.core.output2.Controller.ControllerOutputEvent;
86
import org.netbeans.core.output2.Controller.ControllerOutputEvent;
86
import org.netbeans.core.output2.ui.AbstractOutputPane;
87
import org.netbeans.core.output2.ui.AbstractOutputPane;
87
import org.netbeans.core.output2.ui.AbstractOutputTab;
88
import org.netbeans.core.output2.ui.AbstractOutputTab;
Lines 99-105 Link Here
99
import org.openide.xml.XMLUtil;
100
import org.openide.xml.XMLUtil;
100
101
101
import static org.netbeans.core.output2.OutputTab.ACTION.*;
102
import static org.netbeans.core.output2.OutputTab.ACTION.*;
102
import org.openide.windows.IOProvider;
103
import org.netbeans.core.output2.ui.OutputKeymapManager;
103
104
104
105
105
/**
106
/**
Lines 716-721 Link Here
716
    private final Map<ACTION, TabAction> actions = new EnumMap<ACTION, TabAction>(ACTION.class);;
717
    private final Map<ACTION, TabAction> actions = new EnumMap<ACTION, TabAction>(ACTION.class);;
717
718
718
    private void createActions() {
719
    private void createActions() {
720
        KeyStrokeUtils.refreshActionCache();
719
        for (ACTION a : ACTION.values()) {
721
        for (ACTION a : ACTION.values()) {
720
            TabAction action;
722
            TabAction action;
721
            switch(a) {
723
            switch(a) {
Lines 782-791 Link Here
782
        TabAction(ACTION action, String bundleKey) {
784
        TabAction(ACTION action, String bundleKey) {
783
            if (bundleKey != null) {
785
            if (bundleKey != null) {
784
                String name = NbBundle.getMessage(OutputTab.class, bundleKey);
786
                String name = NbBundle.getMessage(OutputTab.class, bundleKey);
785
                KeyStroke accelerator = getAcceleratorFor(bundleKey);
787
                List<KeyStroke[]> accels = getAcceleratorsFor(action);
786
                this.action = action;
788
                this.action = action;
787
                putValue(NAME, name);
789
                putValue(NAME, name);
788
                putValue(ACCELERATOR_KEY, accelerator);
790
                if (accels != null && accels.size() > 0) {
791
                    List<KeyStroke> l = new ArrayList<KeyStroke>(accels.size());
792
                    for (KeyStroke[] ks : accels) {
793
                        if (ks.length == 1) { // ignore multi-key accelerators
794
                            l.add(ks[0]);
795
                        }
796
                    }
797
                    if (l.size() > 0) {
798
                        putValue(ACCELERATORS_KEY,
799
                                l.toArray(new KeyStroke[l.size()]));
800
                        putValue(ACCELERATOR_KEY, l.get(0));
801
                    }
802
                }
789
            }
803
            }
790
        }
804
        }
791
805
Lines 814-828 Link Here
814
         * Get a keyboard accelerator from the resource bundle, with special handling
828
         * Get a keyboard accelerator from the resource bundle, with special handling
815
         * for the mac keyboard layout.
829
         * for the mac keyboard layout.
816
         *
830
         *
817
         * @param name The bundle key prefix
831
         * @param action Action to get accelerator for.
818
         * @return A keystroke
832
         * @return A keystroke
819
         */
833
         */
820
        private KeyStroke getAcceleratorFor(String name) {
834
        private List<KeyStroke[]> getAcceleratorsFor(ACTION action) {
821
            String key = name + ".accel"; //NOI18N
835
            switch (action) {
822
            if (Utilities.isMac()) {
836
                case COPY:
823
                key += ".mac"; //NOI18N
837
                    return KeyStrokeUtils.getKeyStrokesForAction(
838
                            "copy-to-clipboard", null);                 //NOI18N
839
                case PASTE:
840
                    return KeyStrokeUtils.getKeyStrokesForAction(
841
                            "paste-from-clipboard", null);              //NOI18N
842
                case SAVEAS:
843
                    return KeyStrokeUtils.getKeyStrokesForAction(
844
                            OutputKeymapManager.SAVE_AS_ACTION_ID, null);
845
                case CLOSE:
846
                    return KeyStrokeUtils.getKeyStrokesForAction(
847
                            OutputKeymapManager.CLOSE_ACTION_ID, null);
848
                case NEXT_ERROR:
849
                    return KeyStrokeUtils.getKeyStrokesForAction(
850
                            "next-error", null);                        //NOI18N
851
                case PREV_ERROR:
852
                    return KeyStrokeUtils.getKeyStrokesForAction(
853
                            "previous-error", null);                    //NOI18N
854
                case SELECT_ALL:
855
                    return KeyStrokeUtils.getKeyStrokesForAction(
856
                            "select-all", null);                        //NOI18N
857
                case FIND:
858
                    return KeyStrokeUtils.getKeyStrokesForAction(
859
                            "incremental-search-forward", null);        //NOI18N
860
                case FIND_NEXT:
861
                    return KeyStrokeUtils.getKeyStrokesForAction(
862
                            "find-next", null);                         //NOI18N
863
                case FIND_PREVIOUS:
864
                    return KeyStrokeUtils.getKeyStrokesForAction(
865
                            "find-previous", null);                     //NOI18N
866
                case FILTER:
867
                    return KeyStrokeUtils.getKeyStrokesForAction(
868
                            OutputKeymapManager.FILTER_ACTION_ID, null);
869
                case LARGER_FONT:
870
                    return KeyStrokeUtils.getKeyStrokesForAction(
871
                            OutputKeymapManager.LARGER_FONT_ACTION_ID, null);
872
                case SMALLER_FONT:
873
                    return KeyStrokeUtils.getKeyStrokesForAction(
874
                            OutputKeymapManager.SMALLER_FONT_ACTION_ID, null);
875
                case FONT_TYPE:
876
                    return KeyStrokeUtils.getKeyStrokesForAction(
877
                            OutputKeymapManager.FONT_TYPE_ACTION_ID, null);
878
                case CLEAR:
879
                    return KeyStrokeUtils.getKeyStrokesForAction(
880
                            OutputKeymapManager.CLEAR_ACTION_ID, null);
881
                case WRAP:
882
                    return KeyStrokeUtils.getKeyStrokesForAction(
883
                            OutputKeymapManager.WRAP_ACTION_ID, null);
884
                default:
885
                    return null;
824
            }
886
            }
825
            return Utilities.stringToKey(NbBundle.getMessage(OutputTab.class, key));
826
        }
887
        }
827
888
828
        public ACTION getAction() {
889
        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/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 (+10 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.modules.options.keymap</code-name-base>
50
            <code-name-base>org.netbeans.modules.options.keymap</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <release-version>1</release-version>
58
                        <specification-version>1.15</specification-version>
59
                    </run-dependency>
60
                </dependency>
61
                <dependency>
53
                    <code-name-base>org.netbeans.modules.options.api</code-name-base>
62
                    <code-name-base>org.netbeans.modules.options.api</code-name-base>
54
                    <build-prerequisite/>
63
                    <build-prerequisite/>
55
                    <compile-dependency/>
64
                    <compile-dependency/>
Lines 152-157 Link Here
152
                </test-type>
161
                </test-type>
153
            </test-dependencies>
162
            </test-dependencies>
154
            <friend-packages>
163
            <friend-packages>
164
                <friend>org.netbeans.core.output2</friend>
155
                <friend>org.netbeans.modules.editor.macros</friend>
165
                <friend>org.netbeans.modules.editor.macros</friend>
156
                <friend>org.netbeans.modules.jumpto</friend>
166
                <friend>org.netbeans.modules.jumpto</friend>
157
                <friend>org.netbeans.modules.jvi</friend>
167
                <friend>org.netbeans.modules.jvi</friend>
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/Utils.java (-13 / +166 lines)
Lines 42-51 Link Here
42
 * made subject to such option by the copyright holder.
42
 * made subject to such option by the copyright holder.
43
 */
43
 */
44
44
45
package org.netbeans.modules.options.keymap;
45
package org.netbeans.core.options.keymap.api;
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.util.ArrayList;
49
import java.util.Arrays;
50
import java.util.Collection;
51
import java.util.Collections;
52
import java.util.LinkedList;
53
import java.util.List;
54
import java.util.StringTokenizer;
55
import java.util.logging.Level;
56
import java.util.logging.Logger;
48
import javax.swing.KeyStroke;
57
import javax.swing.KeyStroke;
58
import org.netbeans.api.annotations.common.CheckForNull;
59
import org.netbeans.api.annotations.common.NonNull;
60
import org.netbeans.api.annotations.common.NullAllowed;
61
import org.openide.util.Lookup;
49
import org.openide.util.Utilities;
62
import org.openide.util.Utilities;
50
63
51
64
Lines 53-69 Link Here
53
 *
66
 *
54
 * @author Jan Jancura
67
 * @author Jan Jancura
55
 */
68
 */
56
class Utils {
69
public class KeyStrokeUtils {
57
    
70
58
    
71
    private static final Logger LOG = Logger.getLogger(
59
    static String getKeyStrokesAsText (KeyStroke[] keyStrokes, String delim) {
72
            KeyStrokeUtils.class.getName());
60
        if (keyStrokes == null) return "";
73
61
        if (keyStrokes.length == 0) return "";
74
    /**
62
        StringBuffer sb = new StringBuffer (getKeyStrokeAsText (keyStrokes [0]));
75
     * Convert an array of {@link KeyStroke key stroke} to a string composed of
76
     * human-readable names of these key strokes, delimited by {@code delim}.
77
     */
78
    public static String getKeyStrokesAsText(
79
            @NullAllowed KeyStroke[] keyStrokes, @NonNull String delim) {
80
        if (keyStrokes == null) {
81
            return "";                                                  //NOI18N
82
        }
83
        if (keyStrokes.length == 0) {
84
            return "";                                                  //NOI18N
85
        }
86
        StringBuilder sb = new StringBuilder(getKeyStrokeAsText(keyStrokes[0]));
63
        int i, k = keyStrokes.length;
87
        int i, k = keyStrokes.length;
64
        for (i = 1; i < k; i++)
88
        for (i = 1; i < k; i++) {
65
            sb.append (delim).append (getKeyStrokeAsText (keyStrokes [i]));
89
            sb.append(delim).append(getKeyStrokeAsText(keyStrokes[i]));
66
        return new String (sb);
90
        }
91
        return new String(sb);
67
    }
92
    }
68
93
69
    // Important: keep in sync with Editor Settings Storage StorageSupport
94
    // Important: keep in sync with Editor Settings Storage StorageSupport
Lines 90-96 Link Here
90
        }
115
        }
91
    }
116
    }
92
    
117
    
93
    static KeyStroke getKeyStroke (String keyStroke) {
118
    /**
119
     * Convert human-readable keystroke name to {@link KeyStroke} object.
120
     */
121
    public static @CheckForNull KeyStroke getKeyStroke(
122
            @NonNull String keyStroke) {
123
94
        int modifiers = 0;
124
        int modifiers = 0;
95
        while (true) {
125
        while (true) {
96
            if (keyStroke.startsWith(EMACS_CTRL)) {
126
            if (keyStroke.startsWith(EMACS_CTRL)) {
Lines 124-130 Link Here
124
        }
154
        }
125
    }
155
    }
126
    
156
    
127
    static String getKeyStrokeAsText (KeyStroke keyStroke) {
157
    /**
158
     * Get human-readable name for a {@link KeyStroke}.
159
     */
160
    public static String getKeyStrokeAsText(@NonNull KeyStroke keyStroke) {
128
        int modifiers = keyStroke.getModifiers ();
161
        int modifiers = keyStroke.getModifiers ();
129
        StringBuilder sb = new StringBuilder ();
162
        StringBuilder sb = new StringBuilder ();
130
        if ((modifiers & InputEvent.CTRL_DOWN_MASK) > 0) {
163
        if ((modifiers & InputEvent.CTRL_DOWN_MASK) > 0) {
Lines 150-153 Link Here
150
        }
183
        }
151
        return sb.toString ();
184
        return sb.toString ();
152
    }
185
    }
186
187
    /**
188
     * Converts a textual representation of key strokes to an array of <code>KeyStroke</code>
189
     * objects. Please see {@link #keyStrokesToString(Collection<KeyStroke>, boolean)}
190
     * ror details about the available formats.
191
     *
192
     * @param key The textual representation of keystorkes to convert. Its format
193
     *   depends on the value of <code>emacsStyle</code> parameter.
194
     *
195
     * @return The <code>KeyStroke</code>s that were represented by the <code>key</code>
196
     *   text or <code>null</code> if the textual representation was malformed.
197
     * @since 1.16
198
     */
199
    public static @CheckForNull KeyStroke[] getKeyStrokes(@NonNull String key) {
200
        assert key != null : "The parameter key must not be null"; //NOI18N
201
202
        List<KeyStroke> result = new ArrayList<KeyStroke>();
203
        String delimiter = " "; //NOI18N
204
205
        for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N
206
            String ks = st.nextToken().trim();
207
            KeyStroke keyStroke = getKeyStroke(ks);
208
209
            if (keyStroke != null) {
210
                result.add(keyStroke);
211
            } else {
212
                if (LOG.isLoggable(Level.FINE)) {
213
                    LOG.log(Level.FINE,
214
                            "Invalid keystroke string: ''{0}''", ks);   //NOI18N
215
                }
216
                return null;
217
            }
218
        }
219
220
        return result.toArray(new KeyStroke[result.size()]);
221
    }
222
223
    /**
224
     * Find key strokes for an action. The currently selected profile is used.
225
     * If there are more than one key strokes, the most convenient one is the
226
     * first one in the array (index 0). If no key stroke is found and
227
     * {@code defaultKeyStroke} is not null, an array containing only
228
     * {@code defaultKeyStroke} is returned. If no key stroke is found and
229
     * {@code defaultKeyStroke} is null, an empty array is returned.
230
     *
231
     * @param actionId ID of action.
232
     * @param defaultKeyStroke Default key stroke, used in case no key stroke is
233
     * found for the action. Can be null.
234
     * @return Array of key strokes, or an empty array if no key stroke is
235
     * available.
236
     */
237
    public static List<KeyStroke[]> getKeyStrokesForAction(@NonNull String actionId,
238
            @NullAllowed KeyStroke defaultKeyStroke) {
239
        for (ShortcutsFinder sf : Lookup.getDefault().lookupAll(
240
                ShortcutsFinder.class)) {
241
            ShortcutAction sa = sf.findActionForId(actionId);
242
            if (sa != null) {
243
                String[] shortcuts = sf.getShortcuts(sa);
244
                if (shortcuts != null && shortcuts.length > 0) {
245
                    List<KeyStroke[]> ks = new LinkedList<KeyStroke[]>();
246
                    for (int i = 0; i < shortcuts.length; i++) {
247
                        if (shortcuts[i] != null) {
248
                            KeyStroke s[] = getKeyStrokes(shortcuts[i]);
249
                            if (s != null) {
250
                                ks.add(s);
251
                            }
252
                        }
253
                    }
254
                    return sortKeyStrokesByPreference(ks);
255
                }
256
            }
257
        }
258
        return defaultKeyStroke == null
259
                ? Collections.<KeyStroke[]>emptyList()
260
                : Collections.singletonList(new KeyStroke[]{defaultKeyStroke});
261
    }
262
263
    /**
264
     * Sort the list, so that the most appropriate accelerator is at index 0.
265
     */
266
    private static List<KeyStroke[]> sortKeyStrokesByPreference(
267
            List<KeyStroke[]> keystrokes) {
268
        if (keystrokes.size() < 2) {
269
            return keystrokes;
270
        }
271
        KeyStroke best[] = null;
272
        boolean isSolaris =
273
                Utilities.getOperatingSystem() == Utilities.OS_SOLARIS;
274
        for (int i = 0; i < keystrokes.size(); i++) {
275
            KeyStroke[] ks = keystrokes.get(i);
276
            if (ks.length > 1) {
277
                continue;
278
            }
279
            boolean solarisKey = ks[0].getKeyCode() >= KeyEvent.VK_STOP
280
                    && ks[0].getKeyCode() <= KeyEvent.VK_CUT;
281
            if (isSolaris == solarisKey
282
                    && (best == null
283
                    || best[0].getKeyCode() > ks[0].getKeyCode())) {
284
                //Solaris key on solaris OS or other key on other OS.
285
                best = ks;
286
            }
287
        }
288
        if (best != null) {
289
            keystrokes.remove(best);
290
            keystrokes.add(0, best);
291
        }
292
        return keystrokes;
293
    }
294
295
    /**
296
     * Force caches to be refreshed, so that
297
     * {@link #getKeyStrokesForAction(String, KeyStroke)} returns correct and
298
     * up-to-date results.
299
     */
300
    public static void refreshActionCache() {
301
        for (ShortcutsFinder sf :
302
                Lookup.getDefault().lookupAll(ShortcutsFinder.class)) {
303
            sf.refreshActions();
304
        }
305
    }
153
}
306
}
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/KeymapViewModel.java (-3 / +6 lines)
Lines 68-78 Link Here
68
import javax.swing.SwingUtilities;
68
import javax.swing.SwingUtilities;
69
import javax.swing.event.TableModelEvent;
69
import javax.swing.event.TableModelEvent;
70
import javax.swing.table.DefaultTableModel;
70
import javax.swing.table.DefaultTableModel;
71
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
71
import org.netbeans.core.options.keymap.api.ShortcutAction;
72
import org.netbeans.core.options.keymap.api.ShortcutAction;
72
import org.netbeans.core.options.keymap.api.ShortcutsFinder;
73
import org.netbeans.core.options.keymap.api.ShortcutsFinder;
73
import org.openide.DialogDescriptor;
74
import org.openide.DialogDescriptor;
74
import org.openide.DialogDisplayer;
75
import org.openide.DialogDisplayer;
75
import org.openide.ErrorManager;
76
import org.openide.ErrorManager;
77
import org.openide.util.Exceptions;
76
import org.openide.util.NbBundle;
78
import org.openide.util.NbBundle;
77
import org.openide.util.RequestProcessor;
79
import org.openide.util.RequestProcessor;
78
import org.openide.util.Utilities;
80
import org.openide.util.Utilities;
Lines 625-630 Link Here
625
    
627
    
626
    public void refreshActions () {
628
    public void refreshActions () {
627
        categoryToActionsCache = new HashMap<String, List<Object>> ();
629
        categoryToActionsCache = new HashMap<String, List<Object>> ();
630
        shortcutsCache = new HashMap<String, Map<ShortcutAction, Set<String>>>();
628
        model.refreshActions ();
631
        model.refreshActions ();
629
    }
632
    }
630
    
633
    
Lines 658-664 Link Here
658
                shortcutsCache = new HashMap<String, Map<ShortcutAction, Set<String>>> ();
661
                shortcutsCache = new HashMap<String, Map<ShortcutAction, Set<String>>> ();
659
                model = new KeymapModel ();
662
                model = new KeymapModel ();
660
                applyInProgress = false;
663
                applyInProgress = false;
661
    }
664
            }
662
        });
665
        });
663
    }
666
    }
664
    
667
    
Lines 766-772 Link Here
766
            Set<String> shortcuts = new LinkedHashSet<String> ();
769
            Set<String> shortcuts = new LinkedHashSet<String> ();
767
            for (String emacsShortcut: entry.getValue()) {
770
            for (String emacsShortcut: entry.getValue()) {
768
                KeyStroke[] keyStroke = Utilities.stringToKeys (emacsShortcut);
771
                KeyStroke[] keyStroke = Utilities.stringToKeys (emacsShortcut);
769
                shortcuts.add (Utils.getKeyStrokesAsText (keyStroke, " "));
772
                shortcuts.add (KeyStrokeUtils.getKeyStrokesAsText (keyStroke, " "));
770
            }
773
            }
771
            result.put (action, shortcuts);
774
            result.put (action, shortcuts);
772
        }
775
        }
Lines 784-790 Link Here
784
        List<KeyStroke> result = new ArrayList<KeyStroke> ();
787
        List<KeyStroke> result = new ArrayList<KeyStroke> ();
785
        while (st.hasMoreTokens ()) {
788
        while (st.hasMoreTokens ()) {
786
            String ks = st.nextToken ().trim ();
789
            String ks = st.nextToken ().trim ();
787
            KeyStroke keyStroke = Utils.getKeyStroke (ks);
790
            KeyStroke keyStroke = KeyStrokeUtils.getKeyStroke (ks);
788
            if (keyStroke == null) return null; // text is not parsable 
791
            if (keyStroke == null) return null; // text is not parsable 
789
            result.add (keyStroke);
792
            result.add (keyStroke);
790
        }
793
        }
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/ProfilesPanel.java (-2 / +3 lines)
Lines 56-61 Link Here
56
import javax.swing.AbstractListModel;
56
import javax.swing.AbstractListModel;
57
import javax.swing.JFileChooser;
57
import javax.swing.JFileChooser;
58
import javax.swing.KeyStroke;
58
import javax.swing.KeyStroke;
59
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
59
import org.netbeans.core.options.keymap.api.ShortcutAction;
60
import org.netbeans.core.options.keymap.api.ShortcutAction;
60
import org.openide.DialogDisplayer;
61
import org.openide.DialogDisplayer;
61
import org.openide.NotifyDescriptor;
62
import org.openide.NotifyDescriptor;
Lines 347-353 Link Here
347
        for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N
348
        for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N
348
            String ks = st.nextToken().trim();
349
            String ks = st.nextToken().trim();
349
350
350
            KeyStroke keyStroke = Utils.getKeyStroke(ks);
351
            KeyStroke keyStroke = KeyStrokeUtils.getKeyStroke(ks);
351
352
352
            if (keyStroke != null) {
353
            if (keyStroke != null) {
353
                buf.append(Utilities.keyToString(keyStroke, true));
354
                buf.append(Utilities.keyToString(keyStroke, true));
Lines 373-379 Link Here
373
            KeyStroke keyStroke = Utilities.stringToKey(ks);
374
            KeyStroke keyStroke = Utilities.stringToKey(ks);
374
375
375
            if (keyStroke != null) {
376
            if (keyStroke != null) {
376
                buf.append(Utils.getKeyStrokeAsText(keyStroke));
377
                buf.append(KeyStrokeUtils.getKeyStrokeAsText(keyStroke));
377
                if (st.hasMoreTokens())
378
                if (st.hasMoreTokens())
378
                    buf.append(' ');
379
                    buf.append(' ');
379
            } else {
380
            } else {
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/ShortcutListener.java (-1 / +2 lines)
Lines 45-50 Link Here
45
import java.awt.event.KeyListener;
45
import java.awt.event.KeyListener;
46
import javax.swing.JTextField;
46
import javax.swing.JTextField;
47
import javax.swing.KeyStroke;
47
import javax.swing.KeyStroke;
48
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
48
49
49
/**
50
/**
50
 * KeyListener trasforming keystrokes to human-readable and displaying them
51
 * KeyListener trasforming keystrokes to human-readable and displaying them
Lines 125-131 Link Here
125
    }
126
    }
126
127
127
    private void addKeyStroke(KeyStroke keyStroke, boolean add) {
128
    private void addKeyStroke(KeyStroke keyStroke, boolean add) {
128
        String k = Utils.getKeyStrokeAsText(keyStroke);
129
        String k = KeyStrokeUtils.getKeyStrokeAsText(keyStroke);
129
        if (key.equals("")) { //NOI18N
130
        if (key.equals("")) { //NOI18N
130
            textField.setText(k);
131
            textField.setText(k);
131
            if (add)
132
            if (add)
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/ShortcutProvider.java (-6 / +7 lines)
Lines 47-52 Link Here
47
import java.util.LinkedHashSet;
47
import java.util.LinkedHashSet;
48
import java.util.Set;
48
import java.util.Set;
49
import javax.swing.KeyStroke;
49
import javax.swing.KeyStroke;
50
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
50
import org.openide.util.Utilities;
51
import org.openide.util.Utilities;
51
52
52
/**
53
/**
Lines 129-163 Link Here
129
130
130
            //CTRL
131
            //CTRL
131
            for (int i = 0; i < letters.length; i++) {
132
            for (int i = 0; i < letters.length; i++) {
132
                shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.CTRL_MASK)));
133
                shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.CTRL_MASK)));
133
            }
134
            }
134
135
135
            if (Utilities.isMac())
136
            if (Utilities.isMac())
136
                //META
137
                //META
137
                for (int i = 0; i < letters.length; i++) {
138
                for (int i = 0; i < letters.length; i++) {
138
                    shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.META_MASK)));
139
                    shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.META_MASK)));
139
                }
140
                }
140
            else
141
            else
141
                //ALT
142
                //ALT
142
                for (int i = 0; i < letters.length; i++) {
143
                for (int i = 0; i < letters.length; i++) {
143
                    shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.ALT_MASK)));
144
                    shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.ALT_MASK)));
144
                }
145
                }
145
146
146
            //CTRL+SHIFT
147
            //CTRL+SHIFT
147
            for (int i = 0; i < letters.length; i++) {
148
            for (int i = 0; i < letters.length; i++) {
148
                shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)));
149
                shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)));
149
150
150
            }
151
            }
151
152
152
            if (Utilities.isMac())
153
            if (Utilities.isMac())
153
                //SHIFT+META
154
                //SHIFT+META
154
                for (int i = 0; i < letters.length; i++) {
155
                for (int i = 0; i < letters.length; i++) {
155
                    shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.SHIFT_MASK | InputEvent.META_MASK)));
156
                    shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.SHIFT_MASK | InputEvent.META_MASK)));
156
                }
157
                }
157
            else
158
            else
158
                //SHIFT+ALT
159
                //SHIFT+ALT
159
                for (int i = 0; i < letters.length; i++) {
160
                for (int i = 0; i < letters.length; i++) {
160
                    shortcutSet.add(Utils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.SHIFT_MASK | InputEvent.ALT_MASK)));
161
                    shortcutSet.add(KeyStrokeUtils.getKeyStrokeAsText(KeyStroke.getKeyStroke(letters[i], InputEvent.SHIFT_MASK | InputEvent.ALT_MASK)));
161
                }
162
                }
162
        }
163
        }
163
        return shortcutSet;
164
        return shortcutSet;
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/ShortcutsDialog.form (-1 / +1 lines)
Lines 1-4 Link Here
1
<?xml version="1.1" encoding="UTF-8" ?>
1
<?xml version="1.0" encoding="UTF-8" ?>
2
2
3
<Form version="1.3" maxVersion="1.3" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
3
<Form version="1.3" maxVersion="1.3" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
4
  <AccessibilityProperties>
4
  <AccessibilityProperties>
(-)a/options.keymap/src/org/netbeans/modules/options/keymap/ShortcutsDialog.java (-1 / +2 lines)
Lines 58-63 Link Here
58
import javax.swing.JButton;
58
import javax.swing.JButton;
59
import javax.swing.JLabel;
59
import javax.swing.JLabel;
60
import javax.swing.KeyStroke;
60
import javax.swing.KeyStroke;
61
import org.netbeans.core.options.keymap.api.KeyStrokeUtils;
61
import org.netbeans.core.options.keymap.api.ShortcutAction;
62
import org.netbeans.core.options.keymap.api.ShortcutAction;
62
import org.netbeans.core.options.keymap.api.ShortcutsFinder;
63
import org.netbeans.core.options.keymap.api.ShortcutsFinder;
63
import org.openide.awt.Mnemonics;
64
import org.openide.awt.Mnemonics;
Lines 273-279 Link Here
273
            }
274
            }
274
            
275
            
275
            private void addKeyStroke (KeyStroke keyStroke, boolean add) {
276
            private void addKeyStroke (KeyStroke keyStroke, boolean add) {
276
                String k = Utils.getKeyStrokeAsText (keyStroke);
277
                String k = KeyStrokeUtils.getKeyStrokeAsText (keyStroke);
277
                if (key.equals ("")) { //NOI18N
278
                if (key.equals ("")) { //NOI18N
278
                    getTfShortcut().setText (k);
279
                    getTfShortcut().setText (k);
279
                    if (add) key = k;
280
                    if (add) key = k;
(-)a/options.keymap/test/unit/src/org/netbeans/core/options/keymap/api/KeyStrokeUtilsTest.java (+189 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.options.keymap.api;
43
44
import java.util.Collections;
45
import java.util.HashMap;
46
import java.util.HashSet;
47
import java.util.List;
48
import java.util.Map;
49
import java.util.Set;
50
import javax.swing.KeyStroke;
51
import org.netbeans.core.options.keymap.spi.KeymapManager;
52
import org.netbeans.junit.MockServices;
53
import org.netbeans.junit.NbTestCase;
54
55
/**
56
 *
57
 * @author jhavlin
58
 */
59
public class KeyStrokeUtilsTest extends NbTestCase {
60
61
    private static final String DEFAULT_PROFILE = "NetBeans";           //NOI18N
62
63
    public KeyStrokeUtilsTest(String name) {
64
        super(name);
65
    }
66
67
    @Override
68
    protected void setUp() throws Exception {
69
        MockServices.setServices(TestKeymapManager.class);
70
    }
71
72
    public void testGetKeyStrokesForAction() {
73
        List<KeyStroke[]> s1 = KeyStrokeUtils.getKeyStrokesForAction(
74
                "testX1", null);
75
        List<KeyStroke[]> s2 = KeyStrokeUtils.getKeyStrokesForAction(
76
                "testX2", null);
77
        assertEquals(1, s1.size());
78
        assertEquals(1, s2.size());
79
        assertEquals(1, s1.get(0).length);
80
        assertEquals(2, s2.get(0).length);
81
        assertEquals((int) 'O', s1.get(0)[0].getKeyCode());
82
        assertEquals((int) 'T', s2.get(0)[0].getKeyCode());
83
        assertEquals((int) 'M', s2.get(0)[1].getKeyCode());
84
    }
85
86
    public static class TestKeymapManager extends KeymapManager {
87
88
        private String profile = DEFAULT_PROFILE;
89
        private ShortcutAction sa1 = new TestShortcutAction("testX1");
90
        private ShortcutAction sa2 = new TestShortcutAction("testX2");
91
        private Map<ShortcutAction, Set<String>> defaultKeyMap =
92
                new HashMap<ShortcutAction, Set<String>>();
93
        private Map<ShortcutAction, Set<String>> currentKeyMap =
94
                new HashMap<ShortcutAction, Set<String>>();
95
        private Map<String, Set<ShortcutAction>> actionMap =
96
                new HashMap<String, Set<ShortcutAction>>();
97
98
        public TestKeymapManager() {
99
            super("Test");
100
            Set<ShortcutAction> allActions = new HashSet<ShortcutAction>();
101
            Collections.addAll(allActions, sa1, sa2);
102
            actionMap.put(DEFAULT_PROFILE, allActions);
103
            defaultKeyMap.put(sa1, Collections.singleton("C-O"));
104
            defaultKeyMap.put(sa2, Collections.singleton("M-T M-M"));
105
            currentKeyMap.putAll(defaultKeyMap);
106
        }
107
108
        @Override
109
        public Map<String, Set<ShortcutAction>> getActions() {
110
            return actionMap;
111
        }
112
113
        @Override
114
        public void refreshActions() {
115
        }
116
117
        @Override
118
        public Map<ShortcutAction, Set<String>> getKeymap(String profileName) {
119
            return currentKeyMap;
120
        }
121
122
        @Override
123
        public Map<ShortcutAction, Set<String>> getDefaultKeymap(String profileName) {
124
            return defaultKeyMap;
125
        }
126
127
        @Override
128
        public void saveKeymap(String profileName, Map<ShortcutAction, Set<String>> actionToShortcuts) {
129
            // nothing
130
        }
131
132
        @Override
133
        public List<String> getProfiles() {
134
            return Collections.singletonList(profile);
135
        }
136
137
        @Override
138
        public String getCurrentProfile() {
139
            return profile;
140
        }
141
142
        @Override
143
        public void setCurrentProfile(String profileName) {
144
            this.profile = profileName;
145
        }
146
147
        @Override
148
        public void deleteProfile(String profileName) {
149
            // nothing
150
        }
151
152
        @Override
153
        public boolean isCustomProfile(String profileName) {
154
            return !profileName.equals(DEFAULT_PROFILE);
155
        }
156
157
        private class TestShortcutAction implements ShortcutAction {
158
159
            public TestShortcutAction(String name) {
160
                this.name = name;
161
            }
162
            private String name;
163
164
            @Override
165
            public String getDisplayName() {
166
                return name;
167
            }
168
169
            @Override
170
            public String getId() {
171
                return name;
172
            }
173
174
            @Override
175
            public String getDelegatingActionId() {
176
                return null;
177
            }
178
179
            @Override
180
            public ShortcutAction getKeymapManagerInstance(String keymapManagerName) {
181
                if (keymapManagerName.equals(TestKeymapManager.this.getName())) {
182
                    return this;
183
                } else {
184
                    return null;
185
                }
186
            }
187
        }
188
    }
189
}

Return to bug 58126