diff --git a/core.output2/nbproject/project.xml b/core.output2/nbproject/project.xml --- a/core.output2/nbproject/project.xml +++ b/core.output2/nbproject/project.xml @@ -50,6 +50,14 @@ org.netbeans.core.output2 + org.netbeans.modules.options.keymap + + + + 1.17 + + + org.openide.actions diff --git a/core.output2/src/org/netbeans/core/output2/OutputTab.java b/core.output2/src/org/netbeans/core/output2/OutputTab.java --- a/core.output2/src/org/netbeans/core/output2/OutputTab.java +++ b/core.output2/src/org/netbeans/core/output2/OutputTab.java @@ -61,6 +61,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumMap; import java.util.List; import java.util.Map; @@ -82,6 +83,8 @@ import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.text.Document; +import org.netbeans.core.options.keymap.api.ShortcutAction; +import org.netbeans.core.options.keymap.api.ShortcutsFinder; import org.netbeans.core.output2.Controller.ControllerOutputEvent; import org.netbeans.core.output2.ui.AbstractOutputPane; import org.netbeans.core.output2.ui.AbstractOutputTab; @@ -99,7 +102,9 @@ import org.openide.xml.XMLUtil; import static org.netbeans.core.output2.OutputTab.ACTION.*; -import org.openide.windows.IOProvider; +import org.netbeans.core.output2.ui.OutputKeymapManager; +import org.netbeans.core.output2.ui.KeyStrokeNameSupport; +import org.openide.util.Lookup; /** @@ -782,10 +787,13 @@ TabAction(ACTION action, String bundleKey) { if (bundleKey != null) { String name = NbBundle.getMessage(OutputTab.class, bundleKey); - KeyStroke accelerator = getAcceleratorFor(bundleKey); + KeyStroke[] accels = getAcceleratorFor(action); this.action = action; putValue(NAME, name); - putValue(ACCELERATOR_KEY, accelerator); + if (accels != null && accels.length > 0) { + putValue(ACCELERATORS_KEY, accels); + putValue(ACCELERATOR_KEY, getAccelForPopUp(accels)); + } } } @@ -814,15 +822,113 @@ * Get a keyboard accelerator from the resource bundle, with special handling * for the mac keyboard layout. * - * @param name The bundle key prefix + * @param action Action to get accelerator for. * @return A keystroke */ - private KeyStroke getAcceleratorFor(String name) { - String key = name + ".accel"; //NOI18N - if (Utilities.isMac()) { - key += ".mac"; //NOI18N + private KeyStroke[] getAcceleratorFor(ACTION action) { + switch (action) { + case COPY: + return getKeyStrokeForAction( + "copy-to-clipboard"); //NOI18N + case PASTE: + return getKeyStrokeForAction( + "paste-from-clipboard"); //NOI18N + case SAVEAS: + return getKeyStrokeForAction( + OutputKeymapManager.SAVE_AS_ACTION_ID); + case CLOSE: + return getKeyStrokeForAction( + OutputKeymapManager.CLOSE_ACTION_ID); + case NEXT_ERROR: + return getKeyStrokeForAction("next-error"); //NOI18N + case PREV_ERROR: + return getKeyStrokeForAction("previous-error"); //NOI18N + case SELECT_ALL: + return getKeyStrokeForAction("select-all"); //NOI18N + case FIND: + return getKeyStrokeForAction( + "incremental-search-forward"); //NOI18N + case FIND_NEXT: + return getKeyStrokeForAction("find-next"); //NOI18N + case FIND_PREVIOUS: + return getKeyStrokeForAction("find-previous"); //NOI18N + case FILTER: + return getKeyStrokeForAction( + OutputKeymapManager.FILTER_ACTION_ID); + case LARGER_FONT: + return getKeyStrokeForAction( + OutputKeymapManager.LARGER_FONT_ACTION_ID); + case SMALLER_FONT: + return getKeyStrokeForAction( + OutputKeymapManager.SMALLER_FONT_ACTION_ID); + case FONT_TYPE: + return getKeyStrokeForAction( + OutputKeymapManager.FONT_TYPE_ACTION_ID); + case CLEAR: + return getKeyStrokeForAction( + OutputKeymapManager.CLEAR_ACTION_ID); + case WRAP: + return getKeyStrokeForAction( + OutputKeymapManager.WRAP_ACTION_ID); + default: + return null; } - return Utilities.stringToKey(NbBundle.getMessage(OutputTab.class, key)); + } + + private KeyStroke[] getKeyStrokeForAction(String actionId) { + for (ShortcutsFinder sf : Lookup.getDefault().lookupAll( + ShortcutsFinder.class)) { + ShortcutAction sa = sf.findActionForId(actionId); + if (sa != null) { + String[] shortcuts = sf.getShortcuts(sa); + if (shortcuts != null && shortcuts.length > 0) { + KeyStroke[] ks = new KeyStroke[shortcuts.length]; + int valid = 0; + for (int i = 0; i < shortcuts.length; i++) { + if (shortcuts[i] != null) { + KeyStroke s = humanStringToStroke(shortcuts[i]); + if (s != null) { + ks[valid++] = s; + } + } + } + return Arrays.copyOfRange(ks, 0, valid); + } + } + } + return null; + } + + private KeyStroke humanStringToStroke(String s) { + if (s == null) { + return null; + } + KeyStroke[] strokes = KeyStrokeNameSupport.stringToKeyStrokes(s); + if (strokes.length > 0) { + return strokes[0]; + } else { + return null; + } + } + + /** + * Get the most appropriate accelerator for pop-up menu. + */ + public KeyStroke getAccelForPopUp(KeyStroke[] keystrokes) { + KeyStroke best = null; + boolean isSolaris = + Utilities.getOperatingSystem() == Utilities.OS_SOLARIS; + for (KeyStroke ks : keystrokes) { + boolean solarisKey = ks.getKeyCode() >= KeyEvent.VK_STOP + && ks.getKeyCode() <= KeyEvent.VK_CUT; + if (isSolaris == solarisKey + && (best == null + || best.getKeyCode() > ks.getKeyCode())) { + //Solaris key on solaris OS or other key on other OS. + best = ks; + } + } + return best == null ? keystrokes[0] : best; } public ACTION getAction() { diff --git a/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputTab.java b/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputTab.java --- a/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputTab.java +++ b/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputTab.java @@ -68,6 +68,7 @@ private boolean inputVisible = false; private AbstractOutputPane outputPane; private Action[] actions = new Action[0]; + protected static final String ACCELERATORS_KEY = "ACCELERATORS_KEY";//NOI18N private Component toFocus; @@ -191,22 +192,28 @@ //It is a Controller.ControllerAction - don't create a memory leak by listening to it a = new WeakAction(a); } - KeyStroke accel = null; + KeyStroke[] accels = null; String name; - Object o = a.getValue (Action.ACCELERATOR_KEY); - if (o instanceof KeyStroke) { - accel = (KeyStroke) o; + Object o = a.getValue(ACCELERATORS_KEY); + if (o instanceof KeyStroke[]) { + accels = (KeyStroke[]) o; } name = (String) a.getValue(Action.NAME); - if (accel != null) { - if (Controller.LOG) Controller.log ("Installed action " + name + " on " + accel); - // if the logic here changes, check the popup escaping hack in Controller - // it temporarily removes the VK_ESCAPE from input maps.. - JComponent c = getOutputPane().textView; - c.getInputMap().put(accel, name); - c.getActionMap().put(name, a); - getInputMap (WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put (accel, name); - getActionMap().put(name, a); + if (accels != null) { + for (KeyStroke accel : accels) { + if (Controller.LOG) { + Controller.log("Installed action " //NOI18N + + name + " on " + accel); //NOI18N + } + // if the logic here changes, check the popup escaping hack in + // Controller it temporarily removes the VK_ESCAPE from input + // maps.. + JComponent c = getOutputPane().textView; + c.getInputMap().put(accel, name); + c.getActionMap().put(name, a); + getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(accel, name); + getActionMap().put(name, a); + } } } diff --git a/editor.settings.storage/src/org/netbeans/modules/editor/settings/storage/spi/support/StorageSupport.java b/core.output2/src/org/netbeans/core/output2/ui/KeyStrokeNameSupport.java copy from editor.settings.storage/src/org/netbeans/modules/editor/settings/storage/spi/support/StorageSupport.java copy to core.output2/src/org/netbeans/core/output2/ui/KeyStrokeNameSupport.java --- a/editor.settings.storage/src/org/netbeans/modules/editor/settings/storage/spi/support/StorageSupport.java +++ b/core.output2/src/org/netbeans/core/output2/ui/KeyStrokeNameSupport.java @@ -41,109 +41,48 @@ * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ -package org.netbeans.modules.editor.settings.storage.spi.support; +package org.netbeans.core.output2.ui; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.KeyStroke; -import org.netbeans.modules.editor.settings.storage.*; -import org.openide.filesystems.FileObject; import org.openide.util.Utilities; -public final class StorageSupport { +public final class KeyStrokeNameSupport { - private static final Logger LOG = Logger.getLogger(StorageSupport.class.getName()); + private static final Logger LOG = Logger.getLogger(KeyStrokeNameSupport.class.getName()); private static Map names; - private StorageSupport() { + private KeyStrokeNameSupport() { } - public static String getLocalizingBundleMessage(FileObject fo, String key, String defaultValue) { - return Utils.getLocalizedName(fo, key, defaultValue, false); - } - - /** - * Converts a list of KeyStrokes to its textual representation. There - * are two available formats for the textual representation: - * - *
  • Human readable - this format encodes a KeyStroke to - * a string that looks like for example 'Ctrl+A' or 'Alt+Shift+M'. - *
  • Emacs style - this format encodes a KeyStroke to - * a string that's known from Emacs and that looks like for example 'C-A' or 'AS-M'. - * It uses methods from org.openide.util.Utilities, which take - * care of Mac OS specifics and use 'D' and 'O' wildcards for encoding 'Ctrl' - * and 'Alt' keys. - * - * @param keys The KeyStrokes to convert. - * @param emacsStyle If true the returned string will be in so called - * Emacs style, ortherwise it will be in human readable format. - * - * @return The textual representation of KeyStrokes passed in. - * @since 1.16 - */ - public static String keyStrokesToString(Collection keys, boolean emacsStyle) { - StringBuilder sb = new StringBuilder(); - - for (Iterator it = keys.iterator(); it.hasNext(); ) { - KeyStroke keyStroke = it.next(); - if (emacsStyle) { - sb.append(Utilities.keyToString(keyStroke, true)); - if (it.hasNext()) { - sb.append('$'); //NOI18N - } - } else { - sb.append(keyStrokeToHumanReadableString(keyStroke)); - if (it.hasNext()) { - sb.append(' '); //NOI18N - } - } - } - - return sb.toString(); - } - /** * Converts a textual representation of key strokes to an array of KeyStroke - * objects. Please see {@link #keyStrokesToString(Collection, boolean)} - * ror details about the available formats. + * objects. * - * @param key The textual representation of keystorkes to convert. Its format - * depends on the value of emacsStyle parameter. - * @param emacsStyle If true the key string is expected to be - * in so called emacs format, ortherwise it will be in human readable format. - * + * @param key The textual representation of keystorkes to convert. * @return The KeyStrokes that were represented by the key * text or null if the textual representation was malformed. - * @since 1.16 */ - public static KeyStroke[] stringToKeyStrokes(String key, boolean emacsStyle) { + public static KeyStroke[] stringToKeyStrokes(String key) { assert key != null : "The parameter key must not be null"; //NOI18N List result = new ArrayList(); - String delimiter = emacsStyle ? "$" : " "; //NOI18N + String delimiter = " "; //NOI18N for(StringTokenizer st = new StringTokenizer(key, delimiter); st.hasMoreTokens();) { //NOI18N String ks = st.nextToken().trim(); - KeyStroke keyStroke; - - if (emacsStyle) { - keyStroke = Utilities.stringToKey(ks); - } else { - keyStroke = humanReadableStringToKeyStroke(ks); - } - + KeyStroke keyStroke = humanReadableStringToKeyStroke(ks); if (keyStroke != null) { result.add(keyStroke); } else { @@ -210,31 +149,4 @@ return names; } } - - private static String keyStrokeToHumanReadableString(KeyStroke keyStroke) { - int modifiers = keyStroke.getModifiers(); - StringBuilder sb = new StringBuilder(); - if ((modifiers & InputEvent.CTRL_DOWN_MASK) > 0) { - sb.append(EMACS_CTRL); - } - if ((modifiers & InputEvent.ALT_DOWN_MASK) > 0) { - sb.append(EMACS_ALT); - } - if ((modifiers & InputEvent.SHIFT_DOWN_MASK) > 0) { - sb.append(EMACS_SHIFT); - } - if ((modifiers & InputEvent.META_DOWN_MASK) > 0) { - sb.append(EMACS_META); - } - if (keyStroke.getKeyCode() != KeyEvent.VK_SHIFT && - keyStroke.getKeyCode() != KeyEvent.VK_CONTROL && - keyStroke.getKeyCode() != KeyEvent.VK_META && - keyStroke.getKeyCode() != KeyEvent.VK_ALT && - keyStroke.getKeyCode() != KeyEvent.VK_ALT_GRAPH - ) { - sb.append(Utilities.keyToString(KeyStroke.getKeyStroke(keyStroke.getKeyCode(), 0))); - } - return sb.toString(); - } - } diff --git a/core.output2/src/org/netbeans/core/output2/ui/OutputKeymapManager.java b/core.output2/src/org/netbeans/core/output2/ui/OutputKeymapManager.java new file mode 100644 --- /dev/null +++ b/core.output2/src/org/netbeans/core/output2/ui/OutputKeymapManager.java @@ -0,0 +1,334 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ +package org.netbeans.core.output2.ui; + +import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.core.options.keymap.api.ShortcutAction; +import org.netbeans.core.options.keymap.spi.KeymapManager; +import org.netbeans.core.output2.NbIOProvider; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author jhavlin + */ +@ServiceProvider(service = KeymapManager.class) +public class OutputKeymapManager extends KeymapManager { + + private static final Logger LOG = Logger.getLogger( + OutputKeymapManager.class.getName()); + private static final String CATEGORY_NAME = NbBundle.getMessage( + NbIOProvider.class, "OpenIDE-Module-Name"); //NOI18N + /** + * ID of actions in keymap settings panel. + */ + public static final String CLEAR_ACTION_ID = + "output-window-clear"; //NOI18N + public static final String FILTER_ACTION_ID = + "output-window-filter"; //NOI18N + public static final String LARGER_FONT_ACTION_ID = + "output-window-larger-font"; //NOI18N + public static final String SMALLER_FONT_ACTION_ID = + "output-window-smaller-font"; //NOI18N + public static final String CLOSE_ACTION_ID = + "output-window-close"; //NOI18N + public static final String FONT_TYPE_ACTION_ID = + "output-window-font-type"; //NOI18N + public static final String SAVE_AS_ACTION_ID = + "output-window-save-as"; //NOI18N + public static final String WRAP_ACTION_ID = + "output-window-wrap"; //NOI18N + /** + * Constants for persistence. + */ + public static final String STORAGE_DIR = + "org-netbeans-core-output2/actions/"; //NOI18N + public static final String SHORTCUT_PREFIX = "sc"; //NOI18N + /** + * Actions + */ + private final OutWinShortCutAction wrap = new OutWinShortCutAction( + WRAP_ACTION_ID, "ACTION_WRAP"); //NOI18N + private final OutWinShortCutAction clear = new OutWinShortCutAction( + CLEAR_ACTION_ID, "ACTION_CLEAR"); //NOI18N + private final OutWinShortCutAction filter = new OutWinShortCutAction( + FILTER_ACTION_ID, "ACTION_FILTER"); //NOI18N + private final OutWinShortCutAction largerFont = new OutWinShortCutAction( + LARGER_FONT_ACTION_ID, "ACTION_LARGER_FONT"); //NOI18N + private final OutWinShortCutAction smallerFont = new OutWinShortCutAction( + SMALLER_FONT_ACTION_ID, "ACTION_SMALLER_FONT"); //NOI18N + private final OutWinShortCutAction closeWindow = new OutWinShortCutAction( + CLOSE_ACTION_ID, "ACTION_CLOSE"); //NOI18N + private final OutWinShortCutAction fontType = new OutWinShortCutAction( + FONT_TYPE_ACTION_ID, "ACTION_FONT_TYPE"); //NOI18N + private final OutWinShortCutAction saveAs = new OutWinShortCutAction( + SAVE_AS_ACTION_ID, "ACTION_SAVEAS"); //NOI18N + /** + * Map of keymaps. Keys are profile names. + */ + Map>> keymaps = + new HashMap>>(); + /** + * The default keymap. Used if keys for a profile are not set. + */ + Map> defaultKeymap = + new HashMap>(); + /** + * List of all actions. + */ + private final Set allActions = + new HashSet(); + /** + * Map of actions of categories. There is only one category in this case. + */ + Map> actions = + new HashMap>(); + + public OutputKeymapManager() { + super("OutputWindowKeymapManager"); //NOI18N + actions = new HashMap>(); + Collections.addAll(allActions, wrap, clear, filter, largerFont, + smallerFont, closeWindow, fontType, saveAs); + Set set = new HashSet(); + set.addAll(allActions); + actions.put(CATEGORY_NAME, set); + fillDefaultKeyMap(); + loadShortCuts(); + } + + private void fillDefaultKeyMap() { + for (OutWinShortCutAction a : allActions) { + String dflt = a.getDefaultShortcut(); + defaultKeymap.put(a, (dflt != null && !dflt.isEmpty()) + ? Collections.singleton(dflt) + : Collections.emptySet()); + } + } + + @Override + public Map> getActions() { + return actions; + } + + @Override + public void refreshActions() { + } + + @Override + public Map> getKeymap(String profileName) { + Map> km = keymaps.get(profileName); + if (km == null) { + km = new HashMap>(defaultKeymap); + keymaps.put(profileName, km); + } + return km; + } + + @Override + public Map> getDefaultKeymap( + String profileName) { + return defaultKeymap; + } + + @Override + public void saveKeymap(String profileName, + Map> actionToShortcuts) { + + Map> newShortcuts = + new HashMap>(); + keymaps.put(profileName, newShortcuts); + for (OutWinShortCutAction owsa : allActions) { + Set shortcuts = actionToShortcuts.get(owsa); + if (shortcuts == null) { + shortcuts = Collections.emptySet(); + } + newShortcuts.put(owsa, shortcuts); + } + storeShortCuts(profileName); + } + + @Override + public List getProfiles() { + return null; + } + + @Override + public String getCurrentProfile() { + return null; + } + + @Override + public void setCurrentProfile(String profileName) { + } + + @Override + public void deleteProfile(String profileName) { + } + + @Override + public boolean isCustomProfile(String profileName) { + return false; + } + + private class OutWinShortCutAction implements ShortcutAction { + + private String id; + private String bundleKey; + private String displayName; + private String defaultShortcut; + + public OutWinShortCutAction(String id, String bundleKey) { + this.id = id; + this.bundleKey = bundleKey; + this.displayName = NbBundle.getMessage( + NbIOProvider.class, bundleKey); + String nbKeysBundleKey = Utilities.isMac() + ? bundleKey + ".accel.mac" //NOI18N + : bundleKey + ".accel"; //NOI18N + String nbKeys = NbBundle.getMessage(NbIOProvider.class, + nbKeysBundleKey); + this.defaultShortcut = nbKeys; + } + + public String getId() { + return id; + } + + public String getBundleKey() { + return bundleKey; + } + + public String getDisplayName() { + return displayName; + } + + public String getDefaultShortcut() { + return defaultShortcut; + } + + @Override + public String getDelegatingActionId() { + return null; + } + + @Override + public ShortcutAction getKeymapManagerInstance( + String keymapManagerName) { + return null; + } + } + + private void storeShortCuts(String profileName) { + FileObject root = FileUtil.getConfigRoot(); + try { + FileObject actionsDir = FileUtil.createFolder( + root, STORAGE_DIR + profileName); + for (OutWinShortCutAction a : allActions) { + FileObject data = actionsDir.getFileObject(a.getId()); + if (data == null) { + data = actionsDir.createData(a.getId()); + } else if (data.isFolder()) { + throw new IOException(data + " is a folder."); //NOI18N + } + Enumeration atts = data.getAttributes(); + while (atts.hasMoreElements()) { + String attName = atts.nextElement(); + data.setAttribute(attName, null); + } + int index = 1; + if (keymaps.get(profileName).get(a) == null) { + continue; + } + for (String shortCut : keymaps.get(profileName).get(a)) { + data.setAttribute(SHORTCUT_PREFIX + index++, shortCut); + } + } + } catch (IOException e) { + LOG.log(Level.WARNING, "Cannot create folder", e); //NOI18N + } + } + + private void loadShortCuts() { + FileObject root = FileUtil.getConfigRoot(); + FileObject actionsDir = root.getFileObject(STORAGE_DIR); + if (actionsDir == null) { + return; + } + for (FileObject profileDir : actionsDir.getChildren()) { + if (!profileDir.isFolder()) { + continue; + } + Map> keymap = + new HashMap>(); + keymaps.put(profileDir.getName(), keymap); + for (OutWinShortCutAction a : allActions) { + FileObject actionFile = profileDir.getFileObject(a.getId()); + if (actionFile == null || !actionFile.isData()) { + keymap.put(a, Collections.emptySet()); + continue; + } + Enumeration atts = actionFile.getAttributes(); + Set strokes = new HashSet(); + while (atts.hasMoreElements()) { + String att = atts.nextElement(); + if (att.startsWith(SHORTCUT_PREFIX)) { + strokes.add((String) actionFile.getAttribute(att)); + } + } + keymap.put(a, strokes); + } + } + } +} diff --git a/options.keymap/nbproject/project.xml b/options.keymap/nbproject/project.xml --- a/options.keymap/nbproject/project.xml +++ b/options.keymap/nbproject/project.xml @@ -152,6 +152,7 @@ + org.netbeans.core.output2 org.netbeans.modules.editor.macros org.netbeans.modules.jumpto org.netbeans.modules.jvi