KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > keys > BindingPersistence


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.keys;
12
13 import java.io.IOException JavaDoc;
14 import java.io.Reader JavaDoc;
15 import java.io.StringReader JavaDoc;
16 import java.io.StringWriter JavaDoc;
17 import java.io.Writer JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import org.eclipse.core.commands.Command;
27 import org.eclipse.core.commands.ParameterizedCommand;
28 import org.eclipse.core.commands.common.HandleObject;
29 import org.eclipse.core.commands.common.NotDefinedException;
30 import org.eclipse.core.commands.util.Tracing;
31 import org.eclipse.core.runtime.IConfigurationElement;
32 import org.eclipse.core.runtime.IExtensionDelta;
33 import org.eclipse.core.runtime.IExtensionRegistry;
34 import org.eclipse.core.runtime.IRegistryChangeEvent;
35 import org.eclipse.core.runtime.Platform;
36 import org.eclipse.jface.bindings.Binding;
37 import org.eclipse.jface.bindings.BindingManager;
38 import org.eclipse.jface.bindings.Scheme;
39 import org.eclipse.jface.bindings.keys.IKeyLookup;
40 import org.eclipse.jface.bindings.keys.KeyBinding;
41 import org.eclipse.jface.bindings.keys.KeyLookupFactory;
42 import org.eclipse.jface.bindings.keys.KeySequence;
43 import org.eclipse.jface.bindings.keys.KeyStroke;
44 import org.eclipse.jface.bindings.keys.ParseException;
45 import org.eclipse.jface.bindings.keys.SWTKeySupport;
46 import org.eclipse.jface.contexts.IContextIds;
47 import org.eclipse.jface.preference.IPreferenceStore;
48 import org.eclipse.jface.util.PropertyChangeEvent;
49 import org.eclipse.swt.SWT;
50 import org.eclipse.ui.IMemento;
51 import org.eclipse.ui.IWorkbenchPreferenceConstants;
52 import org.eclipse.ui.PlatformUI;
53 import org.eclipse.ui.WorkbenchException;
54 import org.eclipse.ui.XMLMemento;
55 import org.eclipse.ui.commands.ICommandService;
56 import org.eclipse.ui.internal.WorkbenchPlugin;
57 import org.eclipse.ui.internal.misc.Policy;
58 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
59 import org.eclipse.ui.internal.services.PreferencePersistence;
60 import org.eclipse.ui.keys.IBindingService;
61
62 /**
63  * <p>
64  * A static class for accessing the registry and the preference store.
65  * </p>
66  *
67  * @since 3.1
68  */

69 final class BindingPersistence extends PreferencePersistence {
70
71     /**
72      * Whether this class should print out debugging information when it reads
73      * in data, or writes to the preference store.
74      */

75     private static final boolean DEBUG = Policy.DEBUG_KEY_BINDINGS;
76
77     /**
78      * The index of the active scheme configuration elements in the indexed
79      * array.
80      *
81      * @see BindingPersistence#read()
82      */

83     private static final int INDEX_ACTIVE_SCHEME = 0;
84
85     /**
86      * The index of the binding definition configuration elements in the indexed
87      * array.
88      *
89      * @see BindingPersistence#read()
90      */

91     private static final int INDEX_BINDING_DEFINITIONS = 1;
92
93     /**
94      * The index of the scheme definition configuration elements in the indexed
95      * array.
96      *
97      * @see BindingPersistence#read(BindingManager, ICommandService)
98      */

99     private static final int INDEX_SCHEME_DEFINITIONS = 2;
100
101     /**
102      * The name of the default scope in 2.1.x.
103      */

104     private static final String JavaDoc LEGACY_DEFAULT_SCOPE = "org.eclipse.ui.globalScope"; //$NON-NLS-1$
105

106     /**
107      * A look-up map for 2.1.x style <code>string</code> keys on a
108      * <code>keyBinding</code> element.
109      */

110     private static final Map JavaDoc r2_1KeysByName = new HashMap JavaDoc();
111
112     static {
113         final IKeyLookup lookup = KeyLookupFactory.getDefault();
114         r2_1KeysByName.put(IKeyLookup.BACKSPACE_NAME, lookup
115                 .formalKeyLookupInteger(IKeyLookup.BACKSPACE_NAME));
116         r2_1KeysByName.put(IKeyLookup.TAB_NAME, lookup
117                 .formalKeyLookupInteger(IKeyLookup.TAB_NAME));
118         r2_1KeysByName.put(IKeyLookup.RETURN_NAME, lookup
119                 .formalKeyLookupInteger(IKeyLookup.RETURN_NAME));
120         r2_1KeysByName.put(IKeyLookup.ENTER_NAME, lookup
121                 .formalKeyLookupInteger(IKeyLookup.ENTER_NAME));
122         r2_1KeysByName.put(IKeyLookup.ESCAPE_NAME, lookup
123                 .formalKeyLookupInteger(IKeyLookup.ESCAPE_NAME));
124         r2_1KeysByName.put(IKeyLookup.ESC_NAME, lookup
125                 .formalKeyLookupInteger(IKeyLookup.ESC_NAME));
126         r2_1KeysByName.put(IKeyLookup.DELETE_NAME, lookup
127                 .formalKeyLookupInteger(IKeyLookup.DELETE_NAME));
128         r2_1KeysByName.put(IKeyLookup.SPACE_NAME, lookup
129                 .formalKeyLookupInteger(IKeyLookup.SPACE_NAME));
130         r2_1KeysByName.put(IKeyLookup.ARROW_UP_NAME, lookup
131                 .formalKeyLookupInteger(IKeyLookup.ARROW_UP_NAME));
132         r2_1KeysByName.put(IKeyLookup.ARROW_DOWN_NAME, lookup
133                 .formalKeyLookupInteger(IKeyLookup.ARROW_DOWN_NAME));
134         r2_1KeysByName.put(IKeyLookup.ARROW_LEFT_NAME, lookup
135                 .formalKeyLookupInteger(IKeyLookup.ARROW_LEFT_NAME));
136         r2_1KeysByName.put(IKeyLookup.ARROW_RIGHT_NAME, lookup
137                 .formalKeyLookupInteger(IKeyLookup.ARROW_RIGHT_NAME));
138         r2_1KeysByName.put(IKeyLookup.PAGE_UP_NAME, lookup
139                 .formalKeyLookupInteger(IKeyLookup.PAGE_UP_NAME));
140         r2_1KeysByName.put(IKeyLookup.PAGE_DOWN_NAME, lookup
141                 .formalKeyLookupInteger(IKeyLookup.PAGE_DOWN_NAME));
142         r2_1KeysByName.put(IKeyLookup.HOME_NAME, lookup
143                 .formalKeyLookupInteger(IKeyLookup.HOME_NAME));
144         r2_1KeysByName.put(IKeyLookup.END_NAME, lookup
145                 .formalKeyLookupInteger(IKeyLookup.END_NAME));
146         r2_1KeysByName.put(IKeyLookup.INSERT_NAME, lookup
147                 .formalKeyLookupInteger(IKeyLookup.INSERT_NAME));
148         r2_1KeysByName.put(IKeyLookup.F1_NAME, lookup
149                 .formalKeyLookupInteger(IKeyLookup.F1_NAME));
150         r2_1KeysByName.put(IKeyLookup.F2_NAME, lookup
151                 .formalKeyLookupInteger(IKeyLookup.F2_NAME));
152         r2_1KeysByName.put(IKeyLookup.F3_NAME, lookup
153                 .formalKeyLookupInteger(IKeyLookup.F3_NAME));
154         r2_1KeysByName.put(IKeyLookup.F4_NAME, lookup
155                 .formalKeyLookupInteger(IKeyLookup.F4_NAME));
156         r2_1KeysByName.put(IKeyLookup.F5_NAME, lookup
157                 .formalKeyLookupInteger(IKeyLookup.F5_NAME));
158         r2_1KeysByName.put(IKeyLookup.F6_NAME, lookup
159                 .formalKeyLookupInteger(IKeyLookup.F6_NAME));
160         r2_1KeysByName.put(IKeyLookup.F7_NAME, lookup
161                 .formalKeyLookupInteger(IKeyLookup.F7_NAME));
162         r2_1KeysByName.put(IKeyLookup.F8_NAME, lookup
163                 .formalKeyLookupInteger(IKeyLookup.F8_NAME));
164         r2_1KeysByName.put(IKeyLookup.F9_NAME, lookup
165                 .formalKeyLookupInteger(IKeyLookup.F9_NAME));
166         r2_1KeysByName.put(IKeyLookup.F10_NAME, lookup
167                 .formalKeyLookupInteger(IKeyLookup.F10_NAME));
168         r2_1KeysByName.put(IKeyLookup.F11_NAME, lookup
169                 .formalKeyLookupInteger(IKeyLookup.F11_NAME));
170         r2_1KeysByName.put(IKeyLookup.F12_NAME, lookup
171                 .formalKeyLookupInteger(IKeyLookup.F12_NAME));
172     }
173
174     /**
175      * Converts a 2.1.x style key sequence (as parsed from the
176      * <code>string</code> attribute of the <code>keyBinding</code>) to a
177      * 3.1 key sequence.
178      *
179      * @param r21KeySequence
180      * The sequence of 2.1.x key strokes that should be converted
181      * into a 3.1 key sequence; never <code>null</code>.
182      * @return A 3.1 key sequence; never <code>null</code>.
183      */

184     private static final KeySequence convert2_1Sequence(int[] r21KeySequence) {
185         final int r21KeySequenceLength = r21KeySequence.length;
186         final KeyStroke[] keyStrokes = new KeyStroke[r21KeySequenceLength];
187         for (int i = 0; i < r21KeySequenceLength; i++) {
188             keyStrokes[i] = convert2_1Stroke(r21KeySequence[i]);
189         }
190
191         return KeySequence.getInstance(keyStrokes);
192     }
193
194     /**
195      * Converts a 2.1.x style key stroke (as parsed from the <code>string</code>
196      * attribute of the <code>keyBinding</code> to a 3.1 key stroke.
197      *
198      * @param r21Stroke
199      * The 2.1.x stroke to convert; must never be <code>null</code>.
200      * @return A 3.1 key stroke; never <code>null</code>.
201      */

202     private static final KeyStroke convert2_1Stroke(final int r21Stroke) {
203         return SWTKeySupport.convertAcceleratorToKeyStroke(r21Stroke);
204     }
205
206     /**
207      * Returns the default scheme identifier for the currently running
208      * application.
209      *
210      * @return The default scheme identifier (<code>String</code>); never
211      * <code>null</code>, but may be empty or point to an undefined
212      * scheme.
213      */

214     static final String JavaDoc getDefaultSchemeId() {
215         final IPreferenceStore store = PlatformUI.getPreferenceStore();
216         return store
217                 .getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
218     }
219
220     /**
221      * Parses a 2.1.x <code>string</code> attribute of the
222      * <code>keyBinding</code> element.
223      *
224      * @param string
225      * The string to parse; must not be <code>null</code>.
226      * @return An array of integer values -- each integer representing a single
227      * key stroke. This array may be empty, but it is never
228      * <code>null</code>.
229      */

230     private static final int[] parse2_1Sequence(final String JavaDoc string) {
231         final StringTokenizer JavaDoc stringTokenizer = new StringTokenizer JavaDoc(string);
232         final int length = stringTokenizer.countTokens();
233         final int[] strokes = new int[length];
234
235         for (int i = 0; i < length; i++) {
236             strokes[i] = parse2_1Stroke(stringTokenizer.nextToken());
237         }
238
239         return strokes;
240     }
241
242     /**
243      * Parses a single 2.1.x key stroke string, as provided by
244      * <code>parse2_1Sequence</code>.
245      *
246      * @param string
247      * The string to parse; must not be <code>null</code>.
248      * @return An single integer value representing this key stroke.
249      */

250     private static final int parse2_1Stroke(final String JavaDoc string) {
251         final StringTokenizer JavaDoc stringTokenizer = new StringTokenizer JavaDoc(string,
252                 KeyStroke.KEY_DELIMITER, true);
253
254         // Copy out the tokens so we have random access.
255
final int size = stringTokenizer.countTokens();
256         final String JavaDoc[] tokens = new String JavaDoc[size];
257         for (int i = 0; stringTokenizer.hasMoreTokens(); i++) {
258             tokens[i] = stringTokenizer.nextToken();
259         }
260
261         int value = 0;
262         if (size % 2 == 1) {
263             String JavaDoc token = tokens[size - 1];
264             final Integer JavaDoc integer = (Integer JavaDoc) r2_1KeysByName.get(token
265                     .toUpperCase());
266
267             if (integer != null) {
268                 value = integer.intValue();
269             } else if (token.length() == 1) {
270                 value = token.toUpperCase().charAt(0);
271             }
272
273             if (value != 0) {
274                 for (int i = 0; i < size - 1; i++) {
275                     token = tokens[i];
276
277                     if (i % 2 == 0) {
278                         if (token.equalsIgnoreCase(IKeyLookup.CTRL_NAME)) {
279                             if ((value & SWT.CTRL) != 0) {
280                                 return 0;
281                             }
282
283                             value |= SWT.CTRL;
284
285                         } else if (token.equalsIgnoreCase(IKeyLookup.ALT_NAME)) {
286                             if ((value & SWT.ALT) != 0) {
287                                 return 0;
288                             }
289
290                             value |= SWT.ALT;
291
292                         } else if (token
293                                 .equalsIgnoreCase(IKeyLookup.SHIFT_NAME)) {
294                             if ((value & SWT.SHIFT) != 0) {
295                                 return 0;
296                             }
297
298                             value |= SWT.SHIFT;
299
300                         } else if (token
301                                 .equalsIgnoreCase(IKeyLookup.COMMAND_NAME)) {
302                             if ((value & SWT.COMMAND) != 0) {
303                                 return 0;
304                             }
305
306                             value |= SWT.COMMAND;
307
308                         } else {
309                             return 0;
310
311                         }
312
313                     } else if (!KeyStroke.KEY_DELIMITER.equals(token)) {
314                         return 0;
315                     }
316                 }
317             }
318         }
319
320         return value;
321     }
322
323     /**
324      * <p>
325      * Reads the registry and the preference store, and determines the
326      * identifier for the scheme that should be active. There is a complicated
327      * order of priorities for this. The registry will only be read if there is
328      * no user preference, and the default active scheme id is different than
329      * the default default active scheme id.
330      * </p>
331      * <ol>
332      * <li>A non-default preference.</li>
333      * <li>The legacy preference XML memento.</li>
334      * <li>A default preference value that is different than the default
335      * default active scheme id.</li>
336      * <li>The registry.</li>
337      * <li>The default default active scheme id.</li>
338      * </ol>
339      *
340      * @param configurationElements
341      * The configuration elements from the commands extension point;
342      * must not be <code>null</code>.
343      * @param configurationElementCount
344      * The number of configuration elements that are really in the
345      * array.
346      * @param preferences
347      * The memento wrapping the commands preference key; may be
348      * <code>null</code>.
349      * @param bindingManager
350      * The binding manager that should be updated with the active
351      * scheme. This binding manager must already have its schemes
352      * defined. This value must not be <code>null</code>.
353      */

354     private static final void readActiveScheme(
355             final IConfigurationElement[] configurationElements,
356             final int configurationElementCount, final IMemento preferences,
357             final BindingManager bindingManager) {
358         // A non-default preference.
359
final IPreferenceStore store = PlatformUI.getPreferenceStore();
360         final String JavaDoc defaultActiveSchemeId = store
361                 .getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
362         final String JavaDoc preferenceActiveSchemeId = store
363                 .getString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
364         if ((preferenceActiveSchemeId != null)
365                 && (!preferenceActiveSchemeId.equals(defaultActiveSchemeId))) {
366             try {
367                 bindingManager.setActiveScheme(bindingManager
368                         .getScheme(preferenceActiveSchemeId));
369                 return;
370             } catch (final NotDefinedException e) {
371                 // Let's keep looking....
372
}
373         }
374
375         // A legacy preference XML memento.
376
if (preferences != null) {
377             final IMemento[] preferenceMementos = preferences
378                     .getChildren(TAG_ACTIVE_KEY_CONFIGURATION);
379             int preferenceMementoCount = preferenceMementos.length;
380             for (int i = preferenceMementoCount - 1; i >= 0; i--) {
381                 final IMemento memento = preferenceMementos[i];
382                 String JavaDoc id = memento.getString(ATT_KEY_CONFIGURATION_ID);
383                 if (id != null) {
384                     try {
385                         bindingManager.setActiveScheme(bindingManager
386                                 .getScheme(id));
387                         return;
388                     } catch (final NotDefinedException e) {
389                         // Let's keep looking....
390
}
391                 }
392             }
393         }
394
395         // A default preference value that is different than the default.
396
if ((defaultActiveSchemeId != null && defaultActiveSchemeId.length() > 0)
397                 && (!defaultActiveSchemeId
398                         .equals(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID))) {
399             try {
400                 bindingManager.setActiveScheme(bindingManager
401                         .getScheme(defaultActiveSchemeId));
402                 return;
403             } catch (final NotDefinedException e) {
404                 // Let's keep looking....
405
}
406         }
407
408         // The registry.
409
for (int i = configurationElementCount - 1; i >= 0; i--) {
410             final IConfigurationElement configurationElement = configurationElements[i];
411
412             String JavaDoc id = configurationElement
413                     .getAttribute(ATT_KEY_CONFIGURATION_ID);
414             if (id != null) {
415                 try {
416                     bindingManager
417                             .setActiveScheme(bindingManager.getScheme(id));
418                     return;
419                 } catch (final NotDefinedException e) {
420                     // Let's keep looking....
421
}
422             }
423
424             id = configurationElement.getAttribute(ATT_VALUE);
425             if (id != null) {
426                 try {
427                     bindingManager
428                             .setActiveScheme(bindingManager.getScheme(id));
429                     return;
430                 } catch (final NotDefinedException e) {
431                     // Let's keep looking....
432
}
433             }
434         }
435
436         // The default default active scheme id.
437
try {
438             bindingManager
439                     .setActiveScheme(bindingManager
440                             .getScheme(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID));
441         } catch (final NotDefinedException e) {
442             //this is bad - the default default scheme should always exist
443
throw new Error JavaDoc(
444                     "The default default active scheme id is not defined."); //$NON-NLS-1$
445
}
446     }
447
448     /**
449      * Reads all of the binding definitions from the preferences.
450      *
451      * @param preferences
452      * The memento for the commands preferences key.
453      * @param bindingManager
454      * The binding manager to which the bindings should be added;
455      * must not be <code>null</code>.
456      * @param commandService
457      * The command service for the workbench; must not be
458      * <code>null</code>.
459      */

460     private static final void readBindingsFromPreferences(
461             final IMemento preferences, final BindingManager bindingManager,
462             final ICommandService commandService) {
463         List JavaDoc warningsToLog = new ArrayList JavaDoc(1);
464
465         if (preferences != null) {
466             final IMemento[] preferenceMementos = preferences
467                     .getChildren(TAG_KEY_BINDING);
468             int preferenceMementoCount = preferenceMementos.length;
469             for (int i = preferenceMementoCount - 1; i >= 0; i--) {
470                 final IMemento memento = preferenceMementos[i];
471
472                 // Read out the command id.
473
String JavaDoc commandId = readOptional(memento, ATT_COMMAND_ID);
474                 if (commandId == null) {
475                     commandId = readOptional(memento, ATT_COMMAND);
476                 }
477                 final Command command;
478                 if (commandId != null) {
479                     command = commandService.getCommand(commandId);
480                 } else {
481                     command = null;
482                 }
483
484                 // Read out the scheme id.
485
String JavaDoc schemeId = readOptional(memento,
486                         ATT_KEY_CONFIGURATION_ID);
487                 if (schemeId == null) {
488                     schemeId = readRequired(memento, ATT_CONFIGURATION,
489                             warningsToLog,
490                             "Key bindings need a scheme or key configuration"); //$NON-NLS-1$
491
if (schemeId == null) {
492                         continue;
493                     }
494                 }
495
496                 // Read out the context id.
497
String JavaDoc contextId = readOptional(memento, ATT_CONTEXT_ID);
498                 if (contextId == null) {
499                     contextId = readOptional(memento, ATT_SCOPE);
500                 }
501                 if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
502                     contextId = null;
503                 }
504                 if (contextId == null) {
505                     contextId = IContextIds.CONTEXT_ID_WINDOW;
506                 }
507
508                 // Read out the key sequence.
509
String JavaDoc keySequenceText = readOptional(memento, ATT_KEY_SEQUENCE);
510                 KeySequence keySequence = null;
511                 if (keySequenceText == null) {
512                     keySequenceText = readRequired(memento, ATT_STRING,
513                             warningsToLog,
514                             "Key bindings need a key sequence or string"); //$NON-NLS-1$
515
if (keySequenceText == null) {
516                         continue;
517                     }
518
519                     // The key sequence is in the old-style format.
520
keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText));
521
522                 } else {
523                     // The key sequence is in the new-style format.
524
try {
525                         keySequence = KeySequence.getInstance(keySequenceText);
526                     } catch (final ParseException e) {
527                         addWarning(warningsToLog, "Could not parse", null, //$NON-NLS-1$
528
commandId, "keySequence", keySequenceText); //$NON-NLS-1$
529
continue;
530                     }
531                     if (keySequence.isEmpty() || !keySequence.isComplete()) {
532                         addWarning(
533                                 warningsToLog,
534                                 "Key bindings cannot use an empty or incomplete key sequence", //$NON-NLS-1$
535
null, commandId, "keySequence", keySequence //$NON-NLS-1$
536
.toString());
537                         continue;
538                     }
539
540                 }
541
542                 // Read out the locale and platform.
543
final String JavaDoc locale = readOptional(memento, ATT_LOCALE);
544                 final String JavaDoc platform = readOptional(memento, ATT_PLATFORM);
545
546                 // Read out the parameters
547
final ParameterizedCommand parameterizedCommand;
548                 if (command == null) {
549                     parameterizedCommand = null;
550                 } else {
551                     parameterizedCommand = readParameters(memento,
552                             warningsToLog, command);
553                 }
554
555                 final Binding binding = new KeyBinding(keySequence,
556                         parameterizedCommand, schemeId, contextId, locale,
557                         platform, null, Binding.USER);
558                 bindingManager.addBinding(binding);
559             }
560         }
561
562         // If there were any warnings, then log them now.
563
logWarnings(warningsToLog,
564                 "Warnings while parsing the key bindings from the preference store"); //$NON-NLS-1$
565
}
566
567     /**
568      * Reads all of the binding definitions from the commands extension point.
569      *
570      * @param configurationElements
571      * The configuration elements in the commands extension point;
572      * must not be <code>null</code>, but may be empty.
573      * @param configurationElementCount
574      * The number of configuration elements that are really in the
575      * array.
576      * @param bindingManager
577      * The binding manager to which the bindings should be added;
578      * must not be <code>null</code>.
579      * @param commandService
580      * The command service for the workbench; must not be
581      * <code>null</code>.
582      */

583     private static final void readBindingsFromRegistry(
584             final IConfigurationElement[] configurationElements,
585             final int configurationElementCount,
586             final BindingManager bindingManager,
587             final ICommandService commandService) {
588         final Collection JavaDoc bindings = new ArrayList JavaDoc(configurationElementCount);
589         final List JavaDoc warningsToLog = new ArrayList JavaDoc(1);
590
591         for (int i = 0; i < configurationElementCount; i++) {
592             final IConfigurationElement configurationElement = configurationElements[i];
593
594             /*
595              * Read out the command id. Doing this before determining if the key
596              * binding is actually valid is a bit wasteful. However, it is
597              * helpful to have the command identifier when logging syntax
598              * errors.
599              */

600             String JavaDoc commandId = configurationElement
601                     .getAttribute(ATT_COMMAND_ID);
602             if ((commandId == null) || (commandId.length() == 0)) {
603                 commandId = configurationElement.getAttribute(ATT_COMMAND);
604             }
605             if ((commandId != null) && (commandId.length() == 0)) {
606                 commandId = null;
607             }
608             final Command command;
609             if (commandId != null) {
610                 command = commandService.getCommand(commandId);
611                 if (!command.isDefined()) {
612                     // Reference to an undefined command. This is invalid.
613
addWarning(warningsToLog,
614                             "Cannot bind to an undefined command", //$NON-NLS-1$
615
configurationElement, commandId);
616                     continue;
617                 }
618             } else {
619                 command = null;
620             }
621
622             // Read out the scheme id.
623
String JavaDoc schemeId = configurationElement.getAttribute(ATT_SCHEME_ID);
624             if ((schemeId == null) || (schemeId.length() == 0)) {
625                 schemeId = configurationElement
626                         .getAttribute(ATT_KEY_CONFIGURATION_ID);
627                 if ((schemeId == null) || (schemeId.length() == 0)) {
628                     schemeId = configurationElement
629                             .getAttribute(ATT_CONFIGURATION);
630                     if ((schemeId == null) || (schemeId.length() == 0)) {
631                         // The scheme id should never be null. This is invalid.
632
addWarning(warningsToLog, "Key bindings need a scheme", //$NON-NLS-1$
633
configurationElement, commandId);
634                         continue;
635                     }
636                 }
637             }
638
639             // Read out the context id.
640
String JavaDoc contextId = configurationElement
641                     .getAttribute(ATT_CONTEXT_ID);
642             if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
643                 contextId = null;
644             } else if ((contextId == null) || (contextId.length() == 0)) {
645                 contextId = configurationElement.getAttribute(ATT_SCOPE);
646                 if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
647                     contextId = null;
648                 }
649             }
650             if ((contextId == null) || (contextId.length() == 0)) {
651                 contextId = IContextIds.CONTEXT_ID_WINDOW;
652             }
653
654             // Read out the key sequence.
655
KeySequence keySequence = null;
656             String JavaDoc keySequenceText = configurationElement
657                     .getAttribute(ATT_SEQUENCE);
658             if ((keySequenceText == null) || (keySequenceText.length() == 0)) {
659                 keySequenceText = configurationElement
660                         .getAttribute(ATT_KEY_SEQUENCE);
661             }
662             if ((keySequenceText == null) || (keySequenceText.length() == 0)) {
663                 keySequenceText = configurationElement.getAttribute(ATT_STRING);
664                 if ((keySequenceText == null)
665                         || (keySequenceText.length() == 0)) {
666                     // The key sequence should never be null. This is pointless
667
addWarning(
668                             warningsToLog,
669                             "Defining a key binding with no key sequence has no effect", //$NON-NLS-1$
670
configurationElement, commandId);
671                     continue;
672                 }
673
674                 // The key sequence is in the old-style format.
675
try {
676                     keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText));
677                 } catch (final IllegalArgumentException JavaDoc e) {
678                     addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$
679
configurationElement, commandId, "keySequence", //$NON-NLS-1$
680
keySequenceText);
681                     continue;
682                 }
683
684             } else {
685                 // The key sequence is in the new-style format.
686
try {
687                     keySequence = KeySequence.getInstance(keySequenceText);
688                 } catch (final ParseException e) {
689                     addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$
690
configurationElement, commandId, "keySequence", //$NON-NLS-1$
691
keySequenceText);
692                     continue;
693                 }
694                 if (keySequence.isEmpty() || !keySequence.isComplete()) {
695                     addWarning(
696                             warningsToLog,
697                             "Key bindings should not have an empty or incomplete key sequence", //$NON-NLS-1$
698
configurationElement, commandId, "keySequence", //$NON-NLS-1$
699
keySequence.toString());
700                     continue;
701                 }
702
703             }
704
705             // Read out the locale and platform.
706
String JavaDoc locale = configurationElement.getAttribute(ATT_LOCALE);
707             if ((locale != null) && (locale.length() == 0)) {
708                 locale = null;
709             }
710             String JavaDoc platform = configurationElement.getAttribute(ATT_PLATFORM);
711             if ((platform != null) && (platform.length() == 0)) {
712                 platform = null;
713             }
714
715             // Read out the parameters, if any.
716
final ParameterizedCommand parameterizedCommand;
717             if (command == null) {
718                 parameterizedCommand = null;
719             } else {
720                 parameterizedCommand = readParameters(configurationElement,
721                         warningsToLog, command);
722             }
723
724             final Binding binding = new KeyBinding(keySequence,
725                     parameterizedCommand, schemeId, contextId, locale,
726                     platform, null, Binding.SYSTEM);
727             bindings.add(binding);
728         }
729
730         final Binding[] bindingArray = (Binding[]) bindings
731                 .toArray(new Binding[bindings.size()]);
732         bindingManager.setBindings(bindingArray);
733
734         logWarnings(
735                 warningsToLog,
736                 "Warnings while parsing the key bindings from the 'org.eclipse.ui.commands' extension point"); //$NON-NLS-1$
737
}
738
739     /**
740      * Reads all of the scheme definitions from the registry.
741      *
742      * @param configurationElements
743      * The configuration elements in the commands extension point;
744      * must not be <code>null</code>, but may be empty.
745      * @param configurationElementCount
746      * The number of configuration elements that are really in the
747      * array.
748      * @param bindingManager
749      * The binding manager to which the schemes should be added; must
750      * not be <code>null</code>.
751      */

752     private static final void readSchemesFromRegistry(
753             final IConfigurationElement[] configurationElements,
754             final int configurationElementCount,
755             final BindingManager bindingManager) {
756         // Undefine all the previous handle objects.
757
final HandleObject[] handleObjects = bindingManager.getDefinedSchemes();
758         if (handleObjects != null) {
759             for (int i = 0; i < handleObjects.length; i++) {
760                 handleObjects[i].undefine();
761             }
762         }
763
764         final List JavaDoc warningsToLog = new ArrayList JavaDoc(1);
765
766         for (int i = 0; i < configurationElementCount; i++) {
767             final IConfigurationElement configurationElement = configurationElements[i];
768
769             // Read out the attributes.
770
final String JavaDoc id = readRequired(configurationElement, ATT_ID,
771                     warningsToLog, "Schemes need an id"); //$NON-NLS-1$
772
if (id == null) {
773                 continue;
774             }
775             final String JavaDoc name = readRequired(configurationElement, ATT_NAME,
776                     warningsToLog, "A scheme needs a name", id); //$NON-NLS-1$
777
if (name == null) {
778                 continue;
779             }
780             final String JavaDoc description = readOptional(configurationElement,
781                     ATT_DESCRIPTION);
782
783             String JavaDoc parentId = configurationElement.getAttribute(ATT_PARENT_ID);
784             if ((parentId != null) && (parentId.length() == 0)) {
785                 parentId = configurationElement.getAttribute(ATT_PARENT);
786                 if ((parentId != null) && (parentId.length() == 0)) {
787                     parentId = null;
788                 }
789             }
790
791             // Define the scheme.
792
final Scheme scheme = bindingManager.getScheme(id);
793             scheme.define(name, description, parentId);
794         }
795
796         logWarnings(
797                 warningsToLog,
798                 "Warnings while parsing the key bindings from the 'org.eclipse.ui.bindings', 'org.eclipse.ui.acceleratorConfigurations' and 'org.eclipse.ui.commands' extension point"); //$NON-NLS-1$
799
}
800
801     /**
802      * Writes the given active scheme and bindings to the preference store. Only
803      * bindings that are of the <code>Binding.USER</code> type will be
804      * written; the others will be ignored.
805      *
806      * @param activeScheme
807      * The scheme which should be persisted; may be <code>null</code>.
808      * @param bindings
809      * The bindings which should be persisted; may be
810      * <code>null</code>
811      * @throws IOException
812      * If something happens while trying to write to the workbench
813      * preference store.
814      */

815     static final void write(final Scheme activeScheme, final Binding[] bindings)
816             throws IOException JavaDoc {
817         // Print out debugging information, if requested.
818
if (DEBUG) {
819             Tracing.printTrace("BINDINGS", "Persisting active scheme '" //$NON-NLS-1$ //$NON-NLS-2$
820
+ activeScheme.getId() + '\'');
821             Tracing.printTrace("BINDINGS", "Persisting bindings"); //$NON-NLS-1$ //$NON-NLS-2$
822
}
823
824         // Write the simple preference key to the UI preference store.
825
writeActiveScheme(activeScheme);
826
827         // Build the XML block for writing the bindings and active scheme.
828
final XMLMemento xmlMemento = XMLMemento
829                 .createWriteRoot(EXTENSION_COMMANDS);
830         if (activeScheme != null) {
831             writeActiveSchemeToPreferences(xmlMemento, activeScheme);
832         }
833         if (bindings != null) {
834             final int bindingsLength = bindings.length;
835             for (int i = 0; i < bindingsLength; i++) {
836                 final Binding binding = bindings[i];
837                 if (binding.getType() == Binding.USER) {
838                     writeBindingToPreferences(xmlMemento, binding);
839                 }
840             }
841         }
842
843         // Write the XML block to the workbench preference store.
844
final IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault()
845                 .getPreferenceStore();
846         final Writer JavaDoc writer = new StringWriter JavaDoc();
847         try {
848             xmlMemento.save(writer);
849             preferenceStore.setValue(EXTENSION_COMMANDS, writer.toString());
850         } finally {
851             writer.close();
852         }
853     }
854
855     /**
856      * Writes the active scheme to its own preference key. This key is used by
857      * RCP applications as part of their plug-in customization.
858      *
859      * @param scheme
860      * The scheme to write to the preference store. If the scheme is
861      * <code>null</code>, then it is removed.
862      */

863     private static final void writeActiveScheme(final Scheme scheme) {
864         final IPreferenceStore store = PlatformUI.getPreferenceStore();
865         final String JavaDoc schemeId = (scheme == null) ? null : scheme.getId();
866         final String JavaDoc defaultSchemeId = store
867                 .getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
868         if ((defaultSchemeId == null) ? (scheme != null) : (!defaultSchemeId
869                 .equals(schemeId))) {
870             store.setValue(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID,
871                     scheme.getId());
872         } else {
873             store
874                     .setToDefault(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
875         }
876     }
877
878     /**
879      * Writes the active scheme to the memento. If the scheme is
880      * <code>null</code>, then all schemes in the memento are removed.
881      *
882      * @param memento
883      * The memento to which the scheme should be written; must not be
884      * <code>null</code>.
885      * @param scheme
886      * The scheme that should be written; must not be
887      * <code>null</code>.
888      */

889     private static final void writeActiveSchemeToPreferences(
890             final IMemento memento, final Scheme scheme) {
891         // Add this active scheme, if it is not the default.
892
final IPreferenceStore store = PlatformUI.getPreferenceStore();
893         final String JavaDoc schemeId = scheme.getId();
894         final String JavaDoc defaultSchemeId = store
895                 .getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
896         if ((defaultSchemeId == null) ? (schemeId != null) : (!defaultSchemeId
897                 .equals(schemeId))) {
898             final IMemento child = memento
899                     .createChild(TAG_ACTIVE_KEY_CONFIGURATION);
900             child.putString(ATT_KEY_CONFIGURATION_ID, schemeId);
901         }
902     }
903
904     /**
905      * Writes the binding to the memento. This creates a new child element on
906      * the memento, and places the properties of the binding as its attributes.
907      *
908      * @param parent
909      * The parent memento for the binding element; must not be
910      * <code>null</code>.
911      * @param binding
912      * The binding to write; must not be <code>null</code>.
913      */

914     private static final void writeBindingToPreferences(final IMemento parent,
915             final Binding binding) {
916         final IMemento element = parent.createChild(TAG_KEY_BINDING);
917         element.putString(ATT_CONTEXT_ID, binding.getContextId());
918         final ParameterizedCommand parameterizedCommand = binding
919                 .getParameterizedCommand();
920         final String JavaDoc commandId = (parameterizedCommand == null) ? null
921                 : parameterizedCommand.getId();
922         element.putString(ATT_COMMAND_ID, commandId);
923         element.putString(ATT_KEY_CONFIGURATION_ID, binding.getSchemeId());
924         element.putString(ATT_KEY_SEQUENCE, binding.getTriggerSequence()
925                 .toString());
926         element.putString(ATT_LOCALE, binding.getLocale());
927         element.putString(ATT_PLATFORM, binding.getPlatform());
928         if (parameterizedCommand != null) {
929             final Map JavaDoc parameterizations = parameterizedCommand
930                     .getParameterMap();
931             final Iterator JavaDoc parameterizationItr = parameterizations.entrySet()
932                     .iterator();
933             while (parameterizationItr.hasNext()) {
934                 final Map.Entry JavaDoc entry = (Map.Entry JavaDoc) parameterizationItr.next();
935                 final String JavaDoc id = (String JavaDoc) entry.getKey();
936                 final String JavaDoc value = (String JavaDoc) entry.getValue();
937                 final IMemento parameterElement = element
938                         .createChild(TAG_PARAMETER);
939                 parameterElement.putString(ATT_ID, id);
940                 parameterElement.putString(ATT_VALUE, value);
941             }
942         }
943     }
944
945     /**
946      * The binding manager which should be populated with the values from the
947      * registry and preference store; must not be <code>null</code>.
948      */

949     private final BindingManager bindingManager;
950
951     /**
952      * The command service for the workbench; must not be <code>null</code>.
953      */

954     private final ICommandService commandService;
955
956     /**
957      * Constructs a new instance of <code>BindingPersistence</code>.
958      *
959      * @param bindingManager
960      * The binding manager which should be populated with the values
961      * from the registry and preference store; must not be
962      * <code>null</code>.
963      * @param commandService
964      * The command service for the workbench; must not be
965      * <code>null</code>.
966      */

967     BindingPersistence(final BindingManager bindingManager,
968             final ICommandService commandService) {
969         this.bindingManager = bindingManager;
970         this.commandService = commandService;
971     }
972
973     protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
974         final IExtensionDelta[] acceleratorConfigurationDeltas = event
975                 .getExtensionDeltas(
976                         PlatformUI.PLUGIN_ID,
977                         IWorkbenchRegistryConstants.PL_ACCELERATOR_CONFIGURATIONS);
978         if (acceleratorConfigurationDeltas.length == 0) {
979             final IExtensionDelta[] bindingDeltas = event.getExtensionDeltas(
980                     PlatformUI.PLUGIN_ID,
981                     IWorkbenchRegistryConstants.PL_BINDINGS);
982             if (bindingDeltas.length == 0) {
983                 final IExtensionDelta[] commandDeltas = event
984                         .getExtensionDeltas(PlatformUI.PLUGIN_ID,
985                                 IWorkbenchRegistryConstants.PL_COMMANDS);
986                 if (commandDeltas.length == 0) {
987                     final IExtensionDelta[] acceleratorScopeDeltas = event
988                             .getExtensionDeltas(
989                                     PlatformUI.PLUGIN_ID,
990                                     IWorkbenchRegistryConstants.PL_ACCELERATOR_SCOPES);
991                     if (acceleratorScopeDeltas.length == 0) {
992                         final IExtensionDelta[] contextDeltas = event
993                                 .getExtensionDeltas(PlatformUI.PLUGIN_ID,
994                                         IWorkbenchRegistryConstants.PL_CONTEXTS);
995                         if (contextDeltas.length == 0) {
996                             final IExtensionDelta[] actionDefinitionDeltas = event
997                                     .getExtensionDeltas(
998                                             PlatformUI.PLUGIN_ID,
999                                             IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
1000                            if (actionDefinitionDeltas.length == 0) {
1001                                return false;
1002                            }
1003                        }
1004                    }
1005                }
1006            }
1007        }
1008
1009        return true;
1010    }
1011
1012    protected final boolean isChangeImportant(final PropertyChangeEvent event) {
1013        return EXTENSION_COMMANDS.equals(event.getProperty());
1014    }
1015
1016    /**
1017     * Reads all of the binding information from the registry and from the
1018     * preference store.
1019     */

1020    protected final void read() {
1021        super.read();
1022
1023        // Create the extension registry mementos.
1024
final IExtensionRegistry registry = Platform.getExtensionRegistry();
1025        int activeSchemeElementCount = 0;
1026        int bindingDefinitionCount = 0;
1027        int schemeDefinitionCount = 0;
1028        final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][];
1029
1030        // Sort the bindings extension point based on element name.
1031
final IConfigurationElement[] bindingsExtensionPoint = registry
1032                .getConfigurationElementsFor(EXTENSION_BINDINGS);
1033        for (int i = 0; i < bindingsExtensionPoint.length; i++) {
1034            final IConfigurationElement configurationElement = bindingsExtensionPoint[i];
1035            final String JavaDoc name = configurationElement.getName();
1036
1037            // Check if it is a binding definition.
1038
if (TAG_KEY.equals(name)) {
1039                addElementToIndexedArray(configurationElement,
1040                        indexedConfigurationElements,
1041                        INDEX_BINDING_DEFINITIONS, bindingDefinitionCount++);
1042            } else
1043            // Check to see if it is a scheme definition.
1044
if (TAG_SCHEME.equals(name)) {
1045                addElementToIndexedArray(configurationElement,
1046                        indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
1047                        schemeDefinitionCount++);
1048            }
1049
1050        }
1051
1052        // Sort the commands extension point based on element name.
1053
final IConfigurationElement[] commandsExtensionPoint = registry
1054                .getConfigurationElementsFor(EXTENSION_COMMANDS);
1055        for (int i = 0; i < commandsExtensionPoint.length; i++) {
1056            final IConfigurationElement configurationElement = commandsExtensionPoint[i];
1057            final String JavaDoc name = configurationElement.getName();
1058
1059            // Check if it is a binding definition.
1060
if (TAG_KEY_BINDING.equals(name)) {
1061                addElementToIndexedArray(configurationElement,
1062                        indexedConfigurationElements,
1063                        INDEX_BINDING_DEFINITIONS, bindingDefinitionCount++);
1064
1065                // Check if it is a scheme defintion.
1066
} else if (TAG_KEY_CONFIGURATION.equals(name)) {
1067                addElementToIndexedArray(configurationElement,
1068                        indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
1069                        schemeDefinitionCount++);
1070
1071                // Check if it is an active scheme identifier.
1072
} else if (TAG_ACTIVE_KEY_CONFIGURATION.equals(name)) {
1073                addElementToIndexedArray(configurationElement,
1074                        indexedConfigurationElements, INDEX_ACTIVE_SCHEME,
1075                        activeSchemeElementCount++);
1076            }
1077        }
1078
1079        /*
1080         * Sort the accelerator configuration extension point into the scheme
1081         * definitions.
1082         */

1083        final IConfigurationElement[] acceleratorConfigurationsExtensionPoint = registry
1084                .getConfigurationElementsFor(EXTENSION_ACCELERATOR_CONFIGURATIONS);
1085        for (int i = 0; i < acceleratorConfigurationsExtensionPoint.length; i++) {
1086            final IConfigurationElement configurationElement = acceleratorConfigurationsExtensionPoint[i];
1087            final String JavaDoc name = configurationElement.getName();
1088
1089            // Check if the name matches the accelerator configuration element
1090
if (TAG_ACCELERATOR_CONFIGURATION.equals(name)) {
1091                addElementToIndexedArray(configurationElement,
1092                        indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
1093                        schemeDefinitionCount++);
1094            }
1095        }
1096
1097        // Create the preference memento.
1098
final IPreferenceStore store = WorkbenchPlugin.getDefault()
1099                .getPreferenceStore();
1100        final String JavaDoc preferenceString = store.getString(EXTENSION_COMMANDS);
1101        IMemento preferenceMemento = null;
1102        if ((preferenceString != null) && (preferenceString.length() > 0)) {
1103            final Reader JavaDoc reader = new StringReader JavaDoc(preferenceString);
1104            try {
1105                preferenceMemento = XMLMemento.createReadRoot(reader);
1106            } catch (final WorkbenchException e) {
1107                // Could not initialize the preference memento.
1108
}
1109        }
1110
1111        // Read the scheme definitions.
1112
readSchemesFromRegistry(
1113                indexedConfigurationElements[INDEX_SCHEME_DEFINITIONS],
1114                schemeDefinitionCount, bindingManager);
1115        readActiveScheme(indexedConfigurationElements[INDEX_ACTIVE_SCHEME],
1116                activeSchemeElementCount, preferenceMemento, bindingManager);
1117        readBindingsFromRegistry(
1118                indexedConfigurationElements[INDEX_BINDING_DEFINITIONS],
1119                bindingDefinitionCount, bindingManager, commandService);
1120        readBindingsFromPreferences(preferenceMemento, bindingManager,
1121                commandService);
1122    }
1123}
1124
Popular Tags