1 11 12 package org.eclipse.ui.internal.handlers; 13 14 import java.io.BufferedWriter ; 15 import java.io.IOException ; 16 import java.io.StringWriter ; 17 import java.util.Collection ; 18 import java.util.Collections ; 19 import java.util.HashMap ; 20 import java.util.HashSet ; 21 import java.util.Iterator ; 22 import java.util.Map ; 23 import java.util.Set ; 24 import java.util.SortedSet ; 25 import java.util.TreeSet ; 26 27 import org.eclipse.core.commands.Command; 28 import org.eclipse.core.commands.IHandler; 29 import org.eclipse.core.commands.util.Tracing; 30 import org.eclipse.core.expressions.EvaluationContext; 31 import org.eclipse.core.expressions.EvaluationResult; 32 import org.eclipse.core.expressions.Expression; 33 import org.eclipse.core.expressions.IEvaluationContext; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.IStatus; 36 import org.eclipse.core.runtime.MultiStatus; 37 import org.eclipse.core.runtime.Status; 38 import org.eclipse.swt.widgets.Shell; 39 import org.eclipse.ui.ISources; 40 import org.eclipse.ui.commands.ICommandService; 41 import org.eclipse.ui.handlers.IHandlerActivation; 42 import org.eclipse.ui.internal.WorkbenchPlugin; 43 import org.eclipse.ui.internal.misc.Policy; 44 import org.eclipse.ui.internal.services.EvaluationResultCacheComparator; 45 import org.eclipse.ui.internal.services.ExpressionAuthority; 46 47 62 final class HandlerAuthority extends ExpressionAuthority { 63 64 68 private static final int ACTIVATIONS_BY_SOURCE_SIZE = 256; 69 70 74 private static final int ACTIVATIONS_TO_RECOMPUTE_SIZE = 1024; 75 76 81 private static final boolean DEBUG = Policy.DEBUG_HANDLERS; 82 83 87 private static final boolean DEBUG_PERFORMANCE = Policy.DEBUG_HANDLERS_PERFORMANCE; 88 89 94 private static final boolean DEBUG_VERBOSE = Policy.DEBUG_HANDLERS 95 && Policy.DEBUG_HANDLERS_VERBOSE; 96 97 100 private static final String DEBUG_VERBOSE_COMMAND_ID = Policy.DEBUG_HANDLERS_VERBOSE_COMMAND_ID; 101 102 105 private static final String TRACING_COMPONENT = "HANDLERS"; 107 116 private final Map [] activationsByExpressionBySourcePriority = new Map [33]; 117 118 122 private final ICommandService commandService; 123 124 131 private final Map handlerActivationsByCommandId = new HashMap (); 132 133 private Set previousLogs = new HashSet (); 134 135 142 HandlerAuthority(final ICommandService commandService) { 143 if (commandService == null) { 144 throw new NullPointerException ( 145 "The handler authority needs a command service"); } 147 148 this.commandService = commandService; 149 } 150 151 159 final void activateHandler(final IHandlerActivation activation) { 160 final String commandId = activation.getCommandId(); 162 MultiStatus conflicts = new MultiStatus("org.eclipse.ui.workbench", 0, "A handler conflict occurred. This may disable some commands.", null); 165 final Object value = handlerActivationsByCommandId.get(commandId); 166 if (value instanceof SortedSet ) { 167 final SortedSet handlerActivations = (SortedSet ) value; 168 if (!handlerActivations.contains(activation)) { 169 handlerActivations.add(activation); 170 updateCommand(commandId, resolveConflicts(commandId, 171 handlerActivations, conflicts)); 172 } 173 } else if (value instanceof IHandlerActivation) { 174 if (value != activation) { 175 final SortedSet handlerActivations = new TreeSet ( 176 new EvaluationResultCacheComparator()); 177 handlerActivations.add(value); 178 handlerActivations.add(activation); 179 handlerActivationsByCommandId 180 .put(commandId, handlerActivations); 181 updateCommand(commandId, resolveConflicts(commandId, 182 handlerActivations, conflicts)); 183 } 184 } else { 185 handlerActivationsByCommandId.put(commandId, activation); 186 updateCommand(commandId, (evaluate(activation) ? activation : null)); 187 } 188 189 if (conflicts.getSeverity()!=IStatus.OK) { 190 WorkbenchPlugin.log(conflicts); 191 } 192 193 final int sourcePriority = activation.getSourcePriority(); 195 for (int i = 1; i <= 32; i++) { 196 if ((sourcePriority & (1 << i)) != 0) { 197 Map activationsByExpression = activationsByExpressionBySourcePriority[i]; 198 if (activationsByExpression == null) { 199 activationsByExpression = new HashMap ( 200 ACTIVATIONS_BY_SOURCE_SIZE); 201 activationsByExpressionBySourcePriority[i] = activationsByExpression; 202 } 203 204 final Expression expression = activation.getExpression(); 205 Collection activations = (Collection ) activationsByExpression 206 .get(expression); 207 if (activations == null) { 208 activations = new HashSet (); 209 activationsByExpression.put(expression, activations); 210 } 211 activations.add(activation); 212 } 213 } 214 } 215 216 223 final void deactivateHandler(final IHandlerActivation activation) { 224 final String commandId = activation.getCommandId(); 226 MultiStatus conflicts = new MultiStatus("org.eclipse.ui.workbench", 0, "A handler conflict occurred. This may disable some commands.", null); 229 final Object value = handlerActivationsByCommandId.get(commandId); 230 if (value instanceof SortedSet ) { 231 final SortedSet handlerActivations = (SortedSet ) value; 232 if (handlerActivations.contains(activation)) { 233 handlerActivations.remove(activation); 234 if (handlerActivations.isEmpty()) { 235 handlerActivationsByCommandId.remove(commandId); 236 updateCommand(commandId, null); 237 238 } else if (handlerActivations.size() == 1) { 239 final IHandlerActivation remainingActivation = (IHandlerActivation) handlerActivations 240 .iterator().next(); 241 handlerActivationsByCommandId.put(commandId, 242 remainingActivation); 243 updateCommand( 244 commandId, 245 (evaluate(remainingActivation) ? remainingActivation 246 : null)); 247 248 } else { 249 updateCommand(commandId, resolveConflicts(commandId, 250 handlerActivations, conflicts)); 251 } 252 } 253 } else if (value instanceof IHandlerActivation) { 254 if (value == activation) { 255 handlerActivationsByCommandId.remove(commandId); 256 updateCommand(commandId, null); 257 } 258 } 259 if (conflicts.getSeverity()!=IStatus.OK) { 260 WorkbenchPlugin.log(conflicts); 261 } 262 263 final int sourcePriority = activation.getSourcePriority(); 265 for (int i = 1; i <= 32; i++) { 266 if ((sourcePriority & (1 << i)) != 0) { 267 final Map activationsByExpression = activationsByExpressionBySourcePriority[i]; 268 if (activationsByExpression == null) { 269 continue; 270 } 271 272 final Expression expression = activation.getExpression(); 273 final Collection activations = (Collection ) activationsByExpression 274 .get(expression); 275 activations.remove(activation); 276 if (activations.isEmpty()) { 277 activationsByExpression.remove(expression); 278 } 279 280 if (activationsByExpression.isEmpty()) { 281 activationsByExpressionBySourcePriority[i] = null; 282 } 283 } 284 } 285 } 286 287 292 final Shell getActiveShell() { 293 return (Shell) getVariable(ISources.ACTIVE_SHELL_NAME); 294 } 295 296 313 private final IHandlerActivation resolveConflicts(final String commandId, 314 final SortedSet activations, MultiStatus conflicts) { 315 if (activations.isEmpty()) { 317 return null; 318 } 319 320 final Iterator activationItr = activations.iterator(); 322 IHandlerActivation bestActivation = null; 323 IHandlerActivation currentActivation = null; 324 boolean conflict = false; 325 while (activationItr.hasNext()) { 326 currentActivation = (IHandlerActivation) activationItr.next(); 327 if (!evaluate(currentActivation)) { 328 continue; } 330 331 if ((DEBUG_VERBOSE) 333 && ((DEBUG_VERBOSE_COMMAND_ID == null) || (DEBUG_VERBOSE_COMMAND_ID 334 .equals(commandId)))) { 335 Tracing.printTrace(TRACING_COMPONENT, 336 " resolveConflicts: eval: " + currentActivation); } 338 if (bestActivation == null) { 339 bestActivation = currentActivation; 340 conflict = false; 341 continue; 342 } 343 344 final int comparison = bestActivation.compareTo(currentActivation); 346 if (comparison < 0) { 347 bestActivation = currentActivation; 348 conflict = false; 349 350 } else if (comparison == 0) { 351 if (currentActivation.getHandler() != bestActivation 352 .getHandler()) { 353 conflict = true; 354 break; 355 } 356 357 } else { 358 break; 359 } 360 } 361 362 if (DEBUG) { 364 if (conflict) { 365 Tracing.printTrace(TRACING_COMPONENT, 366 "Unresolved conflict detected for '" + commandId + '\''); 368 } else if ((bestActivation != null) 369 && (DEBUG_VERBOSE) 370 && ((DEBUG_VERBOSE_COMMAND_ID == null) || (DEBUG_VERBOSE_COMMAND_ID 371 .equals(commandId)))) { 372 Tracing 373 .printTrace(TRACING_COMPONENT, 374 "Resolved conflict detected. The following activation won: "); Tracing.printTrace(TRACING_COMPONENT, " " + bestActivation); } 377 } 378 379 if (conflict) { 381 if (previousLogs.add(commandId)) { 382 final StringWriter sw = new StringWriter (); 383 final BufferedWriter buffer = new BufferedWriter (sw); 384 try { 385 buffer.write("Conflict for \'"); buffer.write(commandId); 387 buffer.write("\':"); buffer.newLine(); 389 buffer.write(bestActivation.toString()); 390 buffer.newLine(); 391 buffer.write(currentActivation.toString()); 392 buffer.flush(); 393 } catch (IOException e) { 394 } 396 397 IStatus s = new Status(IStatus.WARNING, 398 "org.eclipse.ui.workbench", sw.toString()); 400 conflicts.add(s); 401 } 402 return null; 403 } 404 return bestActivation; 405 } 406 407 415 protected final void sourceChanged(final int sourcePriority) { 416 long startTime = 0L; 418 if (DEBUG_PERFORMANCE) { 419 startTime = System.currentTimeMillis(); 420 } 421 422 428 final Collection changedCommandIds = new HashSet ( 429 ACTIVATIONS_TO_RECOMPUTE_SIZE); 430 for (int i = 1; i <= 32; i++) { 431 if ((sourcePriority & (1 << i)) != 0) { 432 final Map activationsByExpression = activationsByExpressionBySourcePriority[i]; 433 if (activationsByExpression != null) { 434 final Iterator activationByExpressionItr = activationsByExpression 435 .values().iterator(); 436 while (activationByExpressionItr.hasNext()) { 437 final Collection activations = (Collection ) activationByExpressionItr 438 .next(); 439 final Iterator activationItr = activations.iterator(); 440 441 if (activationItr.hasNext()) { 443 IHandlerActivation activation = (IHandlerActivation) activationItr 444 .next(); 445 final boolean currentActive = evaluate(activation); 446 activation.clearResult(); 447 final boolean newActive = evaluate(activation); 448 if (newActive != currentActive) { 449 changedCommandIds 450 .add(activation.getCommandId()); 451 452 while (activationItr.hasNext()) { 454 activation = (IHandlerActivation) activationItr 455 .next(); 456 activation.setResult(newActive); 457 458 changedCommandIds.add(activation 459 .getCommandId()); 460 } 461 } else { 462 while (activationItr.hasNext()) { 463 activation = (IHandlerActivation) activationItr 464 .next(); 465 if (newActive != evaluate(activation)) { 470 activation.setResult(newActive); 471 changedCommandIds.add(activation 472 .getCommandId()); 473 } 474 } 475 } 476 } 477 } 478 } 479 } 480 } 481 482 MultiStatus conflicts = new MultiStatus("org.eclipse.ui.workbench", 0, "A handler conflict occurred. This may disable some commands.", null); 485 486 490 final Iterator changedCommandIdItr = changedCommandIds.iterator(); 491 while (changedCommandIdItr.hasNext()) { 492 final String commandId = (String ) changedCommandIdItr.next(); 493 final Object value = handlerActivationsByCommandId.get(commandId); 494 if (value instanceof IHandlerActivation) { 495 final IHandlerActivation activation = (IHandlerActivation) value; 496 updateCommand(commandId, (evaluate(activation) ? activation 497 : null)); 498 } else if (value instanceof SortedSet ) { 499 final IHandlerActivation activation = resolveConflicts( 500 commandId, (SortedSet ) value, conflicts); 501 updateCommand(commandId, activation); 502 } else { 503 updateCommand(commandId, null); 504 } 505 } 506 if (conflicts.getSeverity()!=IStatus.OK) { 507 WorkbenchPlugin.log(conflicts); 508 } 509 510 if (DEBUG_PERFORMANCE) { 512 final long elapsedTime = System.currentTimeMillis() - startTime; 513 final int size = changedCommandIds.size(); 514 if (size > 0) { 515 Tracing.printTrace(TRACING_COMPONENT, size 516 + " command ids changed in " + elapsedTime + "ms"); } 518 } 519 } 520 521 531 private final void updateCommand(final String commandId, 532 final IHandlerActivation activation) { 533 final Command command = commandService.getCommand(commandId); 534 if (activation == null) { 535 command.setHandler(null); 536 } else { 537 command.setHandler(activation.getHandler()); 538 commandService.refreshElements(commandId, null); 539 } 540 } 541 542 552 final void updateShellKludge() { 553 updateCurrentState(); 554 sourceChanged(ISources.ACTIVE_SHELL); 555 } 556 557 569 public final IHandler findHandler(String commandId, 570 IEvaluationContext context) { 571 Object o = handlerActivationsByCommandId.get(commandId); 572 if (o instanceof IHandlerActivation) { 573 IHandlerActivation activation = (IHandlerActivation) o; 574 try { 575 if (eval(context, activation)) { 576 return activation.getHandler(); 577 } 578 } catch (CoreException e) { 579 } 581 } else if (o instanceof SortedSet ) { 582 SortedSet activations = (SortedSet ) o; 583 IHandlerActivation lastActivation = null; 584 IHandlerActivation currentActivation = null; 585 Iterator i = activations.iterator(); 586 while (i.hasNext() && lastActivation==null) { 587 IHandlerActivation activation = (IHandlerActivation) i.next(); 588 try { 589 if (eval(context, activation)) { 590 lastActivation = currentActivation; 591 currentActivation = activation; 592 } 593 } catch (CoreException e) { 594 } 596 } 597 if (currentActivation != null) { 598 if (lastActivation == null) { 599 return currentActivation.getHandler(); 600 } 601 if (lastActivation.getSourcePriority() != currentActivation 602 .getSourcePriority()) { 603 return lastActivation.getHandler(); 604 } 605 } 606 } 607 return null; 608 } 609 610 623 private boolean eval(IEvaluationContext context, 624 IHandlerActivation activation) throws CoreException { 625 Expression expression = activation.getExpression(); 626 if (expression == null) { 627 return true; 628 } 629 return expression.evaluate(context) == EvaluationResult.TRUE; 630 } 631 632 644 public IEvaluationContext getContextSnapshot() { 645 return fillInContext(false); 646 } 647 648 659 public IEvaluationContext getFullContextSnapshot() { 660 return fillInContext(true); 661 } 662 663 private IEvaluationContext fillInContext(boolean fullContext) { 664 IEvaluationContext tmpContext = getCurrentState(); 665 666 EvaluationContext context = null; 667 if (fullContext) { 668 context = new EvaluationContext(null, tmpContext.getDefaultVariable()); 669 copyVariable(context, tmpContext, ISources.ACTIVE_CURRENT_SELECTION_NAME); 670 copyVariable(context, tmpContext, ISources.ACTIVE_FOCUS_CONTROL_ID_NAME); 671 copyVariable(context, tmpContext, ISources.ACTIVE_FOCUS_CONTROL_NAME); 672 copyVariable(context, tmpContext, ISources.ACTIVE_MENU_EDITOR_INPUT_NAME); 673 copyVariable(context, tmpContext, ISources.ACTIVE_MENU_NAME); 674 copyVariable(context, tmpContext, ISources.ACTIVE_MENU_SELECTION_NAME); 675 } else { 676 context = new EvaluationContext(null, Collections.EMPTY_LIST); 677 } 678 679 copyVariable(context, tmpContext, ISources.ACTIVE_ACTION_SETS_NAME); 680 copyVariable(context, tmpContext, ISources.ACTIVE_CONTEXT_NAME); 681 copyVariable(context, tmpContext, ISources.ACTIVE_EDITOR_ID_NAME); 682 copyVariable(context, tmpContext, ISources.ACTIVE_EDITOR_NAME); 683 copyVariable(context, tmpContext, ISources.ACTIVE_PART_ID_NAME); 684 copyVariable(context, tmpContext, ISources.ACTIVE_PART_NAME); 685 copyVariable(context, tmpContext, ISources.ACTIVE_SITE_NAME); 686 copyVariable(context, tmpContext, 687 ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME); 688 copyVariable(context, tmpContext, 689 ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME); 690 copyVariable(context, tmpContext, ISources.ACTIVE_WORKBENCH_WINDOW_NAME); 691 copyVariable(context, tmpContext, 692 ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME); 693 copyVariable(context, tmpContext, ISources.ACTIVE_SHELL_NAME); 694 695 return context; 696 } 697 698 private void copyVariable(IEvaluationContext context, 699 IEvaluationContext tmpContext, String var) { 700 Object o = tmpContext.getVariable(var); 701 if (o != null) { 702 context.addVariable(var, o); 703 } 704 } 705 } 706 | Popular Tags |