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

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

(-)a/o.n.core/src/org/netbeans/core/NbKeymap.java (-139 / +95 lines)
Lines 43-60 Link Here
43
43
44
import java.awt.event.ActionEvent;
44
import java.awt.event.ActionEvent;
45
import java.awt.event.KeyEvent;
45
import java.awt.event.KeyEvent;
46
import java.io.IOException;
46
import java.util.ArrayList;
47
import java.util.ArrayList;
47
import java.util.Arrays;
48
import java.util.Collections;
48
import java.util.Collections;
49
import java.util.Comparator;
49
import java.util.Comparator;
50
import java.util.HashMap;
50
import java.util.HashMap;
51
import java.util.HashSet;
52
import java.util.Iterator;
53
import java.util.List;
51
import java.util.List;
54
import java.util.Map;
52
import java.util.Map;
55
import java.util.Map.Entry;
56
import java.util.Observable;
53
import java.util.Observable;
57
import java.util.Set;
54
import java.util.TreeMap;
58
import java.util.logging.Level;
55
import java.util.logging.Level;
59
import java.util.logging.Logger;
56
import java.util.logging.Logger;
60
import javax.swing.AbstractAction;
57
import javax.swing.AbstractAction;
Lines 62-68 Link Here
62
import javax.swing.KeyStroke;
59
import javax.swing.KeyStroke;
63
import javax.swing.text.Keymap;
60
import javax.swing.text.Keymap;
64
import org.openide.awt.StatusDisplayer;
61
import org.openide.awt.StatusDisplayer;
65
import org.openide.util.Mutex;
62
import org.openide.cookies.InstanceCookie;
63
import org.openide.filesystems.FileObject;
64
import org.openide.filesystems.FileUtil;
65
import org.openide.loaders.DataObject;
66
import org.openide.util.Exceptions;
67
import org.openide.util.Utilities;
66
import org.openide.util.actions.SystemAction;
68
import org.openide.util.actions.SystemAction;
67
import org.openide.util.lookup.ServiceProvider;
69
import org.openide.util.lookup.ServiceProvider;
68
70
Lines 76-83 Link Here
76
    String name;
78
    String name;
77
    /** Parent keymap */
79
    /** Parent keymap */
78
    Keymap parent;
80
    Keymap parent;
79
    /** Hashtable holding KeyStroke > Action mappings */
80
    Map<KeyStroke,Action> bindings;
81
    /** Default action */
81
    /** Default action */
82
    Action defaultAction;
82
    Action defaultAction;
83
    /** hash table to map (Action -> ArrayList of KeyStrokes) */
83
    /** hash table to map (Action -> ArrayList of KeyStrokes) */
Lines 130-136 Link Here
130
    NbKeymap(final String name, final Keymap parent) {
130
    NbKeymap(final String name, final Keymap parent) {
131
        this.name = name;
131
        this.name = name;
132
        this.parent = parent;
132
        this.parent = parent;
133
        bindings = new HashMap<KeyStroke,Action>();
134
    }
133
    }
135
134
136
    public Action getDefaultAction() {
135
    public Action getDefaultAction() {
Lines 161-167 Link Here
161
        Keymap activ = this;
160
        Keymap activ = this;
162
        for (int i=0; i<ctx.length; i++) {
161
        for (int i=0; i<ctx.length; i++) {
163
            if (activ == this) {
162
            if (activ == this) {
164
                a = bindings.get(ctx[i]);
163
                a = find(ctx[i]);
165
                if ((a == null) && (parent != null)) {
164
                if ((a == null) && (parent != null)) {
166
                    a = parent.getAction(ctx[i]);
165
                    a = parent.getAction(ctx[i]);
167
                }
166
                }
Lines 183-189 Link Here
183
        }
182
        }
184
        
183
        
185
        if (activ == this) {
184
        if (activ == this) {
186
            a = bindings.get(key);
185
            a = find(key);
187
            if ((a == null) && (parent != null)) {
186
            if ((a == null) && (parent != null)) {
188
                a = parent.getAction(key);
187
                a = parent.getAction(key);
189
            }
188
            }
Lines 218-304 Link Here
218
    }
217
    }
219
218
220
    public KeyStroke[] getBoundKeyStrokes() {
219
    public KeyStroke[] getBoundKeyStrokes() {
221
        LOG.log(Level.FINE, "getBoundKeyStrokes");
220
        assert false;
222
        int i = 0;
221
        return null;
223
        KeyStroke[] keys = null;
224
        synchronized (this) {
225
            keys = new KeyStroke[bindings.size()];
226
            for (KeyStroke ks: bindings.keySet()) {
227
                keys[i++] = ks;
228
            }
229
        }
230
        return keys;
231
    }
222
    }
232
223
233
    public Action[] getBoundActions() {
224
    public Action[] getBoundActions() {
234
        LOG.log(Level.FINE, "getBoundActions");
225
        assert false;
235
        int i = 0;
226
        return null;
236
        Action[] actionsArray = null;
237
        synchronized (this) {
238
            actionsArray = new Action[bindings.size()];
239
            for (Iterator iter = bindings.values().iterator(); iter.hasNext(); ) {
240
                actionsArray[i++] = (Action) iter.next();
241
            }
242
        }
243
        return actionsArray;
244
    }
227
    }
245
228
246
    public KeyStroke[] getKeyStrokesForAction(Action a) {
229
    public KeyStroke[] getKeyStrokesForAction(Action a) {
247
        LOG.log(Level.FINE, "getKeyStrokesForAction {0}", id(a));
230
        LOG.log(Level.FINE, "getKeyStrokesForAction {0}", id(a));
248
231
        FileObject definingFile = (FileObject) a.getValue("definingFile"); // cf. o.o.awt.Toolbar.setAccelerator
249
        Map<Action,List<KeyStroke>> localActions = actions;
232
        if (definingFile == null) {
250
        if (localActions == null) {
233
            System.err.println("XXX no defining file known for " + a);
251
            localActions = buildReverseMapping ();
252
        }
253
254
        List<KeyStroke> strokes = localActions.get (a);
255
        if (strokes != null) {
256
            return strokes.toArray(new KeyStroke[strokes.size ()]);
257
        } else {
258
            return new KeyStroke[0];
234
            return new KeyStroke[0];
259
        }
235
        }
236
        synchronized (this) {
237
            if (id2Stroke == null) {
238
                id2Stroke = new TreeMap<String,String>();
239
                FileObject shortcuts = FileUtil.getConfigFile("Shortcuts");
240
                for (FileObject f : shortcuts.getChildren()) {
241
                    id2Stroke.put(idForFile(f), f.getName());
242
                }
243
                shortcuts = FileUtil.getConfigFile("Keymaps/NetBeans");
244
                for (FileObject f : shortcuts.getChildren()) {
245
                    id2Stroke.put(idForFile(f), f.getName());
246
                }
247
                { // XXX for debugging
248
                    for (Map.Entry<String,String> entry : id2Stroke.entrySet()) {
249
                        System.err.println(entry.getValue() + " => " + entry.getKey());
250
                    }
251
                }
252
            }
253
        }
254
        String id = idForFile(definingFile);
255
        String k = id2Stroke.get(id);
256
        System.err.println("XXX found keystroke " + k + " for " + a + " with ID " + id);
257
        // XXX return all available keystrokes, or make Toolbar.setAccelerator pick the most common, e.g. C-V over PASTE
258
        return k != null ? new KeyStroke[] {Utilities.stringToKey(k)} : new KeyStroke[0];
259
    }
260
    private Map<String,String> id2Stroke;
261
    /**
262
     * Traverses shadow files to origin.
263
     * Returns impl class name if that is obvious (common for SystemAction's);
264
     * else just returns file path (usual for more modern registrations).
265
     */
266
    private static String idForFile(FileObject f) {
267
        if (f.hasExt("shadow")) {
268
            String path = (String) f.getAttribute("originalFile");
269
            f = FileUtil.getConfigFile(path);
270
        }
271
        // Cannot actually load instanceCreate methodvalue=... attribute; just want to see if it is there.
272
        if (f.hasExt("instance") && !Collections.list(f.getAttributes()).contains("instanceCreate")) {
273
            String clazz = (String) f.getAttribute("instanceClass");
274
            if (clazz != null) {
275
                return clazz;
276
            } else {
277
                return f.getName().replace('-', '.');
278
            }
279
        }
280
        return f.getPath();
260
    }
281
    }
261
282
262
    private Map<Action,List<KeyStroke>> buildReverseMapping () {
283
    private Action find(KeyStroke key) {
263
        Map<Action,List<KeyStroke>> localActions = actions = new HashMap<Action,List<KeyStroke>> ();
284
        FileObject shortcuts = FileUtil.getConfigFile("Keymaps/NetBeans");
264
285
        String nm = Utilities.keyToString(key);
265
        synchronized (this) {
286
        FileObject def = shortcuts.getFileObject(nm + ".shadow");
266
            for (Map.Entry<KeyStroke,Action> curEntry: bindings.entrySet()) {
287
        if (def == null) {
267
                Action curAction = curEntry.getValue();
288
            def = shortcuts.getFileObject(nm + ".instance");
268
                KeyStroke curKey = curEntry.getKey();
289
        }
269
290
        if (def == null) {
270
                List<KeyStroke> keysForAction = localActions.get (curAction);
291
            shortcuts = FileUtil.getConfigFile("Shortcuts");
271
                if (keysForAction == null) {
292
            def = shortcuts.getFileObject(nm + ".shadow");
272
                    keysForAction = Collections.synchronizedList (new ArrayList<KeyStroke> (1));
293
            if (def == null) {
273
                    localActions.put (curAction, keysForAction);
294
                def = shortcuts.getFileObject(nm + ".instance");
274
                }
295
            }
275
                keysForAction.add (curKey);
296
            if (def == null) {
297
                return null;
276
            }
298
            }
277
        }
299
        }
278
300
        try {
279
        return localActions;
301
            DataObject d = DataObject.find(def);
302
            InstanceCookie ic = d.getLookup().lookup(InstanceCookie.class);
303
            if (ic == null) {
304
                return null;
305
            }
306
            return (Action) ic.instanceCreate();
307
        } catch (ClassNotFoundException x) {
308
            Exceptions.printStackTrace(x);
309
        } catch (IOException x) {
310
            Exceptions.printStackTrace(x);
311
        }
312
        return null;
280
    }
313
    }
281
314
282
    public synchronized boolean isLocallyDefined(KeyStroke key) {
315
    public synchronized boolean isLocallyDefined(KeyStroke key) {
283
        LOG.log(Level.FINE, "isLocallyDefined {0}", key);
316
        assert false;
284
        return bindings.containsKey(key);
317
        return false;
285
    }
318
    }
286
319
287
    /** Updates action accelerator. */
288
    private void updateActionAccelerator(final Action a) {
289
        if(a == null) {
290
            return;
291
        }
292
        
293
        Mutex.EVENT.writeAccess(new Runnable() {
294
            public void run() {
295
                KeyStroke[] keystrokes = getKeyStrokesForAction(a);
296
                Arrays.sort (keystrokes, NbKeymap.this);
297
                a.putValue(Action.ACCELERATOR_KEY, keystrokes.length > 0 ? keystrokes[0] : null);
298
            }
299
        });
300
    }
301
    
302
    public int compare(KeyStroke k1, KeyStroke k2) {
320
    public int compare(KeyStroke k1, KeyStroke k2) {
303
        //#47024 and 32733 - "Find" should not be shown as an accelerator,
321
        //#47024 and 32733 - "Find" should not be shown as an accelerator,
304
        //nor should "Backspace" for Delete.  Solution:  The shorter text wins.
322
        //nor should "Backspace" for Delete.  Solution:  The shorter text wins.
Lines 308-377 Link Here
308
    
326
    
309
    
327
    
310
    public void addActionForKeyStroke(KeyStroke key, Action a) {
328
    public void addActionForKeyStroke(KeyStroke key, Action a) {
311
        LOG.log(Level.FINE, "addActionForKeyStroke {0} => {1}", new Object[] { key, id(a) });
329
        assert false;
312
        // Update reverse binding for old action too (#30455):
313
        Action old;
314
        synchronized (this) {
315
            old = bindings.put(key, a);
316
            actions = null;
317
        }
318
        
319
        updateActionAccelerator(a);
320
        updateActionAccelerator(old);
321
        setChanged();
322
        notifyObservers();
323
    }
324
325
    void addActionForKeyStrokeMap(Map<KeyStroke,Action> map) {
326
        Set<Action> actionsSet = new HashSet<Action>();
327
        synchronized (this) {
328
            for (Entry<KeyStroke,Action> entry: map.entrySet ()) {
329
                KeyStroke key = entry.getKey();
330
                Action value = entry.getValue();
331
                // Add both old and new action:
332
                actionsSet.add(value);
333
                actionsSet.add(bindings.put(key, value));
334
            }
335
            actions = null;
336
        }
337
        
338
        for(Action a: actionsSet) {
339
            updateActionAccelerator(a);
340
        }
341
        
342
        setChanged();
343
        notifyObservers();
344
    }
330
    }
345
331
346
    public void removeKeyStrokeBinding(KeyStroke key) {
332
    public void removeKeyStrokeBinding(KeyStroke key) {
347
        LOG.log(Level.FINE, "removeKeyStrokeBinding {0}", key);
333
        assert false;
348
349
        Action a;
350
        synchronized (this) {
351
            a = bindings.remove(key);
352
            actions = null;
353
        }
354
        updateActionAccelerator(a);
355
        setChanged();
356
        notifyObservers();
357
    }
334
    }
358
335
359
    public void removeBindings() {
336
    public void removeBindings() {
360
        LOG.log(Level.FINE, "removeBindings");
337
        assert false;
361
362
        Set<Action> actionsSet;
363
        synchronized (this) {
364
            actionsSet = new HashSet<Action>(bindings.values());
365
            bindings.clear();
366
            actions = null;
367
        }
368
        
369
        for(Action a: actionsSet) {
370
            updateActionAccelerator(a);
371
        }
372
        
373
        setChanged();
374
        notifyObservers();
375
    }
338
    }
376
339
377
    public Keymap getResolveParent() {
340
    public Keymap getResolveParent() {
Lines 385-397 Link Here
385
        notifyObservers();
348
        notifyObservers();
386
    }
349
    }
387
350
388
    /** Returns string representation - can be looong.
389
    */
390
    @Override
391
    public String toString() {
392
        return "Keymap[" + name + "]" + bindings; // NOI18N
393
    }
394
395
    private static Object id(Action a) {
351
    private static Object id(Action a) {
396
        if (a instanceof SystemAction) {
352
        if (a instanceof SystemAction) {
397
            return a.getClass();
353
            return a.getClass();
(-)a/o.n.core/src/org/netbeans/core/NonGui.java (-7 lines)
Lines 147-159 Link Here
147
        Splash.getInstance().increment(10);
147
        Splash.getInstance().increment(10);
148
        StartLog.logProgress ("Timer initialized"); // NOI18N
148
        StartLog.logProgress ("Timer initialized"); // NOI18N
149
149
150
        // -----------------------------------------------------------------------------------------------------
151
        // 13. Initialize Shortcuts
152
        ShortcutsFolder.initShortcuts();
153
        Splash.getInstance().increment(1);
154
        StartLog.logProgress ("Shortcuts initialized"); // NOI18N
155
156
157
    // -----------------------------------------------------------------------------------------------------
150
    // -----------------------------------------------------------------------------------------------------
158
    // 14. Open main window
151
    // 14. Open main window
159
        StatusDisplayer.getDefault().setStatusText (NbBundle.getMessage (NonGui.class, "MSG_WindowShowInit"));
152
        StatusDisplayer.getDefault().setStatusText (NbBundle.getMessage (NonGui.class, "MSG_WindowShowInit"));
(-)a/o.n.core/src/org/netbeans/core/ShortcutsFolder.java (-236 lines)
Lines 1-236 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * Contributor(s):
25
 *
26
 * The Original Software is NetBeans. The Initial Developer of the Original
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
 * Microsystems, Inc. All Rights Reserved.
29
 *
30
 * If you wish your version of this file to be governed by only the CDDL
31
 * or only the GPL Version 2, indicate your decision by adding
32
 * "[Contributor] elects to include this software in this distribution
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34
 * single choice of license, a recipient has the option to distribute
35
 * your version of this file under either the CDDL, the GPL Version 2 or
36
 * to extend the choice of license to its licensees as provided above.
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
40
 */
41
42
package org.netbeans.core;
43
44
import java.io.IOException;
45
import java.util.Collection;
46
import java.util.Enumeration;
47
import java.util.LinkedList;
48
import java.util.logging.Level;
49
import java.util.logging.Logger;
50
import javax.swing.Action;
51
import javax.swing.KeyStroke;
52
import javax.swing.text.Keymap;
53
import org.netbeans.core.NbKeymap.KeymapAction;
54
import org.netbeans.core.startup.StartLog;
55
import org.openide.cookies.InstanceCookie;
56
import org.openide.filesystems.FileAttributeEvent;
57
import org.openide.filesystems.FileChangeAdapter;
58
import org.openide.filesystems.FileEvent;
59
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.FileUtil;
61
import org.openide.loaders.DataFolder;
62
import org.openide.loaders.DataObject;
63
import org.openide.util.Exceptions;
64
import org.openide.util.Lookup;
65
import org.openide.util.RequestProcessor;
66
import org.openide.util.Utilities;
67
68
/**
69
 * Bridge to old layers based system.
70
 *
71
 * @author Jan Jancura
72
 */
73
class ShortcutsFolder {
74
    
75
    private static final String PROFILES_FOLDER = "Keymaps";
76
    private static final String SHORTCUTS_FOLDER = "Shortcuts";
77
    private static final String CURRENT_PROFILE_ATTRIBUTE = "currentKeymap";
78
79
    private static ShortcutsFolder  shortcutsFolder;
80
    private Listener                listener = new Listener ();
81
    private FileObject              profilesFileObject;
82
    private FileObject              shortcutsFileObject;
83
    private FileObject              currentFolder;
84
    private Logger debug = Logger.getLogger(ShortcutsFolder.class.getName ());
85
    private Collection<DataObject> dataObjects;
86
    
87
    
88
    static void initShortcuts () {
89
        StartLog.logStart("initShortcuts");
90
        try {
91
            if (shortcutsFolder != null) return;
92
            shortcutsFolder = new ShortcutsFolder ();
93
        } finally {
94
            StartLog.logEnd("initShortcuts");
95
        }
96
    }
97
    
98
    private ShortcutsFolder () {
99
        try {
100
            FileObject root = FileUtil.getConfigRoot ();
101
            profilesFileObject = root.getFileObject (PROFILES_FOLDER);
102
            if (profilesFileObject == null)
103
                profilesFileObject = root.createFolder (PROFILES_FOLDER);
104
            profilesFileObject.addFileChangeListener (listener);
105
            
106
            shortcutsFileObject = root.getFileObject (SHORTCUTS_FOLDER);
107
            if (shortcutsFileObject == null)
108
                shortcutsFileObject = root.createFolder (SHORTCUTS_FOLDER);
109
            shortcutsFileObject.addFileChangeListener (listener);            
110
        } catch (IOException ex) {
111
            Exceptions.printStackTrace(ex);
112
        }
113
        refresh ();
114
    }
115
    
116
    static void waitFinished () {
117
        shortcutsFolder.listener.task.waitFinished ();
118
    }
119
    
120
    private void refresh () {
121
        
122
        // get keymap and delete old shortcuts
123
        NbKeymap keymap = (NbKeymap) Lookup.getDefault ().lookup (Keymap.class);
124
        keymap.removeBindings ();
125
        dataObjects = new LinkedList<DataObject>();
126
127
        // update main shortcuts
128
        readShortcuts (keymap, shortcutsFileObject);
129
        
130
        // update shortcuts from profile
131
        String keymapName = (String) profilesFileObject.getAttribute
132
            (CURRENT_PROFILE_ATTRIBUTE);
133
        if (keymapName == null || "".equals (keymapName))
134
            keymapName = "NetBeans"; // NOI18N
135
        if (currentFolder != null) 
136
            currentFolder.removeFileChangeListener (listener);
137
        currentFolder = FileUtil.getConfigFile (PROFILES_FOLDER + '/' + keymapName);
138
        if (currentFolder == null) {
139
            try {
140
                currentFolder = profilesFileObject.createFolder(keymapName);
141
            } catch (IOException ioe) {
142
                Exceptions.printStackTrace(ioe);
143
            }
144
        }
145
        if (currentFolder != null) {
146
            readShortcuts (keymap, currentFolder);
147
            // add listener to current profile folder
148
            currentFolder.addFileChangeListener (listener);
149
        }
150
    }
151
    
152
    
153
    private void readShortcuts (NbKeymap keymap, FileObject fileObject) {
154
        debug.fine("\nreadShortcuts " + fileObject);
155
        DataFolder folder = DataFolder.findFolder (fileObject);
156
        Enumeration<DataObject> en = folder.children(false);
157
        while (en.hasMoreElements ()) {
158
            DataObject dataObject = en.nextElement();
159
            if (dataObject instanceof DataFolder) continue;
160
            InstanceCookie ic = dataObject.getCookie(InstanceCookie.class);
161
            if (ic == null) continue;
162
            try {
163
                Action action = (Action) ic.instanceCreate ();
164
                String shortcuts = dataObject.getName ();
165
                debug.fine("  " + shortcuts + " : " + action);
166
                KeyStroke[] keyStrokes = Utilities.stringToKeys (shortcuts);
167
                if (keyStrokes != null) {
168
                    addShortcut(keymap, action, keyStrokes);
169
                } else { // see e.g. secondary exception in #74169
170
                    debug.warning("Unrecognized shortcut name from " + dataObject.getPrimaryFile().getPath()); // NOI18N
171
                }
172
                //remember DataObjects used to create the Actions so that there are
173
                //the same Action instances in the menu
174
                dataObjects.add( dataObject );
175
            } catch (ClassNotFoundException x) {
176
                Logger.getLogger(ShortcutsFolder.class.getName()).log(Level.WARNING,
177
                        "{0} ignored; cannot load class {1}",
178
                        new Object[] {dataObject.getPrimaryFile().getPath(), ic.instanceName()});
179
            } catch (Exception ex) {
180
                Logger.getLogger(ShortcutsFolder.class.getName()).log(Level.WARNING, null, ex);
181
            }
182
        }
183
    }
184
        
185
    private static void addShortcut (
186
        NbKeymap keymap, 
187
        Action action, 
188
        KeyStroke[] keyStrokes
189
    ) {
190
        Keymap currentKeymap = keymap;
191
        int i, k = keyStrokes.length - 1;
192
        for (i = 0; i < k; i++) {
193
            Action a = currentKeymap.getAction (keyStrokes [i]);
194
            if (a == null) {
195
                a = keymap.createMapAction 
196
                    (new NbKeymap.SubKeymap (null), keyStrokes [i]);
197
                currentKeymap.addActionForKeyStroke (keyStrokes [i], a);
198
            }
199
            if (!(a instanceof KeymapAction)) return;
200
            currentKeymap = ((KeymapAction) a).getSubMap ();
201
        }
202
        currentKeymap.addActionForKeyStroke (keyStrokes [k], action);
203
    }
204
    
205
    private class Listener extends FileChangeAdapter implements Runnable {
206
        
207
        private RequestProcessor.Task task = new RequestProcessor ("ShortcutsFolder").create (this);
208
        
209
        public void run () {
210
            refresh ();
211
        }
212
        
213
        @Override
214
        public void fileDataCreated (FileEvent fe) {
215
            task.schedule (500);
216
        }
217
218
        @Override
219
        public void fileChanged (FileEvent fe) {
220
            task.schedule (500);
221
        }
222
223
        @Override
224
        public void fileDeleted (FileEvent fe) {
225
            task.schedule (500);
226
        }
227
        
228
        @Override
229
        public void fileAttributeChanged (FileAttributeEvent fe) {
230
            if (fe.getName () != null &&
231
                !CURRENT_PROFILE_ATTRIBUTE.equals (fe.getName ())
232
            ) return;
233
            task.schedule (500);
234
        }
235
    }
236
}
(-)a/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java (-11 / +3 lines)
Lines 14-21 Link Here
14
import javax.swing.AbstractAction;
14
import javax.swing.AbstractAction;
15
import javax.swing.Action;
15
import javax.swing.Action;
16
import javax.swing.Icon;
16
import javax.swing.Icon;
17
import javax.swing.KeyStroke;
18
import javax.swing.text.Keymap;
19
import org.openide.util.ContextAwareAction;
17
import org.openide.util.ContextAwareAction;
20
import org.openide.util.ImageUtilities;
18
import org.openide.util.ImageUtilities;
21
import org.openide.util.Lookup;
19
import org.openide.util.Lookup;
Lines 129-136 Link Here
129
                return null;
127
                return null;
130
            }
128
            }
131
        }
129
        }
132
130
        Object o = extractCommonAttribute(map, this, name);
133
        return extractCommonAttribute(map, this, name);
131
        // cf. #137709 JG18:
132
        return o != null ? o : super.getValue(name);
134
    }
133
    }
135
134
136
    static final Object extractCommonAttribute(Map fo, Action action, String name) {
135
    static final Object extractCommonAttribute(Map fo, Action action, String name) {
Lines 168-180 Link Here
168
        if ("noIconInMenu".equals(name)) { // NOI18N
167
        if ("noIconInMenu".equals(name)) { // NOI18N
169
            return fo == null ? null : fo.get("noIconInMenu"); // NOI18N
168
            return fo == null ? null : fo.get("noIconInMenu"); // NOI18N
170
        }
169
        }
171
        if (Action.ACCELERATOR_KEY.equals(name)) {
172
            Keymap map = Lookup.getDefault().lookup(Keymap.class);
173
            if (map != null) {
174
                KeyStroke[] arr = map.getKeyStrokesForAction(action);
175
                return arr.length > 0 ? arr[0] : null;
176
            }
177
        }
178
        // Delegate query to other properties to "fo" ignoring special properties
170
        // Delegate query to other properties to "fo" ignoring special properties
179
        if (!"delegate".equals(name) && !"instanceCreate".equals(name)) {
171
        if (!"delegate".equals(name) && !"instanceCreate".equals(name)) {
180
            return fo.get(name);
172
            return fo.get(name);
(-)a/openide.loaders/src/org/openide/awt/DynaMenuModel.java (-2 / +5 lines)
Lines 51-62 Link Here
51
import java.util.Map;
51
import java.util.Map;
52
import javax.swing.Action;
52
import javax.swing.Action;
53
import javax.swing.Icon;
53
import javax.swing.Icon;
54
import javax.swing.ImageIcon;
55
import javax.swing.JComponent;
54
import javax.swing.JComponent;
56
import javax.swing.JMenu;
55
import javax.swing.JMenu;
57
import javax.swing.JMenuItem;
56
import javax.swing.JMenuItem;
58
import javax.swing.JPopupMenu;
57
import javax.swing.JPopupMenu;
59
import javax.swing.JSeparator;
58
import javax.swing.JSeparator;
59
import org.openide.filesystems.FileObject;
60
import org.openide.util.ImageUtilities;
60
import org.openide.util.ImageUtilities;
61
import org.openide.util.Utilities;
61
import org.openide.util.Utilities;
62
import org.openide.util.actions.Presenter;
62
import org.openide.util.actions.Presenter;
Lines 76-82 Link Here
76
        actionToMenuMap = new HashMap<DynamicMenuContent, JComponent[]>();
76
        actionToMenuMap = new HashMap<DynamicMenuContent, JComponent[]>();
77
    }
77
    }
78
    
78
    
79
    public void loadSubmenu(List cInstances, JMenu m) {
79
    public void loadSubmenu(List cInstances, JMenu m, Map<Object,FileObject> cookiesToFiles) {
80
        // clear first - refresh the menu's content
80
        // clear first - refresh the menu's content
81
        boolean addSeparator = false;
81
        boolean addSeparator = false;
82
        Icon curIcon = null;
82
        Icon curIcon = null;
Lines 85-90 Link Here
85
        actionToMenuMap.clear();
85
        actionToMenuMap.clear();
86
        while (it.hasNext()) {
86
        while (it.hasNext()) {
87
            Object obj = it.next();
87
            Object obj = it.next();
88
            if (obj instanceof Action) {
89
                Toolbar.setAccelerator((Action) obj, cookiesToFiles.get(obj));
90
            }
88
            if (obj instanceof Presenter.Menu) {
91
            if (obj instanceof Presenter.Menu) {
89
                // does this still apply??
92
                // does this still apply??
90
                obj = ((Presenter.Menu)obj).getMenuPresenter();
93
                obj = ((Presenter.Menu)obj).getMenuPresenter();
(-)a/openide.loaders/src/org/openide/awt/MenuBar.java (-1 / +11 lines)
Lines 51-58 Link Here
51
import java.io.ObjectOutput;
51
import java.io.ObjectOutput;
52
import java.util.ArrayList;
52
import java.util.ArrayList;
53
import java.util.Arrays;
53
import java.util.Arrays;
54
import java.util.HashMap;
54
import java.util.Iterator;
55
import java.util.Iterator;
55
import java.util.LinkedList;
56
import java.util.LinkedList;
57
import java.util.Map;
56
import javax.swing.Action;
58
import javax.swing.Action;
57
import javax.swing.BorderFactory;
59
import javax.swing.BorderFactory;
58
import javax.swing.ImageIcon;
60
import javax.swing.ImageIcon;
Lines 627-632 Link Here
627
                super.waitFinished();
629
                super.waitFinished();
628
            }
630
            }
629
            
631
            
632
        private Map<Object,FileObject> cookiesToFiles = new HashMap<Object,FileObject>();
633
634
        @Override
635
        protected Object instanceForCookie(DataObject obj, InstanceCookie cookie) throws IOException, ClassNotFoundException {
636
            Object result = super.instanceForCookie(obj, cookie);
637
            cookiesToFiles.put(result, obj.getPrimaryFile());
638
            return result;
639
        }
630
640
631
    	    /**
641
    	    /**
632
             * Accepts only cookies that can provide <code>Menu</code>.
642
             * Accepts only cookies that can provide <code>Menu</code>.
Lines 685-691 Link Here
685
                    m.add(item);
695
                    m.add(item);
686
                }
696
                }
687
697
688
                m.dynaModel.loadSubmenu(cInstances, m);
698
                m.dynaModel.loadSubmenu(cInstances, m, cookiesToFiles);
689
699
690
                return m;
700
                return m;
691
            }
701
            }
(-)a/openide.loaders/src/org/openide/awt/Toolbar.java (-2 / +25 lines)
Lines 58-71 Link Here
58
import javax.swing.JComponent;
58
import javax.swing.JComponent;
59
import javax.swing.JSeparator;
59
import javax.swing.JSeparator;
60
import javax.swing.JToolBar;
60
import javax.swing.JToolBar;
61
import javax.swing.KeyStroke;
61
import javax.swing.UIManager;
62
import javax.swing.UIManager;
62
import javax.swing.plaf.metal.MetalLookAndFeel;
63
import javax.swing.plaf.metal.MetalLookAndFeel;
64
import javax.swing.text.Keymap;
63
import org.netbeans.modules.openide.loaders.DataObjectAccessor;
65
import org.netbeans.modules.openide.loaders.DataObjectAccessor;
64
import org.openide.cookies.InstanceCookie;
66
import org.openide.cookies.InstanceCookie;
67
import org.openide.filesystems.FileObject;
65
import org.openide.loaders.DataFolder;
68
import org.openide.loaders.DataFolder;
66
import org.openide.loaders.DataObject;
69
import org.openide.loaders.DataObject;
67
import org.openide.loaders.FolderInstance;
70
import org.openide.loaders.FolderInstance;
68
import org.openide.util.ImageUtilities;
71
import org.openide.util.ImageUtilities;
72
import org.openide.util.Lookup;
69
import org.openide.util.Task;
73
import org.openide.util.Task;
70
import org.openide.util.actions.Presenter;
74
import org.openide.util.actions.Presenter;
71
75
Lines 352-358 Link Here
352
            return Toolbar.this.getClass();
356
            return Toolbar.this.getClass();
353
        }
357
        }
354
358
355
        private Map<Object, Object> cookiesToObjects = new HashMap<Object, Object>();
359
        private Map<Object,DataObject> cookiesToObjects = new HashMap<Object,DataObject>();
356
    
360
    
357
        @Override
361
        @Override
358
        protected Object instanceForCookie (DataObject obj, InstanceCookie cookie)
362
        protected Object instanceForCookie (DataObject obj, InstanceCookie cookie)
Lines 411-417 Link Here
411
            for (int i = 0; i < cookies.length; i++) {
415
            for (int i = 0; i < cookies.length; i++) {
412
                try {
416
                try {
413
                    Object obj = cookies[i].instanceCreate();
417
                    Object obj = cookies[i].instanceCreate();
414
                    Object file = cookiesToObjects.get(obj);
418
                    DataObject file = cookiesToObjects.get(obj);
415
419
416
                    if (obj instanceof Presenter.Toolbar) {
420
                    if (obj instanceof Presenter.Toolbar) {
417
                        obj = ((Presenter.Toolbar) obj).getToolbarPresenter();
421
                        obj = ((Presenter.Toolbar) obj).getToolbarPresenter();
Lines 447-452 Link Here
447
                        org.openide.awt.Actions.connect(b, a);
451
                        org.openide.awt.Actions.connect(b, a);
448
                        b.putClientProperty("file", file);
452
                        b.putClientProperty("file", file);
449
                        org.openide.awt.Toolbar.this.add(b);
453
                        org.openide.awt.Toolbar.this.add(b);
454
                        setAccelerator(a, file.getPrimaryFile());
450
                        continue;
455
                        continue;
451
                    }
456
                    }
452
                }
457
                }
Lines 479-484 Link Here
479
484
480
    } // end of inner class Folder
485
    } // end of inner class Folder
481
486
487
    static void setAccelerator(Action a, FileObject file) {
488
        if (file == null) {
489
            return;
490
        }
491
        a.putValue("definingFile", file); // cf. o.n.core.NbKeymap.getKeyStrokesForAction
492
        KeyStroke[] keys;
493
        try {
494
            Keymap keymap = Lookup.getDefault().lookup(Keymap.class);
495
            keys = keymap != null ? keymap.getKeyStrokesForAction(a) : new KeyStroke[0];
496
            assert keys != null : keymap;
497
        } finally {
498
            a.putValue("definingFile", null);
499
        }
500
        if (keys.length > 0) {
501
            a.putValue(Action.ACCELERATOR_KEY, keys[0]);
502
        }
503
    }
504
482
    @Override
505
    @Override
483
    public void setUI(javax.swing.plaf.ToolBarUI ui) {
506
    public void setUI(javax.swing.plaf.ToolBarUI ui) {
484
        super.setUI(ui);
507
        super.setUI(ui);

Return to bug 152576