KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > KeyBindingService


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collections JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import org.eclipse.jface.action.IAction;
24 import org.eclipse.ui.IKeyBindingService;
25 import org.eclipse.ui.INestableKeyBindingService;
26 import org.eclipse.ui.IWorkbenchPartSite;
27 import org.eclipse.ui.IWorkbenchSite;
28 import org.eclipse.ui.commands.ActionHandler;
29 import org.eclipse.ui.commands.HandlerSubmission;
30 import org.eclipse.ui.commands.IHandler;
31 import org.eclipse.ui.commands.Priority;
32 import org.eclipse.ui.contexts.EnabledSubmission;
33 import org.eclipse.ui.internal.actions.CommandAction;
34 import org.eclipse.ui.internal.handlers.CommandLegacyActionWrapper;
35
36 /**
37  * This service provides a nestable implementation of a key binding service.
38  * This class is provided for backwards compatibility only, and might be removed
39  * in the future. All of the functionality is the class can be duplicated by
40  * using the commands and contexts API.
41  *
42  * @since 2.0
43  */

44 public final class KeyBindingService implements INestableKeyBindingService {
45
46     /**
47      * The currently active nested service, if any. If there are no nested
48      * services or none of them are active, then this value is <code>null</code>.
49      */

50     private IKeyBindingService activeService = null;
51
52     /**
53      * Whether this key binding service has been disposed. A disposed key
54      * binding service should not be used again.
55      */

56     private boolean disposed;
57
58     /**
59      * The set of context identifiers enabled in this key binding service (not
60      * counting any nested services). This set may be empty, but it is never
61      * <code>null</code>.
62      */

63     private Set JavaDoc enabledContextIds = Collections.EMPTY_SET;
64
65     /**
66      * The list of context submissions indicating the enabled state of the
67      * context. This does not include those from nested services. This list may
68      * be empty, but it is never <code>null</code>.
69      */

70     private List JavaDoc enabledSubmissions = new ArrayList JavaDoc();
71
72     /**
73      * The map of handler submissions, sorted by command identifiers. This does
74      * not include those from nested services. This map may be empty, but it is
75      * never <code>null</code>.
76      */

77     private Map JavaDoc handlerSubmissionsByCommandId = new HashMap JavaDoc();
78
79     /**
80      * The context submissions from the currently active nested service. This
81      * value is <code>null</code> if there is no currently active nested
82      * service.
83      */

84     private List JavaDoc nestedEnabledSubmissions = null;
85
86     /**
87      * The handler submissions from the currently active nested service. This
88      * value is <code>null</code> if there is no currently active handler
89      * service.
90      */

91     private List JavaDoc nestedHandlerSubmissions = null;
92
93     /**
94      * The map of workbench part sites to nested key binding services. This map
95      * may be empty, but is never <code>null</code>.
96      */

97     private final Map JavaDoc nestedServices = new HashMap JavaDoc();
98
99     /**
100      * The parent for this key binding service; <code>null</code> if there is
101      * no parent. If there is a parent, then this means that it should not do a
102      * "live" update of its contexts or handlers, but should make a call to the
103      * parent instead.
104      */

105     private final KeyBindingService parent;
106
107     /**
108      * The site within the workbench at which this service is provided. This
109      * value should not be <code>null</code>.
110      */

111     private IWorkbenchPartSite workbenchPartSite;
112
113     /**
114      * Constructs a new instance of <code>KeyBindingService</code> on a given
115      * workbench site. This instance is not nested.
116      *
117      * @param workbenchPartSite
118      * The site for which this service will be responsible; should
119      * not be <code>null</code>.
120      */

121     public KeyBindingService(IWorkbenchPartSite workbenchPartSite) {
122         this(workbenchPartSite, null);
123     }
124
125     /**
126      * Constructs a new instance of <code>KeyBindingService</code> on a given
127      * workbench site.
128      *
129      * @param workbenchPartSite
130      * The site for which this service will be responsible; should
131      * not be <code>null</code>.
132      * @param parent
133      * The parent key binding service, if any; <code>null</code> if
134      * none.
135      */

136     KeyBindingService(IWorkbenchPartSite workbenchPartSite,
137             KeyBindingService parent) {
138         this.workbenchPartSite = workbenchPartSite;
139         this.parent = parent;
140     }
141
142     /*
143      * (non-Javadoc)
144      *
145      * @see org.eclipse.ui.INestableKeyBindingService#activateKeyBindingService(org.eclipse.ui.IWorkbenchSite)
146      */

147     public boolean activateKeyBindingService(IWorkbenchSite nestedSite) {
148         if (disposed) {
149             return false;
150         }
151
152         // Check if we should do a deactivation.
153
if (nestedSite == null) {
154             // We should do a deactivation, if there is one active.
155
if (activeService == null) {
156                 // There is no active service. Do no work.
157
return false;
158             } else {
159                 // Deactivate the currently active nested service.
160
deactivateNestedService();
161                 return true;
162             }
163         }
164
165         // Attempt to activate a service.
166
final IKeyBindingService service = (IKeyBindingService) nestedServices
167                 .get(nestedSite);
168         if (service == null) {
169             return false;
170         }
171
172         if (service == activeService) {
173             // The service is already active.
174
return false;
175         }
176
177         deactivateNestedService();
178         activateNestedService(service);
179         return true;
180     }
181
182     /**
183      * Activates the given service without worrying about the currently active
184      * service. This goes through the work of adding all of the nested context
185      * ids as enabled submissions.
186      *
187      * @param service
188      * The service to become active; if <code>null</code>, then
189      * the reference to the active service is set to
190      * <code>null</code> but nothing else happens.
191      */

192     private final void activateNestedService(final IKeyBindingService service) {
193         if (disposed) {
194             return;
195         }
196
197         /*
198          * If I have a parent, and I'm the active service, then deactivate so
199          * that I can make changes.
200          */

201         boolean active = false;
202         boolean haveParent = (parent != null);
203         if (haveParent) {
204             active = (parent.activeService == this);
205             if (active) {
206                 parent.deactivateNestedService();
207             }
208         }
209
210         // Update the active service.
211
activeService = service;
212
213         // Check to see that the service isn't null.
214
if (service == null) {
215             return;
216         }
217
218         if (haveParent) {
219             if (active) {
220                 parent.activateNestedService(this);
221             }
222
223         } else if (activeService instanceof KeyBindingService) {
224             // I have no parent, so I can make the changes myself.
225
final KeyBindingService nestedService = (KeyBindingService) activeService;
226
227             // Update the contexts.
228
nestedEnabledSubmissions = nestedService.getEnabledSubmissions();
229             normalizeSites(nestedEnabledSubmissions);
230             Workbench.getInstance().getContextSupport().addEnabledSubmissions(
231                     nestedEnabledSubmissions);
232
233             // Update the handlers.
234
nestedHandlerSubmissions = nestedService.getHandlerSubmissions();
235             normalizeSites(nestedHandlerSubmissions);
236             Workbench.getInstance().getCommandSupport().addHandlerSubmissions(
237                     nestedHandlerSubmissions);
238         }
239     }
240
241     /**
242      * Deactives the currently active service. This nulls out the reference, and
243      * removes all the enabled submissions for the nested service.
244      */

245     private final void deactivateNestedService() {
246         if (disposed) {
247             return;
248         }
249
250         // Don't do anything if there is no active service.
251
if (activeService == null) {
252             return;
253         }
254
255         // Check to see if there is a parent.
256
boolean active = false;
257         if (parent != null) {
258             // Check if I'm the active service.
259
if (parent.activeService == this) {
260                 active = true;
261                 // Deactivate myself so I can make changes.
262
parent.deactivateNestedService();
263             }
264
265         } else if (activeService instanceof KeyBindingService) {
266             // Remove all the nested context ids.
267
Workbench.getInstance().getContextSupport()
268                     .removeEnabledSubmissions(nestedEnabledSubmissions);
269
270             /*
271              * Remove all of the nested handler submissions. The handlers here
272              * weren't created by this instance (but by the nest instance), and
273              * hence can't be disposed here.
274              */

275             Workbench.getInstance().getCommandSupport()
276                     .removeHandlerSubmissions(nestedHandlerSubmissions);
277
278         }
279
280         // Clear our reference to the active service.
281
activeService = null;
282
283         // If necessary, let my parent know that changes have occurred.
284
if (active) {
285             parent.activateNestedService(this);
286         }
287     }
288
289     /**
290      * Disposes this key binding service. This clears out all of the submissions
291      * held by this service, and its nested services.
292      */

293     public void dispose() {
294         if (!disposed) {
295             deactivateNestedService();
296             disposed = true;
297
298             Workbench
299                     .getInstance()
300                     .getContextSupport()
301                     .removeEnabledSubmissions(new ArrayList JavaDoc(enabledSubmissions));
302             enabledSubmissions.clear();
303
304             /*
305              * Each removed handler submission, must dispose its corresponding
306              * handler -- as these handlers only exist inside of this class.
307              */

308             final List JavaDoc submissions = new ArrayList JavaDoc(
309                     handlerSubmissionsByCommandId.values());
310             final Iterator JavaDoc submissionItr = submissions.iterator();
311             while (submissionItr.hasNext()) {
312                 ((HandlerSubmission) submissionItr.next()).getHandler()
313                         .dispose();
314             }
315             Workbench.getInstance().getCommandSupport()
316                     .removeHandlerSubmissions(submissions);
317             handlerSubmissionsByCommandId.clear();
318
319             for (Iterator JavaDoc iterator = nestedServices.values().iterator(); iterator
320                     .hasNext();) {
321                 KeyBindingService keyBindingService = (KeyBindingService) iterator
322                         .next();
323                 keyBindingService.dispose();
324             }
325
326             nestedEnabledSubmissions = null;
327             nestedHandlerSubmissions = null;
328             nestedServices.clear();
329         }
330     }
331
332     /**
333      * Gets a copy of all the enabled submissions in the nesting chain.
334      *
335      * @return All of the nested enabled submissions -- including the ones from
336      * this service. This list may be empty, but is never
337      * <code>null</code>.
338      */

339     private final List JavaDoc getEnabledSubmissions() {
340         if (disposed) {
341             return null;
342         }
343
344         final List JavaDoc submissions = new ArrayList JavaDoc(enabledSubmissions);
345         if (activeService instanceof KeyBindingService) {
346             final KeyBindingService nestedService = (KeyBindingService) activeService;
347             submissions.addAll(nestedService.getEnabledSubmissions());
348         }
349         return submissions;
350     }
351
352     /**
353      * Gets a copy of all the handler submissions in the nesting chain.
354      *
355      * @return All of the nested handler submissions -- including the ones from
356      * this service. This list may be empty, but is never
357      * <code>null</code>.
358      */

359     private final List JavaDoc getHandlerSubmissions() {
360         if (disposed) {
361             return null;
362         }
363
364         final List JavaDoc submissions = new ArrayList JavaDoc(handlerSubmissionsByCommandId
365                 .values());
366         if (activeService instanceof KeyBindingService) {
367             final KeyBindingService nestedService = (KeyBindingService) activeService;
368             submissions.addAll(nestedService.getHandlerSubmissions());
369         }
370         return submissions;
371     }
372
373     /*
374      * (non-Javadoc)
375      *
376      * @see org.eclipse.ui.INestableKeyBindingService#getKeyBindingService(org.eclipse.ui.IWorkbenchSite)
377      */

378     public IKeyBindingService getKeyBindingService(IWorkbenchSite nestedSite) {
379         if (disposed) {
380             return null;
381         }
382
383         if (nestedSite == null) {
384             return null;
385         }
386
387         IKeyBindingService service = (IKeyBindingService) nestedServices
388                 .get(nestedSite);
389         if (service == null) {
390             // TODO the INestedKeyBindingService API should be based on
391
// IWorkbenchPartSite..
392
if (nestedSite instanceof IWorkbenchPartSite) {
393                 service = new KeyBindingService(
394                         (IWorkbenchPartSite) nestedSite, this);
395             } else {
396                 service = new KeyBindingService(null, this);
397             }
398
399             nestedServices.put(nestedSite, service);
400         }
401
402         return service;
403     }
404
405     public String JavaDoc[] getScopes() {
406         if (disposed) {
407             return null;
408         }
409
410         // Get the nested scopes, if any.
411
final String JavaDoc[] nestedScopes;
412         if (activeService == null) {
413             nestedScopes = null;
414         } else {
415             nestedScopes = activeService.getScopes();
416         }
417
418         // Build the list of active scopes
419
final Set JavaDoc activeScopes = new HashSet JavaDoc();
420         activeScopes.addAll(enabledContextIds);
421         if (nestedScopes != null) {
422             for (int i = 0; i < nestedScopes.length; i++) {
423                 activeScopes.add(nestedScopes[i]);
424             }
425         }
426
427         return (String JavaDoc[]) activeScopes.toArray(new String JavaDoc[activeScopes.size()]);
428     }
429
430     /**
431      * Replaces the active workbench site with this service's active workbench
432      * site. This ensures that the context manager will recognize the context as
433      * active. Note: this method modifies the list in place; it is
434      * <em>destructive</em>.
435      *
436      * @param submissionsToModify
437      * The submissions list to modify; must not be <code>null</code>,
438      * but may be empty.
439      */

440     private final void normalizeSites(final List JavaDoc submissionsToModify) {
441         if (disposed) {
442             return;
443         }
444
445         final int size = submissionsToModify.size();
446         for (int i = 0; i < size; i++) {
447             final Object JavaDoc submission = submissionsToModify.get(i);
448             final Object JavaDoc replacementSubmission;
449
450             if (submission instanceof EnabledSubmission) {
451                 final EnabledSubmission enabledSubmission = (EnabledSubmission) submission;
452                 if (!workbenchPartSite.equals(enabledSubmission
453                         .getActiveWorkbenchPartSite())) {
454                     replacementSubmission = new EnabledSubmission(null,
455                             enabledSubmission.getActiveShell(),
456                             workbenchPartSite, enabledSubmission.getContextId());
457                 } else {
458                     replacementSubmission = enabledSubmission;
459                 }
460
461             } else if (submission instanceof HandlerSubmission) {
462                 final HandlerSubmission handlerSubmission = (HandlerSubmission) submission;
463                 if (!workbenchPartSite.equals(handlerSubmission
464                         .getActiveWorkbenchPartSite())) {
465                     replacementSubmission = new HandlerSubmission(null,
466                             handlerSubmission.getActiveShell(),
467                             workbenchPartSite,
468                             handlerSubmission.getCommandId(), handlerSubmission
469                                     .getHandler(), handlerSubmission
470                                     .getPriority());
471                 } else {
472                     replacementSubmission = handlerSubmission;
473                 }
474
475             } else {
476                 replacementSubmission = submission;
477             }
478
479             submissionsToModify.set(i, replacementSubmission);
480         }
481
482     }
483
484     public void registerAction(IAction action) {
485         if (disposed) {
486             return;
487         }
488         
489         if (action instanceof CommandLegacyActionWrapper) {
490             // this is a registration of a fake action for an already
491
// registered handler
492
WorkbenchPlugin
493                     .log("Cannot register a CommandLegacyActionWrapper back into the system"); //$NON-NLS-1$
494
return;
495         }
496         
497         if (action instanceof CommandAction) {
498             // we unfortunately had to allow these out into the wild, but they
499
// still must not feed back into the system
500
return;
501         }
502
503         unregisterAction(action);
504         String JavaDoc commandId = action.getActionDefinitionId();
505         if (commandId != null) {
506             /*
507              * If I have a parent and I'm active, de-activate myself while
508              * making changes.
509              */

510             boolean active = false;
511             if ((parent != null) && (parent.activeService == this)) {
512                 active = true;
513                 parent.deactivateNestedService();
514             }
515
516             // Create the new submission
517
IHandler handler = new ActionHandler(action);
518             HandlerSubmission handlerSubmission = new HandlerSubmission(null,
519                     workbenchPartSite.getShell(), workbenchPartSite, commandId,
520                     handler, Priority.MEDIUM);
521             handlerSubmissionsByCommandId.put(commandId, handlerSubmission);
522
523             // Either submit the new handler myself, or simply re-activate.
524
if (parent != null) {
525                 if (active) {
526                     parent.activateNestedService(this);
527                 }
528             } else {
529                 Workbench.getInstance().getCommandSupport()
530                         .addHandlerSubmission(handlerSubmission);
531             }
532         }
533     }
534
535     /*
536      * (non-Javadoc)
537      *
538      * @see org.eclipse.ui.INestableKeyBindingService#removeKeyBindingService(org.eclipse.ui.IWorkbenchSite)
539      */

540     public boolean removeKeyBindingService(IWorkbenchSite nestedSite) {
541         if (disposed) {
542             return false;
543         }
544
545         final IKeyBindingService service = (IKeyBindingService) nestedServices
546                 .remove(nestedSite);
547         if (service == null) {
548             return false;
549         }
550
551         if (service.equals(activeService)) {
552             deactivateNestedService();
553         }
554
555         return true;
556     }
557
558     public void setScopes(String JavaDoc[] scopes) {
559         if (disposed) {
560             return;
561         }
562
563         // Either deactivate myself, or remove the previous submissions myself.
564
boolean active = false;
565         if ((parent != null) && (parent.activeService == this)) {
566             active = true;
567             parent.deactivateNestedService();
568         } else {
569             Workbench.getInstance().getContextSupport()
570                     .removeEnabledSubmissions(enabledSubmissions);
571         }
572         enabledSubmissions.clear();
573
574         // Determine the new list of submissions.
575
enabledContextIds = new HashSet JavaDoc(Arrays.asList(scopes));
576         for (Iterator JavaDoc iterator = enabledContextIds.iterator(); iterator
577                 .hasNext();) {
578             String JavaDoc contextId = (String JavaDoc) iterator.next();
579             enabledSubmissions.add(new EnabledSubmission(null, null,
580                     workbenchPartSite, contextId));
581         }
582
583         // Submit the new contexts myself, or simply re-active myself.
584
if (parent != null) {
585             if (active) {
586                 parent.activateNestedService(this);
587             }
588         } else {
589             Workbench.getInstance().getContextSupport().addEnabledSubmissions(
590                     enabledSubmissions);
591         }
592     }
593
594     public void unregisterAction(IAction action) {
595         if (disposed) {
596             return;
597         }
598         
599         if (action instanceof CommandLegacyActionWrapper) {
600             // this is a registration of a fake action for an already
601
// registered handler
602
WorkbenchPlugin
603                     .log("Cannot unregister a CommandLegacyActionWrapper out of the system"); //$NON-NLS-1$
604
return;
605         }
606
607         String JavaDoc commandId = action.getActionDefinitionId();
608
609         if (commandId != null) {
610             // Deactivate this service while making changes.
611
boolean active = false;
612             if ((parent != null) && (parent.activeService == this)) {
613                 active = true;
614                 parent.deactivateNestedService();
615             }
616
617             // Remove the current submission, if any.
618
HandlerSubmission handlerSubmission = (HandlerSubmission) handlerSubmissionsByCommandId
619                     .remove(commandId);
620
621             /*
622              * Either activate this service again, or remove the submission
623              * myself.
624              */

625             if (parent != null) {
626                 if (active) {
627                     parent.activateNestedService(this);
628                 }
629             } else {
630                 if (handlerSubmission != null) {
631                     Workbench.getInstance().getCommandSupport()
632                             .removeHandlerSubmission(handlerSubmission);
633                     handlerSubmission.getHandler().dispose();
634                 }
635             }
636         }
637     }
638 }
639
Popular Tags