1 11 12 package org.eclipse.ui.internal.contexts; 13 14 import java.util.ArrayList ; 15 import java.util.Collection ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.Set ; 22 import java.util.WeakHashMap ; 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 47 public final class ContextAuthority extends ExpressionAuthority { 48 public static final String DEFER_EVENTS = "org.eclipse.ui.internal.contexts.deferEvents"; public static final String SEND_EVENTS = "org.eclipse.ui.internal.contexts.sendEvents"; 51 52 56 private static final int ACTIVATIONS_TO_RECOMPUTE_SIZE = 4; 57 58 62 private static final boolean DEBUG = Policy.DEBUG_CONTEXTS; 63 64 68 private static final boolean DEBUG_PERFORMANCE = Policy.DEBUG_CONTEXTS_PERFORMANCE; 69 70 73 private static final String DISPOSE_LISTENER = "org.eclipse.ui.internal.contexts.ContextAuthority"; 75 78 private static final String TRACING_COMPONENT = "CONTEXTS"; 80 86 private final Set [] activationsBySourcePriority = new Set [33]; 87 88 96 private final Map contextActivationsByContextId = new HashMap (); 97 98 102 private final ContextManager contextManager; 103 104 108 private final IContextService contextService; 109 110 120 private final Map registeredWindows = new WeakHashMap (); 121 122 133 ContextAuthority(final ContextManager contextManager, 134 final IContextService contextService) { 135 if (contextManager == null) { 136 throw new NullPointerException ( 137 "The context authority needs a context manager"); } 139 if (contextService == null) { 140 throw new NullPointerException ( 141 "The context authority needs an evaluation context"); } 143 144 this.contextManager = contextManager; 145 this.contextService = contextService; 146 } 147 148 154 final void activateContext(final IContextActivation activation) { 155 final String contextId = activation.getContextId(); 157 if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) { 158 contextManager.addActiveContext(contextId); 159 return; 160 } 161 final Object value = contextActivationsByContextId.get(contextId); 162 if (value instanceof Collection ) { 163 final Collection contextActivations = (Collection ) 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 contextActivations = new ArrayList (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 final int sourcePriority = activation.getSourcePriority(); 184 for (int i = 1; i <= 32; i++) { 185 if ((sourcePriority & (1 << i)) != 0) { 186 Set activations = activationsBySourcePriority[i]; 187 if (activations == null) { 188 activations = new HashSet (1); 189 activationsBySourcePriority[i] = activations; 190 } 191 activations.add(activation); 192 } 193 } 194 } 195 196 210 private final void checkWindowType(final Shell newShell, 211 final Shell oldShell) { 212 216 Collection oldActivations = (Collection ) registeredWindows 217 .get(oldShell); 218 if (oldActivations == null) { 219 223 oldActivations = (Collection ) registeredWindows.get(null); 224 if (oldActivations != null) { 225 final Iterator oldActivationItr = oldActivations.iterator(); 226 while (oldActivationItr.hasNext()) { 227 final IContextActivation activation = (IContextActivation) oldActivationItr 228 .next(); 229 deactivateContext(activation); 230 } 231 } 232 } 233 234 239 if ((newShell != null) && (!newShell.isDisposed())) { 240 final Collection newActivations; 241 242 if ((newShell.getParent() != null) 243 && (registeredWindows.get(newShell) == null)) { 244 newActivations = new ArrayList (); 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 265 newShell.addDisposeListener(new DisposeListener() { 266 267 272 public void widgetDisposed(DisposeEvent e) { 273 registeredWindows.remove(null); 274 if (!newShell.isDisposed()) { 275 newShell.removeDisposeListener(this); 276 } 277 278 286 final Iterator newActivationItr = newActivations 287 .iterator(); 288 while (newActivationItr.hasNext()) { 289 deactivateContext((IContextActivation) newActivationItr 290 .next()); 291 } 292 } 293 }); 294 295 } else { 296 newActivations = null; 298 299 } 300 } 301 } 302 303 313 private final boolean containsActive(final Collection activations) { 314 final Iterator 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 333 final void deactivateContext(final IContextActivation activation) { 334 final String contextId = activation.getContextId(); 336 if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) { 337 return; 338 } 339 final Object value = contextActivationsByContextId.get(contextId); 340 if (value instanceof Collection ) { 341 final Collection contextActivations = (Collection ) 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 final int sourcePriority = activation.getSourcePriority(); 368 for (int i = 1; i <= 32; i++) { 369 if ((sourcePriority & (1 << i)) != 0) { 370 final Set 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 387 final Shell getActiveShell() { 388 return (Shell) getVariable(ISources.ACTIVE_SHELL_NAME); 389 } 390 391 402 public final int getShellType(final Shell shell) { 403 if (shell == null) { 405 return IContextService.TYPE_NONE; 406 } 407 408 final Collection activations = (Collection ) registeredWindows 409 .get(shell); 410 if (activations != null) { 411 if (activations.isEmpty()) { 413 return IContextService.TYPE_NONE; 415 } 416 417 final Iterator activationItr = activations.iterator(); 419 while (activationItr.hasNext()) { 420 final IContextActivation activation = (IContextActivation) activationItr 421 .next(); 422 final String 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 Assert 432 .isTrue( 433 false, 434 "A registered shell should have at least one submission matching TYPE_WINDOW or TYPE_DIALOG"); return IContextService.TYPE_NONE; 437 } else if (shell.getParent() != null) { 438 442 return IContextService.TYPE_DIALOG; 443 444 } else { 445 449 return IContextService.TYPE_NONE; 450 } 451 } 452 453 485 public final boolean registerShell(final Shell shell, final int type) { 486 if (shell == null) { 488 throw new NullPointerException ("The shell was null"); } 490 491 if (DEBUG) { 493 final StringBuffer buffer = new StringBuffer ("register shell '"); buffer.append(shell); 495 buffer.append("' as "); switch (type) { 497 case IContextService.TYPE_DIALOG: 498 buffer.append("dialog"); break; 500 case IContextService.TYPE_WINDOW: 501 buffer.append("window"); break; 503 case IContextService.TYPE_NONE: 504 buffer.append("none"); break; 506 default: 507 buffer.append("unknown"); break; 509 } 510 Tracing.printTrace(TRACING_COMPONENT, buffer.toString()); 511 } 512 513 final List activations = new ArrayList (); 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 ("The type is not recognized: " + type); 549 } 550 551 boolean returnValue = false; 553 final Collection previousActivations = (Collection ) registeredWindows 554 .get(shell); 555 if (previousActivations != null) { 556 returnValue = true; 557 final Iterator previousActivationItr = previousActivations 558 .iterator(); 559 while (previousActivationItr.hasNext()) { 560 final IContextActivation activation = (IContextActivation) previousActivationItr 561 .next(); 562 deactivateContext(activation); 563 } 564 } 565 566 registeredWindows.put(shell, activations); 568 569 573 final DisposeListener shellDisposeListener = new DisposeListener() { 574 575 580 public void widgetDisposed(DisposeEvent e) { 581 registeredWindows.remove(shell); 582 if (!shell.isDisposed()) { 583 shell.removeDisposeListener(this); 584 } 585 586 593 final Iterator activationItr = activations.iterator(); 594 while (activationItr.hasNext()) { 595 deactivateContext((IContextActivation) activationItr.next()); 596 } 597 } 598 }; 599 600 shell.addDisposeListener(shellDisposeListener); 602 shell.setData(DISPOSE_LISTENER, shellDisposeListener); 603 604 return returnValue; 605 } 606 607 615 protected final void sourceChanged(final int sourcePriority) { 616 long startTime = 0L; 618 if (DEBUG_PERFORMANCE) { 619 startTime = System.currentTimeMillis(); 620 } 621 622 628 final Set activationsToRecompute = new HashSet ( 629 ACTIVATIONS_TO_RECOMPUTE_SIZE); 630 for (int i = 1; i <= 32; i++) { 631 if ((sourcePriority & (1 << i)) != 0) { 632 final Collection activations = activationsBySourcePriority[i]; 633 if (activations != null) { 634 final Iterator activationItr = activations.iterator(); 635 while (activationItr.hasNext()) { 636 activationsToRecompute.add(activationItr.next()); 637 } 638 } 639 } 640 } 641 642 647 final Collection changedContextIds = new ArrayList ( 648 activationsToRecompute.size()); 649 final Iterator 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 667 final Iterator changedContextIdItr = changedContextIds.iterator(); 668 while (changedContextIdItr.hasNext()) { 669 final String contextId = (String ) changedContextIdItr.next(); 670 final Object 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 ) { 676 updateContext(contextId, containsActive((Collection ) value)); 677 } else { 678 updateContext(contextId, false); 679 } 680 } 681 } finally { 682 contextManager.addActiveContext(SEND_EVENTS); 683 } 684 685 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"); } 693 } 694 } 695 696 715 public final boolean unregisterShell(final Shell shell) { 716 if (shell == null) { 718 return false; 719 } 720 721 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 previousActivations = (Collection ) registeredWindows 735 .get(shell); 736 if (previousActivations != null) { 737 registeredWindows.remove(shell); 738 739 final Iterator 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 762 private final void updateContext(final String contextId, 763 final boolean active) { 764 if (active) { 765 contextManager.addActiveContext(contextId); 766 } else { 767 contextManager.removeActiveContext(contextId); 768 } 769 } 770 771 785 protected final void updateEvaluationContext(final String name, 786 final Object value) { 787 792 if ((name != null) 793 && (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME.equals(name))) { 794 799 if (ISources.ACTIVE_SHELL_NAME.equals(name)) { 800 checkWindowType((Shell) value, 801 (Shell) getVariable(ISources.ACTIVE_SHELL_NAME)); 802 } 803 804 changeVariable(name, value); 806 } 807 } 808 809 819 final void updateShellKludge() { 820 updateCurrentState(); 821 sourceChanged(ISources.ACTIVE_SHELL); 822 } 823 } 824 | Popular Tags |