diff --git a/o.n.core/src/org/netbeans/core/NbKeymap.java b/o.n.core/src/org/netbeans/core/NbKeymap.java --- a/o.n.core/src/org/netbeans/core/NbKeymap.java +++ b/o.n.core/src/org/netbeans/core/NbKeymap.java @@ -41,20 +41,18 @@ package org.netbeans.core; +import java.awt.EventQueue; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.Observable; -import java.util.Set; +import java.util.TreeMap; +import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; @@ -62,39 +60,184 @@ import javax.swing.KeyStroke; import javax.swing.text.Keymap; import org.openide.awt.StatusDisplayer; -import org.openide.util.Mutex; +import org.openide.cookies.InstanceCookie; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.loaders.DataShadow; +import org.openide.util.Utilities; import org.openide.util.actions.SystemAction; import org.openide.util.lookup.ServiceProvider; -/** Implementation of standard key - action mappings. -* -* @author Dafe Simonek -*/ @ServiceProvider(service=Keymap.class) -public final class NbKeymap extends Observable implements Keymap, Comparator { - /** Name of this keymap */ - String name; - /** Parent keymap */ - Keymap parent; - /** Hashtable holding KeyStroke > Action mappings */ - Map bindings; - /** Default action */ - Action defaultAction; - /** hash table to map (Action -> ArrayList of KeyStrokes) */ - Map> actions; +public final class NbKeymap implements Keymap, Comparator { + + private static final Action BROKEN = new AbstractAction("") { // NOI18N + public void actionPerformed(ActionEvent e) { + Toolkit.getDefaultToolkit().beep(); + } + }; + + /** Represents a binding of a keystroke. */ + private static class Binding { + /** file defining an action; null if nested is not null */ + final FileObject actionDefinition; + /** lazily instantiated actual action, in case actionDefinition is not null */ + private Action action; + /** nested bindings; null if actionDefinition is not null */ + final Map nested; + Binding(FileObject def) { + actionDefinition = def; + nested = null; + } + Binding() { + actionDefinition = null; + nested = new HashMap(); + } + synchronized Action loadAction() { + assert actionDefinition != null; + if (action == null) { + try { + DataObject d = DataObject.find(actionDefinition); + InstanceCookie ic = d.getLookup().lookup(InstanceCookie.class); + if (ic == null) { + return null; + } + action = (Action) ic.instanceCreate(); + } catch (/*ClassNotFoundException,IOException,ClassCastException*/Exception x) { + LOG.log(Level.INFO, "could not load action for " + actionDefinition.getPath(), x); + } + } + if (action == null) { + action = BROKEN; + } + return action; + } + } + + private Map bindings; + private Map id2Stroke; + private final Map action2Id = new WeakHashMap(); + private FileChangeListener keymapListener; + private FileChangeListener bindingsListener = new FileChangeAdapter() { + public @Override void fileDataCreated(FileEvent fe) { + refreshBindings(); + } + public @Override void fileAttributeChanged(FileAttributeEvent fe) { + refreshBindings(); + } + public @Override void fileChanged(FileEvent fe) { + refreshBindings(); + } + public @Override void fileRenamed(FileRenameEvent fe) { + refreshBindings(); + } + public @Override void fileDeleted(FileEvent fe) { + refreshBindings(); + } + }; + + private synchronized void refreshBindings() { + bindings = null; + bindings(); + } + + private synchronized Map bindings() { + if (bindings == null) { + bindings = new HashMap(); + boolean refresh = id2Stroke != null; + id2Stroke = new TreeMap(); + List dirs = new ArrayList(2); + dirs.add(FileUtil.getConfigFile("Shortcuts")); // NOI18N + FileObject keymaps = FileUtil.getConfigFile("Keymaps"); // NOI18N + if (keymaps != null) { + String curr = (String) keymaps.getAttribute("currentKeymap"); // NOI18N + if (curr == null) { + curr = "NetBeans"; // NOI18N + } + dirs.add(keymaps.getFileObject(curr)); + if (keymapListener == null) { + keymapListener = new FileChangeAdapter() { + public @Override void fileAttributeChanged(FileAttributeEvent fe) { + refreshBindings(); + } + }; + keymaps.addFileChangeListener(keymapListener); + } + } + for (FileObject dir : dirs) { + if (dir != null) { + for (FileObject def : dir.getChildren()) { + if (def.isData()) { + KeyStroke[] strokes = Utilities.stringToKeys(def.getName()); + if (strokes == null || strokes.length == 0) { + LOG.log(Level.WARNING, "could not load parse name of " + def.getPath()); + continue; + } + Map binder = bindings; + for (int i = 0; i < strokes.length - 1; i++) { + Binding sub = binder.get(strokes[i]); + if (sub != null && sub.nested == null) { + LOG.log(Level.WARNING, "conflict between " + sub.actionDefinition.getPath() + " and " + def.getPath()); + sub = null; + } + if (sub == null) { + binder.put(strokes[i], sub = new Binding()); + } + binder = sub.nested; + } + // XXX warn about conflicts here too: + binder.put(strokes[strokes.length - 1], new Binding(def)); + if (strokes.length == 1) { + String id = idForFile(def); + KeyStroke former = id2Stroke.get(id); + if (former == null || compare(former, strokes[0]) > 0) { + id2Stroke.put(id, strokes[0]); + } + } + } + } + dir.removeFileChangeListener(bindingsListener); + dir.addFileChangeListener(bindingsListener); + } + } + if (refresh) { + // Update accelerators of existing actions after switching keymap. + EventQueue.invokeLater(new Runnable() { + public void run() { + for (Map.Entry entry : action2Id.entrySet()) { + entry.getKey().putValue(Action.ACCELERATOR_KEY, id2Stroke.get(entry.getValue())); + } + } + }); + } + if (LOG.isLoggable(Level.FINE)) { + for (Map.Entry entry : id2Stroke.entrySet()) { + LOG.fine(entry.getValue() + " => " + entry.getKey()); + } + } + } + return bindings; + } - private static List context = new ArrayList(); + private static List context; // accessed reflectively from org.netbeans.editor.MultiKeymap - public static void resetContext() { + private static void resetContext() { context.clear(); StatusDisplayer.getDefault().setStatusText(""); } - public static KeyStroke[] getContext() { + public static KeyStroke[] getContext() { // called from ShortcutAndMenuKeyEventProcessor return context.toArray(new KeyStroke[context.size()]); } - - public static void shiftContext(KeyStroke stroke) { + + private static void shiftContext(KeyStroke stroke) { context.add(stroke); StringBuilder text = new StringBuilder(); @@ -114,191 +257,132 @@ KeyEvent.getKeyText (keyStroke.getKeyCode ()); } - private final Action NO_ACTION = new KeymapAction(null, null); private static final Logger LOG = Logger.getLogger(NbKeymap.class.getName()); - public Action createMapAction(Keymap k, KeyStroke stroke) { - return new KeymapAction(k, stroke); - } - - /** Default constructor - */ public NbKeymap() { - this("Default", null); // NOI18N - } - - NbKeymap(final String name, final Keymap parent) { - this.name = name; - this.parent = parent; - bindings = new HashMap(); + context = new ArrayList(); } public Action getDefaultAction() { - LOG.log(Level.FINE, "getDefaultAction"); - if (defaultAction != null) { - return defaultAction; - } - return (parent != null) ? parent.getDefaultAction() : null; + return null; } public void setDefaultAction(Action a) { - LOG.log(Level.FINE, "setDefaultAction {0}", id(a)); - defaultAction = a; - setChanged(); - notifyObservers(); + throw new UnsupportedOperationException(); } public String getName() { - return name; + return "Default"; // NOI18N } - public Action getAction(KeyStroke key) { + public Action getAction(final KeyStroke key) { + switch (key.getKeyCode()) { + case KeyEvent.VK_SHIFT: + case KeyEvent.VK_CONTROL: + case KeyEvent.VK_ALT: + case KeyEvent.VK_ALT_GRAPH: + case KeyEvent.VK_META: + case KeyEvent.VK_UNDEFINED: + case KeyEvent.CHAR_UNDEFINED: + // Not actually a bindable key press. + return null; + } + if (key.isOnKeyRelease()) { + // Again, not really our business here. + return null; + } LOG.log(Level.FINE, "getAction {0}", key); - - Action a; - - KeyStroke[] ctx = getContext(); - Keymap activ = this; - for (int i=0; i binder = bindings(); + for (KeyStroke ctx : context) { + Binding sub = binder.get(ctx); + if (sub == null) { + resetContext(); + return BROKEN; // no entry found after known prefix } - - if (a instanceof KeymapAction) { - activ = ((KeymapAction)a).keymap; - } else { // unknown ctx - int code = key.getKeyCode(); - if (code != KeyEvent.VK_CONTROL && - code != KeyEvent.VK_ALT && - code != KeyEvent.VK_ALT_GRAPH && - code != KeyEvent.VK_SHIFT && - code != KeyEvent.VK_META) resetContext(); - return null; + binder = sub.nested; + if (binder == null) { + resetContext(); + return BROKEN; // anomalous, expected to find submap here } } - - if (activ == this) { - a = bindings.get(key); - if ((a == null) && (parent != null)) { - a = parent.getAction(key); - } - return a; + Binding b = binder.get(key); + if (b == null) { + resetContext(); + return null; // normal, not found + } + if (b.nested == null) { + resetContext(); + return b.loadAction(); // found real action } else { - a = activ.getAction(key); - } - - if (a != null) { - if (!(a instanceof KeymapAction)) { - resetContext(); - } - return a; - } - - // no action, should we reset? - if (key.isOnKeyRelease() || - (key.getKeyChar() != 0 && key.getKeyChar() != KeyEvent.CHAR_UNDEFINED)) { - return null; - } - - switch (key.getKeyCode()) { - case KeyEvent.VK_SHIFT: - case KeyEvent.VK_CONTROL: - case KeyEvent.VK_ALT: - case KeyEvent.VK_META: - return null; - default: - resetContext(); - return NO_ACTION; + return new AbstractAction() { + public void actionPerformed(ActionEvent e) { + shiftContext(key); // entering submap + } + }; } } public KeyStroke[] getBoundKeyStrokes() { - LOG.log(Level.FINE, "getBoundKeyStrokes"); - int i = 0; - KeyStroke[] keys = null; - synchronized (this) { - keys = new KeyStroke[bindings.size()]; - for (KeyStroke ks: bindings.keySet()) { - keys[i++] = ks; - } - } - return keys; + assert false; + return null; } public Action[] getBoundActions() { - LOG.log(Level.FINE, "getBoundActions"); - int i = 0; - Action[] actionsArray = null; - synchronized (this) { - actionsArray = new Action[bindings.size()]; - for (Iterator iter = bindings.values().iterator(); iter.hasNext(); ) { - actionsArray[i++] = (Action) iter.next(); - } - } - return actionsArray; + assert false; + return null; } public KeyStroke[] getKeyStrokesForAction(Action a) { - LOG.log(Level.FINE, "getKeyStrokesForAction {0}", id(a)); - - Map> localActions = actions; - if (localActions == null) { - localActions = buildReverseMapping (); - } - - List strokes = localActions.get (a); - if (strokes != null) { - return strokes.toArray(new KeyStroke[strokes.size ()]); - } else { + FileObject definingFile = (FileObject) a.getValue("definingFile"); // cf. o.o.awt.Toolbar.setAccelerator + if (definingFile == null) { + LOG.log(Level.FINE, "no defining file known for {0}", id(a)); return new KeyStroke[0]; } + String id = idForFile(definingFile); + bindings(); + action2Id.put(a, id); + KeyStroke k = id2Stroke.get(id); + LOG.log(Level.FINE, "found keystroke {0} for {1} with ID {2}", new Object[] {k, id(a), id}); + return k != null ? new KeyStroke[] {k} : new KeyStroke[0]; } - - private Map> buildReverseMapping () { - Map> localActions = actions = new HashMap> (); - - synchronized (this) { - for (Map.Entry curEntry: bindings.entrySet()) { - Action curAction = curEntry.getValue(); - KeyStroke curKey = curEntry.getKey(); - - List keysForAction = localActions.get (curAction); - if (keysForAction == null) { - keysForAction = Collections.synchronizedList (new ArrayList (1)); - localActions.put (curAction, keysForAction); + /** + * Traverses shadow files to origin. + * Returns impl class name if that is obvious (common for SystemAction's); + * else just returns file path (usual for more modern registrations). + */ + private static String idForFile(FileObject f) { + if (f.hasExt("shadow")) { + String path = (String) f.getAttribute("originalFile"); + if (path != null) { + f = FileUtil.getConfigFile(path); + } else { + try { + DataObject d = DataObject.find(f); + if (d instanceof DataShadow) { + f = ((DataShadow) d).getOriginal().getPrimaryFile(); + } + } catch (DataObjectNotFoundException x) { + LOG.log(Level.INFO, f.getPath(), x); } - keysForAction.add (curKey); } } - - return localActions; + // Cannot actually load instanceCreate methodvalue=... attribute; just want to see if it is there. + if (f.hasExt("instance") && !Collections.list(f.getAttributes()).contains("instanceCreate")) { + String clazz = (String) f.getAttribute("instanceClass"); + if (clazz != null) { + return clazz; + } else { + return f.getName().replace('-', '.'); + } + } + return f.getPath(); } public synchronized boolean isLocallyDefined(KeyStroke key) { - LOG.log(Level.FINE, "isLocallyDefined {0}", key); - return bindings.containsKey(key); + assert false; + return false; } - /** Updates action accelerator. */ - private void updateActionAccelerator(final Action a) { - if(a == null) { - return; - } - - Mutex.EVENT.writeAccess(new Runnable() { - public void run() { - KeyStroke[] keystrokes = getKeyStrokesForAction(a); - Arrays.sort (keystrokes, NbKeymap.this); - a.putValue(Action.ACCELERATOR_KEY, keystrokes.length > 0 ? keystrokes[0] : null); - } - }); - } - public int compare(KeyStroke k1, KeyStroke k2) { //#47024 and 32733 - "Find" should not be shown as an accelerator, //nor should "Backspace" for Delete. Solution: The shorter text wins. @@ -308,88 +392,23 @@ public void addActionForKeyStroke(KeyStroke key, Action a) { - LOG.log(Level.FINE, "addActionForKeyStroke {0} => {1}", new Object[] { key, id(a) }); - // Update reverse binding for old action too (#30455): - Action old; - synchronized (this) { - old = bindings.put(key, a); - actions = null; - } - - updateActionAccelerator(a); - updateActionAccelerator(old); - setChanged(); - notifyObservers(); - } - - void addActionForKeyStrokeMap(Map map) { - Set actionsSet = new HashSet(); - synchronized (this) { - for (Entry entry: map.entrySet ()) { - KeyStroke key = entry.getKey(); - Action value = entry.getValue(); - // Add both old and new action: - actionsSet.add(value); - actionsSet.add(bindings.put(key, value)); - } - actions = null; - } - - for(Action a: actionsSet) { - updateActionAccelerator(a); - } - - setChanged(); - notifyObservers(); + assert false; } public void removeKeyStrokeBinding(KeyStroke key) { - LOG.log(Level.FINE, "removeKeyStrokeBinding {0}", key); - - Action a; - synchronized (this) { - a = bindings.remove(key); - actions = null; - } - updateActionAccelerator(a); - setChanged(); - notifyObservers(); + assert false; } public void removeBindings() { - LOG.log(Level.FINE, "removeBindings"); - - Set actionsSet; - synchronized (this) { - actionsSet = new HashSet(bindings.values()); - bindings.clear(); - actions = null; - } - - for(Action a: actionsSet) { - updateActionAccelerator(a); - } - - setChanged(); - notifyObservers(); + assert false; } public Keymap getResolveParent() { - return parent; + return null; } public void setResolveParent(Keymap parent) { - LOG.log(Level.FINE, "setResolveParent {0}", parent == null ? null : parent.getClass()); - this.parent = parent; - setChanged(); - notifyObservers(); - } - - /** Returns string representation - can be looong. - */ - @Override - public String toString() { - return "Keymap[" + name + "]" + bindings; // NOI18N + throw new UnsupportedOperationException(); } private static Object id(Action a) { @@ -399,94 +418,4 @@ return a; } - public static class SubKeymap implements Keymap { - Object hold; - Keymap parent; - Map bindings; - Action defaultAction; - - public SubKeymap(Object hold) { - this.hold = hold; - bindings = new HashMap(); - } - - public String getName() { - return "name"; - } - - public void setResolveParent(Keymap parent) { - this.parent = parent; - } - - public Keymap getResolveParent() { - return parent; - } - - public void addActionForKeyStroke(KeyStroke key, Action a) { - bindings.put(key, a); - } - - public KeyStroke[] getKeyStrokesForAction(Action a) { - return new KeyStroke[0]; - } - - public void setDefaultAction(Action a) { - defaultAction = a; - } - - public Action getAction(KeyStroke key) { - return bindings.get(key); - } - - public boolean isLocallyDefined(KeyStroke key) { - return bindings.containsKey(key); - } - - public void removeKeyStrokeBinding(KeyStroke keys) { - bindings.remove(keys); - } - - public Action[] getBoundActions() { - synchronized (this) { - return bindings.values().toArray(new Action[0]); - } - } - - public KeyStroke[] getBoundKeyStrokes() { - synchronized (this) { - return bindings.keySet().toArray(new KeyStroke[0]); - } - } - - public Action getDefaultAction() { - return defaultAction; - } - - public void removeBindings() { - bindings.clear(); - } - - } - - public static class KeymapAction extends AbstractAction { - private Keymap keymap; - private KeyStroke stroke; - - public KeymapAction(Keymap keymap, KeyStroke stroke) { - this.keymap = keymap; - this.stroke = stroke; - } - - public Keymap getSubMap() { - return keymap; - } - - public void actionPerformed(ActionEvent e) { - if (stroke == null) { // NO_ACTION -> reset - resetContext(); - } else { - shiftContext(stroke); - } - } - } } diff --git a/o.n.core/src/org/netbeans/core/NonGui.java b/o.n.core/src/org/netbeans/core/NonGui.java --- a/o.n.core/src/org/netbeans/core/NonGui.java +++ b/o.n.core/src/org/netbeans/core/NonGui.java @@ -147,13 +147,6 @@ Splash.getInstance().increment(10); StartLog.logProgress ("Timer initialized"); // NOI18N - // ----------------------------------------------------------------------------------------------------- - // 13. Initialize Shortcuts - ShortcutsFolder.initShortcuts(); - Splash.getInstance().increment(1); - StartLog.logProgress ("Shortcuts initialized"); // NOI18N - - // ----------------------------------------------------------------------------------------------------- // 14. Open main window StatusDisplayer.getDefault().setStatusText (NbBundle.getMessage (NonGui.class, "MSG_WindowShowInit")); diff --git a/o.n.core/src/org/netbeans/core/ShortcutsFolder.java b/o.n.core/src/org/netbeans/core/ShortcutsFolder.java deleted file mode 100644 --- a/o.n.core/src/org/netbeans/core/ShortcutsFolder.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. - * - * 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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]" - * - * Contributor(s): - * - * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun - * Microsystems, Inc. All Rights Reserved. - * - * 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. - */ - -package org.netbeans.core; - -import java.io.IOException; -import java.util.Collection; -import java.util.Enumeration; -import java.util.LinkedList; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.Action; -import javax.swing.KeyStroke; -import javax.swing.text.Keymap; -import org.netbeans.core.NbKeymap.KeymapAction; -import org.netbeans.core.startup.StartLog; -import org.openide.cookies.InstanceCookie; -import org.openide.filesystems.FileAttributeEvent; -import org.openide.filesystems.FileChangeAdapter; -import org.openide.filesystems.FileEvent; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.loaders.DataFolder; -import org.openide.loaders.DataObject; -import org.openide.util.Exceptions; -import org.openide.util.Lookup; -import org.openide.util.RequestProcessor; -import org.openide.util.Utilities; - -/** - * Bridge to old layers based system. - * - * @author Jan Jancura - */ -class ShortcutsFolder { - - private static final String PROFILES_FOLDER = "Keymaps"; - private static final String SHORTCUTS_FOLDER = "Shortcuts"; - private static final String CURRENT_PROFILE_ATTRIBUTE = "currentKeymap"; - - private static ShortcutsFolder shortcutsFolder; - private Listener listener = new Listener (); - private FileObject profilesFileObject; - private FileObject shortcutsFileObject; - private FileObject currentFolder; - private Logger debug = Logger.getLogger(ShortcutsFolder.class.getName ()); - private Collection dataObjects; - - - static void initShortcuts () { - StartLog.logStart("initShortcuts"); - try { - if (shortcutsFolder != null) return; - shortcutsFolder = new ShortcutsFolder (); - } finally { - StartLog.logEnd("initShortcuts"); - } - } - - private ShortcutsFolder () { - try { - FileObject root = FileUtil.getConfigRoot (); - profilesFileObject = root.getFileObject (PROFILES_FOLDER); - if (profilesFileObject == null) - profilesFileObject = root.createFolder (PROFILES_FOLDER); - profilesFileObject.addFileChangeListener (listener); - - shortcutsFileObject = root.getFileObject (SHORTCUTS_FOLDER); - if (shortcutsFileObject == null) - shortcutsFileObject = root.createFolder (SHORTCUTS_FOLDER); - shortcutsFileObject.addFileChangeListener (listener); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - refresh (); - } - - static void waitFinished () { - shortcutsFolder.listener.task.waitFinished (); - } - - private void refresh () { - - // get keymap and delete old shortcuts - NbKeymap keymap = (NbKeymap) Lookup.getDefault ().lookup (Keymap.class); - keymap.removeBindings (); - dataObjects = new LinkedList(); - - // update main shortcuts - readShortcuts (keymap, shortcutsFileObject); - - // update shortcuts from profile - String keymapName = (String) profilesFileObject.getAttribute - (CURRENT_PROFILE_ATTRIBUTE); - if (keymapName == null || "".equals (keymapName)) - keymapName = "NetBeans"; // NOI18N - if (currentFolder != null) - currentFolder.removeFileChangeListener (listener); - currentFolder = FileUtil.getConfigFile (PROFILES_FOLDER + '/' + keymapName); - if (currentFolder == null) { - try { - currentFolder = profilesFileObject.createFolder(keymapName); - } catch (IOException ioe) { - Exceptions.printStackTrace(ioe); - } - } - if (currentFolder != null) { - readShortcuts (keymap, currentFolder); - // add listener to current profile folder - currentFolder.addFileChangeListener (listener); - } - } - - - private void readShortcuts (NbKeymap keymap, FileObject fileObject) { - debug.fine("\nreadShortcuts " + fileObject); - DataFolder folder = DataFolder.findFolder (fileObject); - Enumeration en = folder.children(false); - while (en.hasMoreElements ()) { - DataObject dataObject = en.nextElement(); - if (dataObject instanceof DataFolder) continue; - InstanceCookie ic = dataObject.getCookie(InstanceCookie.class); - if (ic == null) continue; - try { - Action action = (Action) ic.instanceCreate (); - String shortcuts = dataObject.getName (); - debug.fine(" " + shortcuts + " : " + action); - KeyStroke[] keyStrokes = Utilities.stringToKeys (shortcuts); - if (keyStrokes != null) { - addShortcut(keymap, action, keyStrokes); - } else { // see e.g. secondary exception in #74169 - debug.warning("Unrecognized shortcut name from " + dataObject.getPrimaryFile().getPath()); // NOI18N - } - //remember DataObjects used to create the Actions so that there are - //the same Action instances in the menu - dataObjects.add( dataObject ); - } catch (ClassNotFoundException x) { - Logger.getLogger(ShortcutsFolder.class.getName()).log(Level.WARNING, - "{0} ignored; cannot load class {1}", - new Object[] {dataObject.getPrimaryFile().getPath(), ic.instanceName()}); - } catch (Exception ex) { - Logger.getLogger(ShortcutsFolder.class.getName()).log(Level.WARNING, null, ex); - } - } - } - - private static void addShortcut ( - NbKeymap keymap, - Action action, - KeyStroke[] keyStrokes - ) { - Keymap currentKeymap = keymap; - int i, k = keyStrokes.length - 1; - for (i = 0; i < k; i++) { - Action a = currentKeymap.getAction (keyStrokes [i]); - if (a == null) { - a = keymap.createMapAction - (new NbKeymap.SubKeymap (null), keyStrokes [i]); - currentKeymap.addActionForKeyStroke (keyStrokes [i], a); - } - if (!(a instanceof KeymapAction)) return; - currentKeymap = ((KeymapAction) a).getSubMap (); - } - currentKeymap.addActionForKeyStroke (keyStrokes [k], action); - } - - private class Listener extends FileChangeAdapter implements Runnable { - - private RequestProcessor.Task task = new RequestProcessor ("ShortcutsFolder").create (this); - - public void run () { - refresh (); - } - - @Override - public void fileDataCreated (FileEvent fe) { - task.schedule (500); - } - - @Override - public void fileChanged (FileEvent fe) { - task.schedule (500); - } - - @Override - public void fileDeleted (FileEvent fe) { - task.schedule (500); - } - - @Override - public void fileAttributeChanged (FileAttributeEvent fe) { - if (fe.getName () != null && - !CURRENT_PROFILE_ATTRIBUTE.equals (fe.getName ()) - ) return; - task.schedule (500); - } - } -} diff --git a/o.n.core/test/unit/src/org/netbeans/core/NbKeymapTest.java b/o.n.core/test/unit/src/org/netbeans/core/NbKeymapTest.java --- a/o.n.core/test/unit/src/org/netbeans/core/NbKeymapTest.java +++ b/o.n.core/test/unit/src/org/netbeans/core/NbKeymapTest.java @@ -42,183 +42,246 @@ package org.netbeans.core; import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.OutputStream; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Observable; -import java.util.Observer; +import java.util.concurrent.atomic.AtomicReference; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.KeyStroke; import javax.swing.text.Keymap; +import org.netbeans.junit.MockServices; import org.netbeans.junit.NbTestCase; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataFolder; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataShadow; +import org.openide.loaders.Environment; +import org.openide.loaders.InstanceSupport; +import org.openide.loaders.XMLDataObject; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; +import org.openide.util.actions.CallableSystemAction; +import org.openide.util.lookup.Lookups; +import org.w3c.dom.Document; -/** Test NbKeymap. - * @author Jesse Glick - * @see "#30455" */ public class NbKeymapTest extends NbTestCase { public NbKeymapTest(String name) { super(name); } - - @Override - protected boolean runInEQ () { - return true; + + static { + System.setProperty("os.name", "Linux"); // just to standardize modifier key binding + } + + protected @Override void setUp() throws Exception { + for (FileObject f : FileUtil.getConfigRoot().getChildren()) { + f.delete(); + } } - public void testBasicFunctionality() throws Exception { - Keymap km = new NbKeymap(); - Action a1 = new DummyAction("a1"); - Action a2 = new DummyAction("a2"); - Action d = new DummyAction("d"); - KeyStroke k1 = KeyStroke.getKeyStroke("X"); - KeyStroke k2 = KeyStroke.getKeyStroke("Y"); - assertFalse(k1.equals(k2)); - assertNull(km.getAction(k1)); - assertNull(km.getAction(k2)); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundActions())); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundKeyStrokes())); - assertNull(km.getDefaultAction()); - km.setDefaultAction(d); - assertEquals(d, km.getDefaultAction()); - km.addActionForKeyStroke(k1, a1); - assertEquals(a1, km.getAction(k1)); - assertTrue(km.isLocallyDefined(k1)); - assertEquals(null, km.getAction(k2)); - assertEquals(Collections.singletonList(a1), Arrays.asList(km.getBoundActions())); - assertEquals(Collections.singletonList(k1), Arrays.asList(km.getBoundKeyStrokes())); - km.addActionForKeyStroke(k2, a2); - assertEquals(a1, km.getAction(k1)); - assertEquals(a2, km.getAction(k2)); - assertEquals(2, km.getBoundActions().length); - assertEquals(2, km.getBoundKeyStrokes().length); - km.addActionForKeyStroke(k1, d); - assertEquals(d, km.getAction(k1)); - assertEquals(a2, km.getAction(k2)); - assertEquals(2, km.getBoundActions().length); - assertEquals(2, km.getBoundKeyStrokes().length); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getKeyStrokesForAction(a1))); - assertEquals(Collections.singletonList(k2), Arrays.asList(km.getKeyStrokesForAction(a2))); - assertEquals(Collections.singletonList(k1), Arrays.asList(km.getKeyStrokesForAction(d))); - km.removeKeyStrokeBinding(k2); - assertEquals(d, km.getAction(k1)); - assertNull(km.getAction(k2)); - assertEquals(Collections.singletonList(d), Arrays.asList(km.getBoundActions())); - assertEquals(Collections.singletonList(k1), Arrays.asList(km.getBoundKeyStrokes())); - km.removeBindings(); - assertNull(km.getAction(k1)); - assertNull(km.getAction(k2)); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundActions())); - assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundKeyStrokes())); + private FileObject make(String path) throws IOException { + return FileUtil.createData(FileUtil.getConfigRoot(), path); } - - public void testObservability() throws Exception { - NbKeymap km = new NbKeymap(); - O o = new O(); - km.addObserver(o); - assertFalse(o.changed); - Action a1 = new DummyAction("a1"); - Action a2 = new DummyAction("a2"); - KeyStroke k1 = KeyStroke.getKeyStroke("X"); - km.addActionForKeyStroke(k1, a1); - assertTrue(o.changed); - o.changed = false; - km.addActionForKeyStroke(k1, a2); - assertTrue(o.changed); - o.changed = false; - km.removeKeyStrokeBinding(k1); - assertTrue(o.changed); + + private FileObject makeFolder(String path) throws IOException { + return FileUtil.createFolder(FileUtil.getConfigRoot(), path); + } + + private void assertMapping(Keymap km, KeyStroke stroke, FileObject presenterDefinition, String actionName) throws Exception { + Action a = km.getAction(stroke); + assertNotNull("for " + stroke, a); + assertEquals(actionName, a.getValue(Action.NAME)); + a.putValue("definingFile", presenterDefinition); + assertEquals("for " + stroke + " from " + presenterDefinition.getPath(), + Collections.singletonList(stroke), Arrays.asList(km.getKeyStrokesForAction(a))); } public void testAcceleratorMapping() throws Exception { + FileObject def1 = make("Actions/DummyAction1.instance"); + def1.setAttribute("instanceCreate", new DummyAction("one")); + FileObject def2 = make("Actions/DummyAction2.instance"); + def2.setAttribute("instanceCreate", new DummyAction("two")); + FileObject def3 = make("Actions/DummySystemAction1.instance"); + def3.setAttribute("instanceClass", DummySystemAction1.class.getName()); + FileObject def4 = make("Actions/" + DummySystemAction2.class.getName().replace('.', '-') + ".instance"); + DataFolder shortcuts = DataFolder.findFolder(makeFolder("Shortcuts")); + DataShadow.create(shortcuts, "1", DataObject.find(def1)).getPrimaryFile(); + DataShadow.create(shortcuts, "2", DataObject.find(def2)).getPrimaryFile(); + DataShadow.create(shortcuts, "3", DataObject.find(def3)).getPrimaryFile(); + DataShadow.create(shortcuts, "C-4", DataObject.find(def4)).getPrimaryFile(); + DataFolder menu = DataFolder.findFolder(makeFolder("Menu/Tools")); + FileObject menuitem1 = DataShadow.create(menu, "whatever1", DataObject.find(def1)).getPrimaryFile(); + FileObject menuitem2 = DataShadow.create(menu, "whatever2", DataObject.find(def2)).getPrimaryFile(); + FileObject menuitem3 = DataShadow.create(menu, "whatever3", DataObject.find(def3)).getPrimaryFile(); + FileObject menuitem4 = DataShadow.create(menu, "whatever4", DataObject.find(def4)).getPrimaryFile(); Keymap km = new NbKeymap(); - Action a1 = new DummyAction("a1"); - Action a2 = new DummyAction("a2"); - KeyStroke k1 = KeyStroke.getKeyStroke("X"); - KeyStroke k2 = KeyStroke.getKeyStroke("Y"); - assertNull(a1.getValue(Action.ACCELERATOR_KEY)); - assertNull(a2.getValue(Action.ACCELERATOR_KEY)); - AccL l = new AccL(); - a1.addPropertyChangeListener(l); - assertFalse(l.changed); - km.addActionForKeyStroke(k1, a1); - assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); - assertTrue(l.changed); - l.changed = false; - km.addActionForKeyStroke(k2, a2); - assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); - km.addActionForKeyStroke(k2, a1); - Object acc = a1.getValue(Action.ACCELERATOR_KEY); - assertTrue(acc == k1 || acc == k2); - assertNull(a2.getValue(Action.ACCELERATOR_KEY)); - km.removeKeyStrokeBinding(k1); - assertEquals(k2, a1.getValue(Action.ACCELERATOR_KEY)); - km.removeKeyStrokeBinding(k2); - assertNull(a1.getValue(Action.ACCELERATOR_KEY)); - assertTrue(l.changed); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), menuitem1, "one"); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), menuitem2, "two"); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_3, 0), menuitem3, "DummySystemAction1"); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_4, KeyEvent.CTRL_MASK), menuitem4, "DummySystemAction2"); + } + + public void testMultipleAcceleratorMapping() throws Exception { + FileObject def = make("Actions/paste.instance"); + def.setAttribute("instanceCreate", new DummyAction("paste")); + DataFolder shortcuts = DataFolder.findFolder(makeFolder("Shortcuts")); + DataShadow.create(shortcuts, "C-V", DataObject.find(def)).getPrimaryFile(); + DataShadow.create(shortcuts, "PASTE", DataObject.find(def)).getPrimaryFile(); + Keymap km = new NbKeymap(); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK), def, "paste"); } - public void testAddActionForKeyStrokeMap() throws Exception { - NbKeymap km = new NbKeymap(); - O o = new O(); - km.addObserver(o); - Action a1 = new DummyAction("a1"); - Action a2 = new DummyAction("a2"); - Action a3 = new DummyAction("a3"); - KeyStroke k1 = KeyStroke.getKeyStroke("X"); - KeyStroke k2 = KeyStroke.getKeyStroke("Y"); - Map m = new HashMap(); - m.put(k1, a1); - m.put(k2, a2); - km.addActionForKeyStrokeMap(m); - assertTrue(o.changed); - assertEquals(a1, km.getAction(k1)); - assertEquals(a2, km.getAction(k2)); - assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); - assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); - assertEquals(2, km.getBoundActions().length); - assertEquals(2, km.getBoundKeyStrokes().length); - km.removeBindings(); - km.addActionForKeyStroke(k1, a3); - km.addActionForKeyStrokeMap(m); - assertEquals(a1, km.getAction(k1)); - assertEquals(a2, km.getAction(k2)); - assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); - assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); - assertNull(a3.getValue(Action.ACCELERATOR_KEY)); - assertEquals(2, km.getBoundActions().length); - assertEquals(2, km.getBoundKeyStrokes().length); + public void testUnusualInstanceFileExtensions() throws Exception { + MockServices.setServices(ENV.class); + FileObject inst = make("Shortcuts/C-F11.xml"); + OutputStream os = inst.getOutputStream(); + os.write("".getBytes()); + os.close(); + assertMapping(new NbKeymap(), KeyStroke.getKeyStroke(KeyEvent.VK_F11, KeyEvent.CTRL_MASK), inst, "whatever"); + } + + public void testAbstractModifiers() throws Exception { + Keymap km = new NbKeymap(); + FileObject inst1 = make("Shortcuts/D-1.instance"); + inst1.setAttribute("instanceCreate", new DummyAction("one")); + FileObject inst2 = make("Shortcuts/O-1.instance"); + inst2.setAttribute("instanceCreate", new DummyAction("two")); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, KeyEvent.CTRL_MASK), inst1, "one"); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, KeyEvent.ALT_MASK), inst2, "two"); + } + + public void testDifferentKeymaps() throws Exception { + make("Shortcuts/C-A.instance").setAttribute("instanceCreate", new DummyAction("one")); + make("Keymaps/NetBeans/C-A.instance").setAttribute("instanceCreate", new DummyAction("two")); + make("Keymaps/Eclipse/C-A.instance").setAttribute("instanceCreate", new DummyAction("three")); + Keymap km = new NbKeymap(); + KeyStroke controlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK); + assertEquals("two", km.getAction(controlA).getValue(Action.NAME)); + FileUtil.getConfigFile("Keymaps").setAttribute("currentKeymap", "Eclipse"); + assertEquals("three", km.getAction(controlA).getValue(Action.NAME)); + FileUtil.getConfigFile("Keymaps").setAttribute("currentKeymap", "IDEA"); + assertEquals("one", km.getAction(controlA).getValue(Action.NAME)); + } + + public void testChangeOfAcceleratorFromKeymap() throws Exception { + Action a = new DummyAction("one"); + FileObject def = make("Actions/one.instance"); + def.setAttribute("instanceCreate", a); + DataShadow.create(DataFolder.findFolder(makeFolder("Keymaps/NetBeans")), "C-A", DataObject.find(def)); + DataShadow.create(DataFolder.findFolder(makeFolder("Keymaps/Eclipse")), "C-B", DataObject.find(def)); + Keymap km = new NbKeymap(); + assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK), def, "one"); + FileUtil.getConfigFile("Keymaps").setAttribute("currentKeymap", "Eclipse"); + // Any actions ever passed to getKeyStrokesForAction should get updated when keymap changes: + assertEquals(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_MASK), a.getValue(Action.ACCELERATOR_KEY)); + } + + public void testMultiKeyShortcuts() throws Exception { + final AtomicReference ran = new AtomicReference(); + class A extends AbstractAction { + final String s; + A(String s) { + this.s = s; + } + public void actionPerformed(ActionEvent e) { + ran.set(s); + } + } + make("Shortcuts/C-X 1.instance").setAttribute("instanceCreate", new A("C-X 1")); + make("Shortcuts/C-X 2.instance").setAttribute("instanceCreate", new A("C-X 2")); + make("Shortcuts/C-U A B.instance").setAttribute("instanceCreate", new A("C-U A B")); + Keymap km = new NbKeymap(); + Action a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals(null, ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_1, 0)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals("C-X 1", ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals(null, ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_2, 0)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals("C-X 2", ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_MASK)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals(null, ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals(null, ran.getAndSet(null)); + a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0)); + assertNotNull(a); + a.actionPerformed(null); + assertEquals("C-U A B", ran.getAndSet(null)); + } + + public void testChangesInShortcutRegistrations() throws Exception { + make("Shortcuts/C-A.instance").setAttribute("instanceCreate", new DummyAction("one")); + make("Keymaps/NetBeans/C-B.instance").setAttribute("instanceCreate", new DummyAction("two")); + Keymap km = new NbKeymap(); + assertEquals("one", km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK)).getValue(Action.NAME)); + assertEquals("two", km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_MASK)).getValue(Action.NAME)); + assertEquals(null, km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK))); + FileUtil.getConfigFile("Shortcuts/C-A.instance").delete(); + assertEquals(null, km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK))); + make("Shortcuts/C-C.instance").setAttribute("instanceCreate", new DummyAction("three")); + assertEquals("three", km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK)).getValue(Action.NAME)); + make("Keymaps/NetBeans/C-C.instance").setAttribute("instanceCreate", new DummyAction("four")); + assertEquals("four", km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK)).getValue(Action.NAME)); + } + + private static final class DummyAction extends AbstractAction { + public DummyAction(String name) { + super(name); + } + public void actionPerformed(ActionEvent e) {} } - private static final class DummyAction extends AbstractAction { - private final String name; - public DummyAction(String name) { - this.name = name; - } - public void actionPerformed(ActionEvent e) {} - @Override - public String toString() { - return "DummyAction[" + name + "]"; + public static class ENV extends Object implements Environment.Provider { + public Lookup getEnvironment(DataObject obj) { + if (obj instanceof XMLDataObject) { + try { + Document doc = ((XMLDataObject) obj).getDocument(); + if (doc.getDocumentElement().getNodeName().equals("action")) { + return Lookups.singleton(new InstanceSupport.Instance(new DummyAction("whatever"))); + } + } catch (Exception ex) { + ex.printStackTrace(); + fail("No exception: " + ex.getMessage()); + } + } + return Lookup.EMPTY; } } - - private static final class O implements Observer { - public boolean changed = false; - public void update(Observable o, Object arg) { - changed = true; + + public static final class DummySystemAction1 extends CallableSystemAction { + public void performAction() {} + public String getName() { + return "DummySystemAction1"; + } + public HelpCtx getHelpCtx() { + return null; } } - - private static final class AccL implements PropertyChangeListener { - public boolean changed = false; - public void propertyChange(PropertyChangeEvent evt) { - if (Action.ACCELERATOR_KEY.equals(evt.getPropertyName())) { - changed = true; - } + + public static final class DummySystemAction2 extends CallableSystemAction { + public void performAction() {} + public String getName() { + return "DummySystemAction2"; + } + public HelpCtx getHelpCtx() { + return null; } } - + } diff --git a/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolder66845Test.java b/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolder66845Test.java deleted file mode 100644 --- a/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolder66845Test.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. - * - * 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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]" - * - * Contributor(s): - * - * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun - * Microsystems, Inc. All Rights Reserved. - * - * 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. - */ - -package org.netbeans.core; - -import java.util.logging.Level; -import javax.swing.text.Keymap; -import org.netbeans.core.startup.Main; -import org.netbeans.junit.Log; -import org.netbeans.junit.NbTestCase; -import org.openide.filesystems.FileUtil; -import org.openide.util.Lookup; - -public class ShortcutsFolder66845Test extends NbTestCase { - - public ShortcutsFolder66845Test(String s) { - super(s); - } - - private Keymap keymap; - private CharSequence logs; - - @Override - protected void setUp() throws Exception { - Main.initializeURLFactory (); - keymap = Lookup.getDefault().lookup(Keymap.class); - assertNotNull("There is a keymap", keymap); - assertEquals("of correct type", NbKeymap.class, keymap.getClass()); - ShortcutsFolder.initShortcuts (); - logs = Log.enable(ShortcutsFolder.class.getName(), Level.WARNING); - } - - public void testLogging() throws Exception { - FileUtil.createData(FileUtil.getConfigRoot(), "Keymaps/NetBeans/org-nb-Neznam.instance"); - - ShortcutsFolder.waitFinished (); - - assertTrue("got message in " + logs, logs.toString().contains("Neznam")); - } - -} diff --git a/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolderTest.java b/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolderTest.java deleted file mode 100644 --- a/o.n.core/test/unit/src/org/netbeans/core/ShortcutsFolderTest.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. - * - * 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun 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]" - * - * Contributor(s): - * - * The Original Software is NetBeans. The Initial Developer of the Original - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun - * Microsystems, Inc. All Rights Reserved. - * - * 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. - */ -package org.netbeans.core; - -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.io.IOException; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.Collections; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.KeyStroke; -import javax.swing.text.Keymap; -import org.netbeans.core.startup.Main; -import org.netbeans.junit.*; -import org.openide.ErrorManager; -import org.openide.cookies.InstanceCookie; -import org.openide.filesystems.FileLock; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileSystem; -import org.openide.filesystems.FileUtil; -import org.openide.loaders.DataObject; -import org.openide.loaders.DataShadow; -import org.openide.loaders.Environment; -import org.openide.loaders.InstanceSupport; -import org.openide.loaders.XMLDataObject; -import org.openide.util.Lookup; -import org.openide.util.lookup.Lookups; -import org.w3c.dom.Document; - -public class ShortcutsFolderTest extends NbTestCase { - private ErrorManager err; - private Keymap keymap; - - /** Constructor required by JUnit. - * @param testName method name to be used as testcase - */ - public ShortcutsFolderTest(String s) { - super(s); - } - - @Override - protected Level logLevel() { - return Level.ALL; - } - - @Override - protected void setUp() throws Exception { - MockServices.setServices(ENV.class); - - Main.initializeURLFactory (); - keymap = Lookup.getDefault().lookup(Keymap.class); - - assertNotNull("There is a keymap", keymap); - ShortcutsFolder.initShortcuts (); - - err = ErrorManager.getDefault().getInstance("TEST-" + getName()); - } - - public void testApplyChangeToFactoryActionIssue49597 () throws Exception { - final FileObject shortcuts = FileUtil.getConfigFile ("Shortcuts"); - FileObject inst = FileUtil.createData (FileUtil.getConfigRoot (), "Actions/Tools/TestAction.instance"); - TestAction action = new TestAction (); - inst.setAttribute ("instanceCreate", action); - - Reference ref = new WeakReference(inst); - inst = null; - assertGC ("File can disappear", ref); - -// ShortcutsFolder.waitFinished (); - - assertEquals ("Nothing registered", Collections.EMPTY_LIST, Arrays.asList (keymap.getBoundActions ())); - - final KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_F9, KeyEvent.ALT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); - - class R implements FileSystem.AtomicAction { - FileObject inst2; - - public void run() throws IOException { - inst2 = FileUtil.createData (FileUtil.getConfigRoot (), "/Shortcuts/CA-F9.shadow"); - inst2.setAttribute ("originalFile", "/Actions/Tools/TestAction.instance"); - } - } - R run = new R(); - FileUtil.runAtomicAction(run); - - ShortcutsFolder.waitFinished (); - err.log("ShortcutsFolder.waitFinished"); - - FileObject[] arr = shortcuts.getChildren (); - err.log("children are here"); - - assertEquals ("One element is there", 1, arr.length); - DataObject obj = DataObject.find (arr[0]); - err.log("Object is here" + obj); - - assertEquals("It is DataShadow", DataShadow.class, obj.getClass()); - - Object a = keymap.getAction (stroke); - assertNotNull ("There is an action", a); - assertEquals ("It is test action", TestAction.class, a.getClass ()); - } - - @RandomlyFails - public void testShortcutsForDifferentFilesThanInstanceOrShadows () throws Exception { - FileObject inst = FileUtil.createData (FileUtil.getConfigRoot (), "Shortcuts/C-F11.xml"); - - FileLock lock = inst.lock (); - java.io.PrintStream ps = new java.io.PrintStream (inst.getOutputStream (lock)); - ps.println (""); - ps.println (""); - ps.println (""); - ps.println (""); - ps.println (""); - ps.println (""); - ps.close(); - lock.releaseLock (); - - DataObject obj = DataObject.find (inst); - assertEquals ("XML Data object", XMLDataObject.class, obj.getClass()); - InstanceCookie ic = obj.getCookie(InstanceCookie.class); - assertNotNull ("Has cookie", ic); - - final KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_F11, KeyEvent.CTRL_MASK); - - ShortcutsFolder.waitFinished (); - - Action action = keymap.getAction(stroke); - if (action == null) { - fail("There should be some action for " + stroke + " in:\n" + keymap); - } - - inst.delete (); - ShortcutsFolder.waitFinished (); - action = keymap.getAction (stroke); - assertNull ("Action removed", action); - } - - public static class TestAction extends AbstractAction { - public void actionPerformed (ActionEvent ae) {} - } - - public static class ENV extends Object implements Environment.Provider { - public Lookup getEnvironment(DataObject obj) { - if (obj instanceof XMLDataObject) { - try { - Document doc = ((XMLDataObject) obj).getDocument(); - if (doc.getDocumentElement().getNodeName().equals ("project")) { - return Lookups.singleton( - new InstanceSupport.Instance( - new TestAction () - ) - ); - } - } catch (Exception ex) { - ex.printStackTrace(); - fail ("No exception: " + ex.getMessage()); - } - } - return Lookup.EMPTY; - } - } - -} diff --git a/openide.awt/src/org/openide/awt/Actions.java b/openide.awt/src/org/openide/awt/Actions.java --- a/openide.awt/src/org/openide/awt/Actions.java +++ b/openide.awt/src/org/openide/awt/Actions.java @@ -63,15 +63,10 @@ import org.openide.util.HelpCtx; import org.openide.util.Lookup; import org.openide.util.NbBundle; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; -import java.util.Iterator; import java.util.Map; -import java.util.Observable; -import java.util.Observer; -import java.util.WeakHashMap; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ActionMap; @@ -84,7 +79,6 @@ import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.text.Keymap; import org.netbeans.api.actions.Closable; import org.netbeans.api.actions.Editable; import org.netbeans.api.actions.Openable; @@ -202,66 +196,6 @@ ((Actions.MenuItem)item).setBridge(b); } b.updateState(null); - if (!popup) { - // #39508 fix. - setMenuActionConnection(item, action); - } - } - - /** - * #39508 fix. the MenuItems have the accelerator set by the Bridge, however that is not removed when the Menu is invisible. - * it's because of the AddNotify/removeNotify method calls and the Bridge.VisL listener. - * that conflicts with the changes done in the global keymap (NbKeymap) that are not propagated to the menu items when such change occurs. - * Fixed by having one global observer on the NbKeyMap (or any other Keymap impl which is Observable) and always synchronizing the menus with the current - * global Keymap - */ - private static void setMenuActionConnection(JMenuItem menu, Action action) { - synchronized (menuActionLock) { - if (menuActionCache == null) { - menuActionCache = new WeakHashMap>(); - - Keymap map = Lookup.getDefault().lookup(Keymap.class); - - if (map instanceof Observable) { - //HACK MAJOR - assuming we have the NbKeymap which is observable - ((Observable) map).addObserver( - new Observer() { - public void update(Observable o, Object arg) { - synchronized (menuActionLock) { - Iterator>> it = menuActionCache.entrySet().iterator(); - - while (it.hasNext()) { - Map.Entry> entry = it.next(); - Action act = entry.getKey(); - Reference ref = entry.getValue(); - JMenuItem mn = ref.get(); - - if ((act != null) && (mn != null)) { - KeyStroke actKey = (KeyStroke) act.getValue(Action.ACCELERATOR_KEY); - KeyStroke mnKey = mn.getAccelerator(); - - if ( - ((mnKey == null) && (actKey != null)) || - ((mnKey != null) && (actKey == null)) || - ((mnKey != null) && (actKey != null) && !actKey.equals(mnKey)) - ) { - mn.setAccelerator(actKey); - } - } - } - } - } - } - ); - } else { - Logger.getLogger(Actions.class.getName()).warning( - "Keymap is not observable, behaviour described in bug #39508 can reappear." - ); - } - } - - menuActionCache.put(action, new WeakReference(menu)); - } } /** Attaches checkbox menu item to boolean state action. diff --git a/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java b/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java --- a/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java +++ b/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java @@ -14,8 +14,6 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; -import javax.swing.KeyStroke; -import javax.swing.text.Keymap; import org.netbeans.modules.openide.util.ActionsBridge; import org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable; import org.openide.util.ContextAwareAction; @@ -138,8 +136,9 @@ return null; } } - - return extractCommonAttribute(map, this, name); + Object o = extractCommonAttribute(map, this, name); + // cf. #137709 JG18: + return o != null ? o : super.getValue(name); } static final Object extractCommonAttribute(Map fo, Action action, String name) { @@ -185,13 +184,6 @@ if ("noIconInMenu".equals(name)) { // NOI18N return fo == null ? null : fo.get("noIconInMenu"); // NOI18N } - if (Action.ACCELERATOR_KEY.equals(name)) { - Keymap map = Lookup.getDefault().lookup(Keymap.class); - if (map != null) { - KeyStroke[] arr = map.getKeyStrokesForAction(action); - return arr.length > 0 ? arr[0] : null; - } - } // Delegate query to other properties to "fo" ignoring special properties if (!"delegate".equals(name) && !"instanceCreate".equals(name)) { return fo.get(name); @@ -227,7 +219,10 @@ return false; } - + @Override + public String toString() { + return "AlwaysEnabledAction[" + getValue(Action.NAME) + "]"; // NOI18N + } public void propertyChange(PropertyChangeEvent evt) { if (evt.getSource() == delegate) { diff --git a/openide.awt/src/org/openide/awt/GeneralAction.java b/openide.awt/src/org/openide/awt/GeneralAction.java --- a/openide.awt/src/org/openide/awt/GeneralAction.java +++ b/openide.awt/src/org/openide/awt/GeneralAction.java @@ -45,6 +45,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.swing.Action; @@ -245,10 +246,19 @@ } } - public void putValue(String key, Object o) { + private Map attrs; + + public void putValue(String key, Object value) { + if (attrs == null) { + attrs = new HashMap(); + } + attrs.put(key, value); } public Object getValue(String key) { + if (attrs != null && attrs.containsKey(key)) { + return attrs.get(key); + } Object ret = GeneralAction.extractCommonAttribute(map, this, key); if (ret != null) { return ret; diff --git a/openide.awt/test/unit/src/org/openide/awt/ActionsTest.java b/openide.awt/test/unit/src/org/openide/awt/ActionsTest.java --- a/openide.awt/test/unit/src/org/openide/awt/ActionsTest.java +++ b/openide.awt/test/unit/src/org/openide/awt/ActionsTest.java @@ -44,11 +44,6 @@ import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; -import java.util.Observable; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; @@ -58,7 +53,6 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.KeyStroke; -import javax.swing.text.Keymap; import org.netbeans.junit.MockServices; import org.netbeans.junit.NbTestCase; import org.openide.util.HelpCtx; @@ -115,8 +109,7 @@ } protected void setUp() { - MockServices.setServices(new Class[] {TestKeymap.class, TestConnector.class}); - assertNotNull("Keymap has to be in lookup", Lookup.getDefault().lookup(Keymap.class)); + MockServices.setServices(TestConnector.class); } /** @@ -238,37 +231,6 @@ } /** - * tests if the accelerator for JMenuItem is reset when the global KeyMap changes. - * Has to work even when the menu is not visible (when visible is handled by Actions.Bridge listeners) - * when not visible handled by the tested Actions.setMenuActionConnection() - only for menu items. - * #39508 - */ - public void testActionRemoval_Issue39508() throws Exception { - // prepare - Keymap map = (Keymap)Lookup.getDefault().lookup(Keymap.class); - map.removeBindings(); - Action action = new ActionsTest.TestAction(); - KeyStroke stroke = KeyStroke.getKeyStroke("ctrl alt 7"); - assertNotNull(stroke); - //test start - JMenuItem menu = new JMenuItem(); - assertNull(menu.getAccelerator()); - Actions.connect(menu, action, false); - assertEquals(1, ((Observable)map).countObservers()); - assertNull(menu.getAccelerator()); - map.addActionForKeyStroke(stroke, action); - assertNotNull(action.getValue(Action.ACCELERATOR_KEY)); - assertNotNull(menu.getAccelerator()); - map.removeKeyStrokeBinding(stroke); - assertNull(action.getValue(Action.ACCELERATOR_KEY)); - assertNull(menu.getAccelerator()); - Reference ref = new WeakReference(action); - menu = null; - action = null; - assertGC("action can dissappear", ref); - } - - /** * Tests if changes in accelerator key or name of the action does not change the tooltip * of the button if the action has a custom tooltip. See first part of #57974. */ @@ -523,73 +485,6 @@ } - public static final class TestKeymap extends Observable implements Keymap { - - private Map map = new HashMap(); - private Action defAct; - - public void addActionForKeyStroke(KeyStroke key, Action act) { - map.put(key, act); - act.putValue(Action.ACCELERATOR_KEY, key); - setChanged(); - notifyObservers(); - } - - public Action getAction(KeyStroke key) { - return (Action)map.get(key); - } - - public Action[] getBoundActions() { - return new Action[0]; - } - - public KeyStroke[] getBoundKeyStrokes() { - return new KeyStroke[0]; - } - - public Action getDefaultAction() { - return defAct; - } - - public KeyStroke[] getKeyStrokesForAction(Action a) { - return new KeyStroke[0]; - } - - public String getName() { - return "testKeymap"; - } - - public Keymap getResolveParent() { - return null; - } - - public boolean isLocallyDefined(KeyStroke key) { - return true; - } - - public void removeBindings() { - map.clear(); - } - - public void removeKeyStrokeBinding(KeyStroke keys) { - Action act = (Action)map.remove(keys); - if (act != null) { - act.putValue(Action.ACCELERATOR_KEY, null); - } - setChanged(); - notifyObservers(); - } - - public void setDefaultAction(Action a) { - defAct = a; - } - - public void setResolveParent(Keymap parent) { - // ignore - } - - } - public static final class TestConnector implements Actions.ButtonActionConnector { private int called = 0; diff --git a/openide.loaders/src/org/openide/awt/DynaMenuModel.java b/openide.loaders/src/org/openide/awt/DynaMenuModel.java --- a/openide.loaders/src/org/openide/awt/DynaMenuModel.java +++ b/openide.loaders/src/org/openide/awt/DynaMenuModel.java @@ -51,12 +51,12 @@ import java.util.Map; import javax.swing.Action; import javax.swing.Icon; -import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JSeparator; +import org.openide.filesystems.FileObject; import org.openide.util.ImageUtilities; import org.openide.util.Utilities; import org.openide.util.actions.Presenter; @@ -76,7 +76,7 @@ actionToMenuMap = new HashMap(); } - public void loadSubmenu(List cInstances, JMenu m) { + public void loadSubmenu(List cInstances, JMenu m, Map cookiesToFiles) { // clear first - refresh the menu's content boolean addSeparator = false; Icon curIcon = null; @@ -85,6 +85,9 @@ actionToMenuMap.clear(); while (it.hasNext()) { Object obj = it.next(); + if (obj instanceof Action) { + Toolbar.setAccelerator((Action) obj, cookiesToFiles.get(obj)); + } if (obj instanceof Presenter.Menu) { // does this still apply?? obj = ((Presenter.Menu)obj).getMenuPresenter(); diff --git a/openide.loaders/src/org/openide/awt/MenuBar.java b/openide.loaders/src/org/openide/awt/MenuBar.java --- a/openide.loaders/src/org/openide/awt/MenuBar.java +++ b/openide.loaders/src/org/openide/awt/MenuBar.java @@ -51,8 +51,10 @@ import java.io.ObjectOutput; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.Map; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ImageIcon; @@ -627,6 +629,14 @@ super.waitFinished(); } + private Map cookiesToFiles = new HashMap(); + + @Override + protected Object instanceForCookie(DataObject obj, InstanceCookie cookie) throws IOException, ClassNotFoundException { + Object result = super.instanceForCookie(obj, cookie); + cookiesToFiles.put(result, obj.getPrimaryFile()); + return result; + } /** * Accepts only cookies that can provide Menu. @@ -685,7 +695,7 @@ m.add(item); } - m.dynaModel.loadSubmenu(cInstances, m); + m.dynaModel.loadSubmenu(cInstances, m, cookiesToFiles); return m; } diff --git a/openide.loaders/src/org/openide/awt/Toolbar.java b/openide.loaders/src/org/openide/awt/Toolbar.java --- a/openide.loaders/src/org/openide/awt/Toolbar.java +++ b/openide.loaders/src/org/openide/awt/Toolbar.java @@ -58,14 +58,18 @@ import javax.swing.JComponent; import javax.swing.JSeparator; import javax.swing.JToolBar; +import javax.swing.KeyStroke; import javax.swing.UIManager; import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.text.Keymap; import org.netbeans.modules.openide.loaders.DataObjectAccessor; import org.openide.cookies.InstanceCookie; +import org.openide.filesystems.FileObject; import org.openide.loaders.DataFolder; import org.openide.loaders.DataObject; import org.openide.loaders.FolderInstance; import org.openide.util.ImageUtilities; +import org.openide.util.Lookup; import org.openide.util.Task; import org.openide.util.actions.Presenter; @@ -352,7 +356,7 @@ return Toolbar.this.getClass(); } - private Map cookiesToObjects = new HashMap(); + private Map cookiesToObjects = new HashMap(); @Override protected Object instanceForCookie (DataObject obj, InstanceCookie cookie) @@ -411,7 +415,7 @@ for (int i = 0; i < cookies.length; i++) { try { Object obj = cookies[i].instanceCreate(); - Object file = cookiesToObjects.get(obj); + DataObject file = cookiesToObjects.get(obj); if (obj instanceof Presenter.Toolbar) { obj = ((Presenter.Toolbar) obj).getToolbarPresenter(); @@ -447,6 +451,7 @@ org.openide.awt.Actions.connect(b, a); b.putClientProperty("file", file); org.openide.awt.Toolbar.this.add(b); + setAccelerator(a, file.getPrimaryFile()); continue; } } @@ -479,6 +484,25 @@ } // end of inner class Folder + static void setAccelerator(Action a, FileObject file) { + if (file == null) { + return; + } + a.putValue("definingFile", file); // cf. o.n.core.NbKeymap.getKeyStrokesForAction + KeyStroke[] keys; + try { + assert a.getValue("definingFile") == file : a.getClass() + " violated Action.putValue contract"; + Keymap keymap = Lookup.getDefault().lookup(Keymap.class); + keys = keymap != null ? keymap.getKeyStrokesForAction(a) : new KeyStroke[0]; + assert keys != null : keymap; + } finally { + a.putValue("definingFile", null); + } + if (keys.length > 0) { + a.putValue(Action.ACCELERATOR_KEY, keys[0]); + } + } + @Override public void setUI(javax.swing.plaf.ToolBarUI ui) { super.setUI(ui); diff --git a/openide.loaders/test/unit/src/org/openide/awt/DynaMenuModelTest.java b/openide.loaders/test/unit/src/org/openide/awt/DynaMenuModelTest.java --- a/openide.loaders/test/unit/src/org/openide/awt/DynaMenuModelTest.java +++ b/openide.loaders/test/unit/src/org/openide/awt/DynaMenuModelTest.java @@ -44,6 +44,7 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.swing.AbstractAction; import javax.swing.JComponent; @@ -52,6 +53,7 @@ import javax.swing.JPopupMenu; import javax.swing.JSeparator; import junit.framework.TestCase; +import org.openide.filesystems.FileObject; import org.openide.util.actions.Presenter; /** @@ -70,13 +72,13 @@ public void testLoadSubmenu() { System.out.println("loadSubmenu"); - List cInstances = new ArrayList(); + List cInstances = new ArrayList(); cInstances.add(new Act1()); cInstances.add(new Act2()); JMenu m = new JMenu(); DynaMenuModel instance = new DynaMenuModel(); - instance.loadSubmenu(cInstances, m); + instance.loadSubmenu(cInstances, m, Collections.emptyMap()); Component[] comps = m.getPopupMenu().getComponents(); assertEquals("0", ((JMenuItem)comps[0]).getText()); assertEquals("1", ((JMenuItem)comps[1]).getText()); @@ -88,13 +90,13 @@ * Test of checkSubmenu method, of class org.openide.awt.DynaMenuModel. */ public void testCheckSubmenu() { - List cInstances = new ArrayList(); + List cInstances = new ArrayList(); cInstances.add(new Act1()); cInstances.add(new Act2()); JMenu m = new JMenu(); DynaMenuModel instance = new DynaMenuModel(); - instance.loadSubmenu(cInstances, m); + instance.loadSubmenu(cInstances, m, Collections.emptyMap()); instance.checkSubmenu(m); Component[] comps = m.getPopupMenu().getComponents();