KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > contexts > ContextAuthority


1 /*******************************************************************************
2  * Copyright (c) 2005, 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
12 package org.eclipse.ui.internal.contexts;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection 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 import java.util.WeakHashMap JavaDoc;
23
24 import org.eclipse.core.commands.contexts.ContextManager;
25 import org.eclipse.core.commands.util.Tracing;
26 import org.eclipse.core.expressions.Expression;
27 import org.eclipse.core.runtime.Assert;
28 import org.eclipse.swt.events.DisposeEvent;
29 import org.eclipse.swt.events.DisposeListener;
30 import org.eclipse.swt.widgets.Shell;
31 import org.eclipse.ui.ActiveShellExpression;
32 import org.eclipse.ui.ISources;
33 import org.eclipse.ui.contexts.IContextActivation;
34 import org.eclipse.ui.contexts.IContextService;
35 import org.eclipse.ui.internal.misc.Policy;
36 import org.eclipse.ui.internal.services.ExpressionAuthority;
37
38 /**
39  * <p>
40  * A central authority for deciding activation of contexts. This authority
41  * listens to a variety of incoming sources, and updates the underlying context
42  * manager if changes occur.
43  * </p>
44  *
45  * @since 3.1
46  */

47 public final class ContextAuthority extends ExpressionAuthority {
48     public static final String JavaDoc DEFER_EVENTS = "org.eclipse.ui.internal.contexts.deferEvents"; //$NON-NLS-1$
49
public static final String JavaDoc SEND_EVENTS = "org.eclipse.ui.internal.contexts.sendEvents"; //$NON-NLS-1$
50

51
52     /**
53      * The default size of the set containing the activations to recompute. This
54      * is more than enough to cover the average case.
55      */

56     private static final int ACTIVATIONS_TO_RECOMPUTE_SIZE = 4;
57
58     /**
59      * Whether the context authority should kick into debugging mode. This
60      * causes the unresolvable handler conflicts to be printed to the console.
61      */

62     private static final boolean DEBUG = Policy.DEBUG_CONTEXTS;
63
64     /**
65      * Whether the performance information should be printed about the
66      * performance of the context authority.
67      */

68     private static final boolean DEBUG_PERFORMANCE = Policy.DEBUG_CONTEXTS_PERFORMANCE;
69
70     /**
71      * The name of the data tag containing the dispose listener information.
72      */

73     private static final String JavaDoc DISPOSE_LISTENER = "org.eclipse.ui.internal.contexts.ContextAuthority"; //$NON-NLS-1$
74

75     /**
76      * The component name to print when displaying tracing information.
77      */

78     private static final String JavaDoc TRACING_COMPONENT = "CONTEXTS"; //$NON-NLS-1$
79

80     /**
81      * A bucket sort of the context activations based on source priority. Each
82      * activation will appear only once per set, but may appear in multiple
83      * sets. If no activations are defined for a particular priority level, then
84      * the array at that index will only contain <code>null</code>.
85      */

86     private final Set JavaDoc[] activationsBySourcePriority = new Set JavaDoc[33];
87
88     /**
89      * This is a map of context activations (<code>Collection</code> of
90      * <code>IContextActivation</code>) sorted by context identifier (<code>String</code>).
91      * If there is only one context activation for a context, then the
92      * <code>Collection</code> is replaced by a
93      * <code>IContextActivation</code>. If there is no activation, the entry
94      * should be removed entirely.
95      */

96     private final Map JavaDoc contextActivationsByContextId = new HashMap JavaDoc();
97
98     /**
99      * The context manager that should be updated when the contexts are
100      * changing.
101      */

102     private final ContextManager contextManager;
103
104     /**
105      * The context service that should be used for authority-managed
106      * shell-related contexts. This value is never <code>null</code>.
107      */

108     private final IContextService contextService;
109
110     /**
111      * This is a map of shell to a list of activations. When a shell is
112      * registered, it is added to this map with the list of activation that
113      * should be submitted when the shell is active. When the shell is
114      * deactivated, this same list should be withdrawn. A shell is removed from
115      * this map using the {@link #unregisterShell(Shell)}method. This value may
116      * be empty, but is never <code>null</code>. The <code>null</code> key
117      * is reserved for active shells that have not been registered but have a
118      * parent (i.e., default dialog service).
119      */

120     private final Map JavaDoc registeredWindows = new WeakHashMap JavaDoc();
121
122     /**
123      * Constructs a new instance of <code>ContextAuthority</code>.
124      *
125      * @param contextManager
126      * The context manager from which contexts can be retrieved (to
127      * update their active state); must not be <code>null</code>.
128      * @param contextService
129      * The workbench context service for which this authority is
130      * acting. This allows the authority to manage shell-specific
131      * contexts. This value must not be <code>null</code>.
132      */

133     ContextAuthority(final ContextManager contextManager,
134             final IContextService contextService) {
135         if (contextManager == null) {
136             throw new NullPointerException JavaDoc(
137                     "The context authority needs a context manager"); //$NON-NLS-1$
138
}
139         if (contextService == null) {
140             throw new NullPointerException JavaDoc(
141                     "The context authority needs an evaluation context"); //$NON-NLS-1$
142
}
143
144         this.contextManager = contextManager;
145         this.contextService = contextService;
146     }
147
148     /**
149      * Activates a context on the workbench. This will add it to a master list.
150      *
151      * @param activation
152      * The activation; must not be <code>null</code>.
153      */

154     final void activateContext(final IContextActivation activation) {
155         // First we update the contextActivationsByContextId map.
156
final String JavaDoc contextId = activation.getContextId();
157         if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) {
158             contextManager.addActiveContext(contextId);
159             return;
160         }
161         final Object JavaDoc value = contextActivationsByContextId.get(contextId);
162         if (value instanceof Collection JavaDoc) {
163             final Collection JavaDoc contextActivations = (Collection JavaDoc) value;
164             if (!contextActivations.contains(activation)) {
165                 contextActivations.add(activation);
166                 updateContext(contextId, containsActive(contextActivations));
167             }
168         } else if (value instanceof IContextActivation) {
169             if (value != activation) {
170                 final Collection JavaDoc contextActivations = new ArrayList JavaDoc(2);
171                 contextActivations.add(value);
172                 contextActivations.add(activation);
173                 contextActivationsByContextId
174                         .put(contextId, contextActivations);
175                 updateContext(contextId, containsActive(contextActivations));
176             }
177         } else {
178             contextActivationsByContextId.put(contextId, activation);
179             updateContext(contextId, evaluate(activation));
180         }
181
182         // Next we update the source priority bucket sort of activations.
183
final int sourcePriority = activation.getSourcePriority();
184         for (int i = 1; i <= 32; i++) {
185             if ((sourcePriority & (1 << i)) != 0) {
186                 Set JavaDoc activations = activationsBySourcePriority[i];
187                 if (activations == null) {
188                     activations = new HashSet JavaDoc(1);
189                     activationsBySourcePriority[i] = activations;
190                 }
191                 activations.add(activation);
192             }
193         }
194     }
195
196     /**
197      * Checks whether the new active shell is registered. If it is already
198      * registered, then it does no work. If it is not registered, then it checks
199      * what type of contexts the shell should have by default. This is
200      * determined by parenting. A shell with no parent receives no contexts. A
201      * shell with a parent, receives the dialog contexts.
202      *
203      * @param newShell
204      * The newly active shell; may be <code>null</code> or
205      * disposed.
206      * @param oldShell
207      * The previously active shell; may be <code>null</code> or
208      * disposed.
209      */

210     private final void checkWindowType(final Shell newShell,
211             final Shell oldShell) {
212         /*
213          * If the previous active shell was recognized as a dialog by default,
214          * then remove its submissions.
215          */

216         Collection JavaDoc oldActivations = (Collection JavaDoc) registeredWindows
217                 .get(oldShell);
218         if (oldActivations == null) {
219             /*
220              * The old shell wasn't registered. So, we need to check if it was
221              * considered a dialog by default.
222              */

223             oldActivations = (Collection JavaDoc) registeredWindows.get(null);
224             if (oldActivations != null) {
225                 final Iterator JavaDoc oldActivationItr = oldActivations.iterator();
226                 while (oldActivationItr.hasNext()) {
227                     final IContextActivation activation = (IContextActivation) oldActivationItr
228                             .next();
229                     deactivateContext(activation);
230                 }
231             }
232         }
233
234         /*
235          * If the new active shell is recognized as a dialog by default, then
236          * create some submissions, remember them, and submit them for
237          * processing.
238          */

239         if ((newShell != null) && (!newShell.isDisposed())) {
240             final Collection JavaDoc newActivations;
241
242             if ((newShell.getParent() != null)
243                     && (registeredWindows.get(newShell) == null)) {
244                 // This is a dialog by default.
245
newActivations = new ArrayList JavaDoc();
246                 final Expression expression = new ActiveShellExpression(
247                         newShell);
248                 final IContextActivation dialogWindowActivation = new ContextActivation(
249                         IContextService.CONTEXT_ID_DIALOG_AND_WINDOW,
250                         expression, contextService);
251                 activateContext(dialogWindowActivation);
252                 newActivations.add(dialogWindowActivation);
253                 final IContextActivation dialogActivation = new ContextActivation(
254                         IContextService.CONTEXT_ID_DIALOG, expression,
255                         contextService);
256                 activateContext(dialogActivation);
257                 newActivations.add(dialogActivation);
258                 registeredWindows.put(null, newActivations);
259
260                 /*
261                  * Make sure the submissions will be removed in event of
262                  * disposal. This is really just a paranoid check. The
263                  * "oldSubmissions" code above should take care of this.
264                  */

265                 newShell.addDisposeListener(new DisposeListener() {
266
267                     /*
268                      * (non-Javadoc)
269                      *
270                      * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
271                      */

272                     public void widgetDisposed(DisposeEvent e) {
273                         registeredWindows.remove(null);
274                         if (!newShell.isDisposed()) {
275                             newShell.removeDisposeListener(this);
276                         }
277
278                         /*
279                          * In the case where a dispose has happened, we are
280                          * expecting an activation event to arrive at some point
281                          * in the future. If we process the submissions now,
282                          * then we will update the activeShell before
283                          * checkWindowType is called. This means that dialogs
284                          * won't be recognized as dialogs.
285                          */

286                         final Iterator JavaDoc newActivationItr = newActivations
287                                 .iterator();
288                         while (newActivationItr.hasNext()) {
289                             deactivateContext((IContextActivation) newActivationItr
290                                     .next());
291                         }
292                     }
293                 });
294
295             } else {
296                 // Shells that are not dialogs by default must register.
297
newActivations = null;
298
299             }
300         }
301     }
302
303     /**
304      * Returns a subset of the given <code>activations</code> containing only
305      * those that are active
306      *
307      * @param activations
308      * The activations to trim; must not be <code>null</code>, but
309      * may be empty.
310      * @return <code>true</code> if there is at least one active context;
311      * <code>false</code> otherwise.
312      */

313     private final boolean containsActive(final Collection JavaDoc activations) {
314         final Iterator JavaDoc activationItr = activations.iterator();
315         while (activationItr.hasNext()) {
316             final IContextActivation activation = (IContextActivation) activationItr
317                     .next();
318             if (evaluate(activation)) {
319                 return true;
320             }
321         }
322
323         return false;
324     }
325
326     /**
327      * Removes an activation for a context on the workbench. This will remove it
328      * from the master list, and update the appropriate context, if necessary.
329      *
330      * @param activation
331      * The activation; must not be <code>null</code>.
332      */

333     final void deactivateContext(final IContextActivation activation) {
334         // First we update the handlerActivationsByCommandId map.
335
final String JavaDoc contextId = activation.getContextId();
336         if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) {
337             return;
338         }
339         final Object JavaDoc value = contextActivationsByContextId.get(contextId);
340         if (value instanceof Collection JavaDoc) {
341             final Collection JavaDoc contextActivations = (Collection JavaDoc) value;
342             if (contextActivations.contains(activation)) {
343                 contextActivations.remove(activation);
344                 if (contextActivations.isEmpty()) {
345                     contextActivationsByContextId.remove(contextId);
346                     updateContext(contextId, false);
347
348                 } else if (contextActivations.size() == 1) {
349                     final IContextActivation remainingActivation = (IContextActivation) contextActivations
350                             .iterator().next();
351                     contextActivationsByContextId.put(contextId,
352                             remainingActivation);
353                     updateContext(contextId, evaluate(remainingActivation));
354
355                 } else {
356                     updateContext(contextId, containsActive(contextActivations));
357                 }
358             }
359         } else if (value instanceof IContextActivation) {
360             if (value == activation) {
361                 contextActivationsByContextId.remove(contextId);
362                 updateContext(contextId, false);
363             }
364         }
365
366         // Next we update the source priority bucket sort of activations.
367
final int sourcePriority = activation.getSourcePriority();
368         for (int i = 1; i <= 32; i++) {
369             if ((sourcePriority & (1 << i)) != 0) {
370                 final Set JavaDoc activations = activationsBySourcePriority[i];
371                 if (activations == null) {
372                     continue;
373                 }
374                 activations.remove(activation);
375                 if (activations.isEmpty()) {
376                     activationsBySourcePriority[i] = null;
377                 }
378             }
379         }
380     }
381
382     /**
383      * Returns the currently active shell.
384      *
385      * @return The currently active shell; may be <code>null</code>.
386      */

387     final Shell getActiveShell() {
388         return (Shell) getVariable(ISources.ACTIVE_SHELL_NAME);
389     }
390
391     /**
392      * Returns the shell type for the given shell.
393      *
394      * @param shell
395      * The shell for which the type should be determined. If this
396      * value is <code>null</code>, then
397      * <code>IWorkbenchContextSupport.TYPE_NONE</code> is returned.
398      * @return <code>IWorkbenchContextSupport.TYPE_WINDOW</code>,
399      * <code>IWorkbenchContextSupport.TYPE_DIALOG</code>, or
400      * <code>IWorkbenchContextSupport.TYPE_NONE</code>.
401      */

402     public final int getShellType(final Shell shell) {
403         // If the shell is null, then return none.
404
if (shell == null) {
405             return IContextService.TYPE_NONE;
406         }
407
408         final Collection JavaDoc activations = (Collection JavaDoc) registeredWindows
409                 .get(shell);
410         if (activations != null) {
411             // The shell is registered, so check what type it was registered as.
412
if (activations.isEmpty()) {
413                 // It was registered as none.
414
return IContextService.TYPE_NONE;
415             }
416
417             // Look for the right type of context id.
418
final Iterator JavaDoc activationItr = activations.iterator();
419             while (activationItr.hasNext()) {
420                 final IContextActivation activation = (IContextActivation) activationItr
421                         .next();
422                 final String JavaDoc contextId = activation.getContextId();
423                 if (contextId == IContextService.CONTEXT_ID_DIALOG) {
424                     return IContextService.TYPE_DIALOG;
425                 } else if (contextId == IContextService.CONTEXT_ID_WINDOW) {
426                     return IContextService.TYPE_WINDOW;
427                 }
428             }
429
430             // This shouldn't be possible.
431
Assert
432                     .isTrue(
433                             false,
434                             "A registered shell should have at least one submission matching TYPE_WINDOW or TYPE_DIALOG"); //$NON-NLS-1$
435
return IContextService.TYPE_NONE; // not reachable
436

437         } else if (shell.getParent() != null) {
438             /*
439              * The shell is not registered, but it has a parent. It is therefore
440              * considered a dialog by default.
441              */

442             return IContextService.TYPE_DIALOG;
443
444         } else {
445             /*
446              * The shell is not registered, but has no parent. It gets no key
447              * bindings.
448              */

449             return IContextService.TYPE_NONE;
450         }
451     }
452
453     /**
454      * <p>
455      * Registers a shell to automatically promote or demote some basic types of
456      * contexts. The "In Dialogs" and "In Windows" contexts are provided by the
457      * system. This a convenience method to ensure that these contexts are
458      * promoted when the given is shell is active.
459      * </p>
460      * <p>
461      * If a shell is registered as a window, then the "In Windows" context is
462      * enabled when that shell is active. If a shell is registered as a dialog --
463      * or is not registered, but has a parent shell -- then the "In Dialogs"
464      * context is enabled when that shell is active. If the shell is registered
465      * as none -- or is not registered, but has no parent shell -- then the
466      * neither of the contexts will be enabled (by us -- someone else can always
467      * enabled them).
468      * </p>
469      * <p>
470      * If the provided shell has already been registered, then this method will
471      * change the registration.
472      * </p>
473      *
474      * @param shell
475      * The shell to register for key bindings; must not be
476      * <code>null</code>.
477      * @param type
478      * The type of shell being registered. This value must be one of
479      * the constants given in this interface.
480      *
481      * @return <code>true</code> if the shell had already been registered
482      * (i.e., the registration has changed); <code>false</code>
483      * otherwise.
484      */

485     public final boolean registerShell(final Shell shell, final int type) {
486         // We do not allow null shell registration. It is reserved.
487
if (shell == null) {
488             throw new NullPointerException JavaDoc("The shell was null"); //$NON-NLS-1$
489
}
490
491         // Debugging output
492
if (DEBUG) {
493             final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("register shell '"); //$NON-NLS-1$
494
buffer.append(shell);
495             buffer.append("' as "); //$NON-NLS-1$
496
switch (type) {
497             case IContextService.TYPE_DIALOG:
498                 buffer.append("dialog"); //$NON-NLS-1$
499
break;
500             case IContextService.TYPE_WINDOW:
501                 buffer.append("window"); //$NON-NLS-1$
502
break;
503             case IContextService.TYPE_NONE:
504                 buffer.append("none"); //$NON-NLS-1$
505
break;
506             default:
507                 buffer.append("unknown"); //$NON-NLS-1$
508
break;
509             }
510             Tracing.printTrace(TRACING_COMPONENT, buffer.toString());
511         }
512
513         // Build the list of submissions.
514
final List JavaDoc activations = new ArrayList JavaDoc();
515         Expression expression;
516         IContextActivation dialogWindowActivation;
517         switch (type) {
518         case IContextService.TYPE_DIALOG:
519             expression = new ActiveShellExpression(shell);
520             dialogWindowActivation = new ContextActivation(
521                     IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
522                     contextService);
523             activateContext(dialogWindowActivation);
524             activations.add(dialogWindowActivation);
525             final IContextActivation dialogActivation = new ContextActivation(
526                     IContextService.CONTEXT_ID_DIALOG, expression,
527                     contextService);
528             activateContext(dialogActivation);
529             activations.add(dialogActivation);
530             break;
531         case IContextService.TYPE_NONE:
532             break;
533         case IContextService.TYPE_WINDOW:
534             expression = new ActiveShellExpression(shell);
535             dialogWindowActivation = new ContextActivation(
536                     IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
537                     contextService);
538             activateContext(dialogWindowActivation);
539             activations.add(dialogWindowActivation);
540             final IContextActivation windowActivation = new ContextActivation(
541                     IContextService.CONTEXT_ID_WINDOW, expression,
542                     contextService);
543             activateContext(windowActivation);
544             activations.add(windowActivation);
545             break;
546         default:
547             throw new IllegalArgumentException JavaDoc("The type is not recognized: " //$NON-NLS-1$
548
+ type);
549         }
550
551         // Check to see if the activations are already present.
552
boolean returnValue = false;
553         final Collection JavaDoc previousActivations = (Collection JavaDoc) registeredWindows
554                 .get(shell);
555         if (previousActivations != null) {
556             returnValue = true;
557             final Iterator JavaDoc previousActivationItr = previousActivations
558                     .iterator();
559             while (previousActivationItr.hasNext()) {
560                 final IContextActivation activation = (IContextActivation) previousActivationItr
561                         .next();
562                 deactivateContext(activation);
563             }
564         }
565
566         // Add the new submissions, and force some reprocessing to occur.
567
registeredWindows.put(shell, activations);
568
569         /*
570          * Remember the dispose listener so that we can remove it later if we
571          * unregister the shell.
572          */

573         final DisposeListener shellDisposeListener = new DisposeListener() {
574
575             /*
576              * (non-Javadoc)
577              *
578              * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
579              */

580             public void widgetDisposed(DisposeEvent e) {
581                 registeredWindows.remove(shell);
582                 if (!shell.isDisposed()) {
583                     shell.removeDisposeListener(this);
584                 }
585
586                 /*
587                  * In the case where a dispose has happened, we are expecting an
588                  * activation event to arrive at some point in the future. If we
589                  * process the submissions now, then we will update the
590                  * activeShell before checkWindowType is called. This means that
591                  * dialogs won't be recognized as dialogs.
592                  */

593                 final Iterator JavaDoc activationItr = activations.iterator();
594                 while (activationItr.hasNext()) {
595                     deactivateContext((IContextActivation) activationItr.next());
596                 }
597             }
598         };
599
600         // Make sure the submissions will be removed in event of disposal.
601
shell.addDisposeListener(shellDisposeListener);
602         shell.setData(DISPOSE_LISTENER, shellDisposeListener);
603
604         return returnValue;
605     }
606
607     /**
608      * Carries out the actual source change notification. It assumed that by the
609      * time this method is called, <code>context</code> is up-to-date with the
610      * current state of the application.
611      *
612      * @param sourcePriority
613      * A bit mask of all the source priorities that have changed.
614      */

615     protected final void sourceChanged(final int sourcePriority) {
616         // If tracing, then track how long it takes to process the activations.
617
long startTime = 0L;
618         if (DEBUG_PERFORMANCE) {
619             startTime = System.currentTimeMillis();
620         }
621
622         /*
623          * In this first phase, we cycle through all of the activations that
624          * could have potentially changed. Each such activation is added to a
625          * set for future processing. We add it to a set so that we avoid
626          * handling any individual activation more than once.
627          */

628         final Set JavaDoc activationsToRecompute = new HashSet JavaDoc(
629                 ACTIVATIONS_TO_RECOMPUTE_SIZE);
630         for (int i = 1; i <= 32; i++) {
631             if ((sourcePriority & (1 << i)) != 0) {
632                 final Collection JavaDoc activations = activationsBySourcePriority[i];
633                 if (activations != null) {
634                     final Iterator JavaDoc activationItr = activations.iterator();
635                     while (activationItr.hasNext()) {
636                         activationsToRecompute.add(activationItr.next());
637                     }
638                 }
639             }
640         }
641
642         /*
643          * For every activation, we recompute its active state, and check
644          * whether it has changed. If it has changed, then we take note of the
645          * context identifier so we can update the context later.
646          */

647         final Collection JavaDoc changedContextIds = new ArrayList JavaDoc(
648                 activationsToRecompute.size());
649         final Iterator JavaDoc activationItr = activationsToRecompute.iterator();
650         while (activationItr.hasNext()) {
651             final IContextActivation activation = (IContextActivation) activationItr
652                     .next();
653             final boolean currentActive = evaluate(activation);
654             activation.clearResult();
655             final boolean newActive = evaluate(activation);
656             if (newActive != currentActive) {
657                 changedContextIds.add(activation.getContextId());
658             }
659         }
660
661         try {
662             contextManager.addActiveContext(DEFER_EVENTS);
663             /*
664              * For every context identifier with a changed activation, we
665              * resolve conflicts and trigger an update.
666              */

667             final Iterator JavaDoc changedContextIdItr = changedContextIds.iterator();
668             while (changedContextIdItr.hasNext()) {
669                 final String JavaDoc contextId = (String JavaDoc) changedContextIdItr.next();
670                 final Object JavaDoc value = contextActivationsByContextId
671                         .get(contextId);
672                 if (value instanceof IContextActivation) {
673                     final IContextActivation activation = (IContextActivation) value;
674                     updateContext(contextId, evaluate(activation));
675                 } else if (value instanceof Collection JavaDoc) {
676                     updateContext(contextId, containsActive((Collection JavaDoc) value));
677                 } else {
678                     updateContext(contextId, false);
679                 }
680             }
681         } finally {
682             contextManager.addActiveContext(SEND_EVENTS);
683         }
684
685         // If tracing performance, then print the results.
686
if (DEBUG_PERFORMANCE) {
687             final long elapsedTime = System.currentTimeMillis() - startTime;
688             final int size = activationsToRecompute.size();
689             if (size > 0) {
690                 Tracing.printTrace(TRACING_COMPONENT, size
691                         + " activations recomputed in " + elapsedTime + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
692
}
693         }
694     }
695
696     /**
697      * <p>
698      * Unregisters a shell that was previously registered. After this method
699      * completes, the shell will be treated as if it had never been registered
700      * at all. If you have registered a shell, you should ensure that this
701      * method is called when the shell is disposed. Otherwise, a potential
702      * memory leak will exist.
703      * </p>
704      * <p>
705      * If the shell was never registered, or if the shell is <code>null</code>,
706      * then this method returns <code>false</code> and does nothing.
707      *
708      * @param shell
709      * The shell to be unregistered; does nothing if this value is
710      * <code>null</code>.
711      *
712      * @return <code>true</code> if the shell had been registered;
713      * <code>false</code> otherwise.
714      */

715     public final boolean unregisterShell(final Shell shell) {
716         // Don't allow this method to play with the special null slot.
717
if (shell == null) {
718             return false;
719         }
720
721         /*
722          * If we're unregistering the shell but we're not about to dispose it,
723          * then we'll end up leaking the DisposeListener unless we remove it
724          * here.
725          */

726         if (!shell.isDisposed()) {
727             final DisposeListener oldListener = (DisposeListener) shell
728                     .getData(DISPOSE_LISTENER);
729             if (oldListener != null) {
730                 shell.removeDisposeListener(oldListener);
731             }
732         }
733
734         Collection JavaDoc previousActivations = (Collection JavaDoc) registeredWindows
735                 .get(shell);
736         if (previousActivations != null) {
737             registeredWindows.remove(shell);
738
739             final Iterator JavaDoc previousActivationItr = previousActivations
740                     .iterator();
741             while (previousActivationItr.hasNext()) {
742                 final IContextActivation activation = (IContextActivation) previousActivationItr
743                         .next();
744                 deactivateContext(activation);
745             }
746             return true;
747         }
748
749         return false;
750     }
751
752     /**
753      * Updates the context with the given context activation.
754      *
755      * @param contextId
756      * The identifier of the context which should be updated; must
757      * not be <code>null</code>.
758      * @param active
759      * Whether the context should be active; <code>false</code>
760      * otherwise.
761      */

762     private final void updateContext(final String JavaDoc contextId,
763             final boolean active) {
764         if (active) {
765             contextManager.addActiveContext(contextId);
766         } else {
767             contextManager.removeActiveContext(contextId);
768         }
769     }
770
771     /**
772      * Updates this authority's evaluation context. If the changed variable is
773      * the <code>ISources.ACTIVE_SHELL_NAME</code> variable, then this also
774      * triggers an update of the shell-specific contexts. For example, if a
775      * dialog becomes active, then the dialog context will be activated by this
776      * method.
777      *
778      * @param name
779      * The name of the variable to update; must not be
780      * <code>null</code>.
781      * @param value
782      * The new value of the variable. If this value is
783      * <code>null</code>, then the variable is removed.
784      */

785     protected final void updateEvaluationContext(final String JavaDoc name,
786             final Object JavaDoc value) {
787         /*
788          * Bug 84056. If we update the active workbench window, then we risk
789          * falling back to that shell when the active shell has registered as
790          * "none".
791          */

792         if ((name != null)
793                 && (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME.equals(name))) {
794             /*
795              * We need to track shell activation ourselves, as some special
796              * contexts are automatically activated in response to different
797              * types of shells becoming active.
798              */

799             if (ISources.ACTIVE_SHELL_NAME.equals(name)) {
800                 checkWindowType((Shell) value,
801                         (Shell) getVariable(ISources.ACTIVE_SHELL_NAME));
802             }
803
804             // Update the evaluation context itself.
805
changeVariable(name, value);
806         }
807     }
808
809     /**
810      * <p>
811      * Bug 95792. A mechanism by which the key binding architecture can force an
812      * update of the contexts (based on the active shell) before trying to
813      * execute a command. This mechanism is required for GTK+ only.
814      * </p>
815      * <p>
816      * DO NOT CALL THIS METHOD.
817      * </p>
818      */

819     final void updateShellKludge() {
820         updateCurrentState();
821         sourceChanged(ISources.ACTIVE_SHELL);
822     }
823 }
824
Popular Tags