Package org.eclipse.ui.internal.contexts

Source Code of org.eclipse.ui.internal.contexts.ContextAuthority

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

package org.eclipse.ui.internal.contexts;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.eclipse.core.commands.contexts.ContextManager;
import org.eclipse.core.commands.util.Tracing;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ActiveShellExpression;
import org.eclipse.ui.ISources;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.misc.Policy;
import org.eclipse.ui.internal.services.ExpressionAuthority;

/**
* <p>
* A central authority for deciding activation of contexts. This authority
* listens to a variety of incoming sources, and updates the underlying context
* manager if changes occur.
* </p>
*
* @since 3.1
*/
public final class ContextAuthority extends ExpressionAuthority {
  public static final String DEFER_EVENTS = "org.eclipse.ui.internal.contexts.deferEvents"; //$NON-NLS-1$
  public static final String SEND_EVENTS = "org.eclipse.ui.internal.contexts.sendEvents"; //$NON-NLS-1$


  /**
   * The default size of the set containing the activations to recompute. This
   * is more than enough to cover the average case.
   */
  private static final int ACTIVATIONS_TO_RECOMPUTE_SIZE = 4;

  /**
   * Whether the context authority should kick into debugging mode. This
   * causes the unresolvable handler conflicts to be printed to the console.
   */
  private static final boolean DEBUG = Policy.DEBUG_CONTEXTS;

  /**
   * Whether the performance information should be printed about the
   * performance of the context authority.
   */
  private static final boolean DEBUG_PERFORMANCE = Policy.DEBUG_CONTEXTS_PERFORMANCE;

  /**
   * The name of the data tag containing the dispose listener information.
   */
  private static final String DISPOSE_LISTENER = "org.eclipse.ui.internal.contexts.ContextAuthority"; //$NON-NLS-1$

  /**
   * The component name to print when displaying tracing information.
   */
  private static final String TRACING_COMPONENT = "CONTEXTS"; //$NON-NLS-1$

  /**
   * A bucket sort of the context activations based on source priority. Each
   * activation will appear only once per set, but may appear in multiple
   * sets. If no activations are defined for a particular priority level, then
   * the array at that index will only contain <code>null</code>.
   */
  private final Set[] activationsBySourcePriority = new Set[33];

  /**
   * This is a map of context activations (<code>Collection</code> of
   * <code>IContextActivation</code>) sorted by context identifier (<code>String</code>).
   * If there is only one context activation for a context, then the
   * <code>Collection</code> is replaced by a
   * <code>IContextActivation</code>. If there is no activation, the entry
   * should be removed entirely.
   */
  private final Map contextActivationsByContextId = new HashMap();

  /**
   * The context manager that should be updated when the contexts are
   * changing.
   */
  private final ContextManager contextManager;

  /**
   * The context service that should be used for authority-managed
   * shell-related contexts. This value is never <code>null</code>.
   */
  private final IContextService contextService;

  /**
   * This is a map of shell to a list of activations. When a shell is
   * registered, it is added to this map with the list of activation that
   * should be submitted when the shell is active. When the shell is
   * deactivated, this same list should be withdrawn. A shell is removed from
   * this map using the {@link #unregisterShell(Shell)}method. This value may
   * be empty, but is never <code>null</code>. The <code>null</code> key
   * is reserved for active shells that have not been registered but have a
   * parent (i.e., default dialog service).
   */
  private final Map registeredWindows = new WeakHashMap();

  /**
   * Constructs a new instance of <code>ContextAuthority</code>.
   *
   * @param contextManager
   *            The context manager from which contexts can be retrieved (to
   *            update their active state); must not be <code>null</code>.
   * @param contextService
   *            The workbench context service for which this authority is
   *            acting. This allows the authority to manage shell-specific
   *            contexts. This value must not be <code>null</code>.
   */
  ContextAuthority(final ContextManager contextManager,
      final IContextService contextService) {
    if (contextManager == null) {
      throw new NullPointerException(
          "The context authority needs a context manager"); //$NON-NLS-1$
    }
    if (contextService == null) {
      throw new NullPointerException(
          "The context authority needs an evaluation context"); //$NON-NLS-1$
    }

    this.contextManager = contextManager;
    this.contextService = contextService;
  }

  /**
   * Activates a context on the workbench. This will add it to a master list.
   *
   * @param activation
   *            The activation; must not be <code>null</code>.
   */
  final void activateContext(final IContextActivation activation) {
    // First we update the contextActivationsByContextId map.
    final String contextId = activation.getContextId();
    if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) {
      contextManager.addActiveContext(contextId);
      return;
    }
    final Object value = contextActivationsByContextId.get(contextId);
    if (value instanceof Collection) {
      final Collection contextActivations = (Collection) value;
      if (!contextActivations.contains(activation)) {
        contextActivations.add(activation);
        updateContext(contextId, containsActive(contextActivations));
      }
    } else if (value instanceof IContextActivation) {
      if (value != activation) {
        final Collection contextActivations = new ArrayList(2);
        contextActivations.add(value);
        contextActivations.add(activation);
        contextActivationsByContextId
            .put(contextId, contextActivations);
        updateContext(contextId, containsActive(contextActivations));
      }
    } else {
      contextActivationsByContextId.put(contextId, activation);
      updateContext(contextId, evaluate(activation));
    }

    // Next we update the source priority bucket sort of activations.
    final int sourcePriority = activation.getSourcePriority();
    for (int i = 1; i <= 32; i++) {
      if ((sourcePriority & (1 << i)) != 0) {
        Set activations = activationsBySourcePriority[i];
        if (activations == null) {
          activations = new HashSet(1);
          activationsBySourcePriority[i] = activations;
        }
        activations.add(activation);
      }
    }
  }

  /**
   * Checks whether the new active shell is registered. If it is already
   * registered, then it does no work. If it is not registered, then it checks
   * what type of contexts the shell should have by default. This is
   * determined by parenting. A shell with no parent receives no contexts. A
   * shell with a parent, receives the dialog contexts.
   *
   * @param newShell
   *            The newly active shell; may be <code>null</code> or
   *            disposed.
   * @param oldShell
   *            The previously active shell; may be <code>null</code> or
   *            disposed.
   */
  private final void checkWindowType(final Shell newShell,
      final Shell oldShell) {
    /*
     * If the previous active shell was recognized as a dialog by default,
     * then remove its submissions.
     */
    Collection oldActivations = (Collection) registeredWindows
        .get(oldShell);
    if (oldActivations == null) {
      /*
       * The old shell wasn't registered. So, we need to check if it was
       * considered a dialog by default.
       */
      oldActivations = (Collection) registeredWindows.get(null);
      if (oldActivations != null) {
        final Iterator oldActivationItr = oldActivations.iterator();
        while (oldActivationItr.hasNext()) {
          final IContextActivation activation = (IContextActivation) oldActivationItr
              .next();
          deactivateContext(activation);
        }
      }
    }

    /*
     * If the new active shell is recognized as a dialog by default, then
     * create some submissions, remember them, and submit them for
     * processing.
     */
    if ((newShell != null) && (!newShell.isDisposed())) {
      final Collection newActivations;

      if ((newShell.getParent() != null)
          && (registeredWindows.get(newShell) == null)) {
        // This is a dialog by default.
        newActivations = new ArrayList();
        final Expression expression = new ActiveShellExpression(
            newShell);
        final IContextActivation dialogWindowActivation = new ContextActivation(
            IContextService.CONTEXT_ID_DIALOG_AND_WINDOW,
            expression, contextService);
        activateContext(dialogWindowActivation);
        newActivations.add(dialogWindowActivation);
        final IContextActivation dialogActivation = new ContextActivation(
            IContextService.CONTEXT_ID_DIALOG, expression,
            contextService);
        activateContext(dialogActivation);
        newActivations.add(dialogActivation);
        registeredWindows.put(null, newActivations);

        /*
         * Make sure the submissions will be removed in event of
         * disposal. This is really just a paranoid check. The
         * "oldSubmissions" code above should take care of this.
         */
        newShell.addDisposeListener(new DisposeListener() {

          /*
           * (non-Javadoc)
           *
           * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
           */
          public void widgetDisposed(DisposeEvent e) {
            registeredWindows.remove(null);
            if (!newShell.isDisposed()) {
              newShell.removeDisposeListener(this);
            }

            /*
             * In the case where a dispose has happened, we are
             * expecting an activation event to arrive at some point
             * in the future. If we process the submissions now,
             * then we will update the activeShell before
             * checkWindowType is called. This means that dialogs
             * won't be recognized as dialogs.
             */
            final Iterator newActivationItr = newActivations
                .iterator();
            while (newActivationItr.hasNext()) {
              deactivateContext((IContextActivation) newActivationItr
                  .next());
            }
          }
        });

      } else {
        // Shells that are not dialogs by default must register.
        newActivations = null;

      }
    }
  }

  /**
   * Returns a subset of the given <code>activations</code> containing only
   * those that are active
   *
   * @param activations
   *            The activations to trim; must not be <code>null</code>, but
   *            may be empty.
   * @return <code>true</code> if there is at least one active context;
   *         <code>false</code> otherwise.
   */
  private final boolean containsActive(final Collection activations) {
    final Iterator activationItr = activations.iterator();
    while (activationItr.hasNext()) {
      final IContextActivation activation = (IContextActivation) activationItr
          .next();
      if (evaluate(activation)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Removes an activation for a context on the workbench. This will remove it
   * from the master list, and update the appropriate context, if necessary.
   *
   * @param activation
   *            The activation; must not be <code>null</code>.
   */
  final void deactivateContext(final IContextActivation activation) {
    // First we update the handlerActivationsByCommandId map.
    final String contextId = activation.getContextId();
    if (DEFER_EVENTS.equals(contextId) || SEND_EVENTS.equals(contextId)) {
      return;
    }
    final Object value = contextActivationsByContextId.get(contextId);
    if (value instanceof Collection) {
      final Collection contextActivations = (Collection) value;
      if (contextActivations.contains(activation)) {
        contextActivations.remove(activation);
        if (contextActivations.isEmpty()) {
          contextActivationsByContextId.remove(contextId);
          updateContext(contextId, false);

        } else if (contextActivations.size() == 1) {
          final IContextActivation remainingActivation = (IContextActivation) contextActivations
              .iterator().next();
          contextActivationsByContextId.put(contextId,
              remainingActivation);
          updateContext(contextId, evaluate(remainingActivation));

        } else {
          updateContext(contextId, containsActive(contextActivations));
        }
      }
    } else if (value instanceof IContextActivation) {
      if (value == activation) {
        contextActivationsByContextId.remove(contextId);
        updateContext(contextId, false);
      }
    }

    // Next we update the source priority bucket sort of activations.
    final int sourcePriority = activation.getSourcePriority();
    for (int i = 1; i <= 32; i++) {
      if ((sourcePriority & (1 << i)) != 0) {
        final Set activations = activationsBySourcePriority[i];
        if (activations == null) {
          continue;
        }
        activations.remove(activation);
        if (activations.isEmpty()) {
          activationsBySourcePriority[i] = null;
        }
      }
    }
  }

  /**
   * Returns the currently active shell.
   *
   * @return The currently active shell; may be <code>null</code>.
   */
  final Shell getActiveShell() {
    return (Shell) getVariable(ISources.ACTIVE_SHELL_NAME);
  }

  /**
   * Returns the shell type for the given shell.
   *
   * @param shell
   *            The shell for which the type should be determined. If this
   *            value is <code>null</code>, then
   *            <code>IWorkbenchContextSupport.TYPE_NONE</code> is returned.
   * @return <code>IWorkbenchContextSupport.TYPE_WINDOW</code>,
   *         <code>IWorkbenchContextSupport.TYPE_DIALOG</code>, or
   *         <code>IWorkbenchContextSupport.TYPE_NONE</code>.
   */
  public final int getShellType(final Shell shell) {
    // If the shell is null, then return none.
    if (shell == null) {
      return IContextService.TYPE_NONE;
    }

    final Collection activations = (Collection) registeredWindows
        .get(shell);
    if (activations != null) {
      // The shell is registered, so check what type it was registered as.
      if (activations.isEmpty()) {
        // It was registered as none.
        return IContextService.TYPE_NONE;
      }

      // Look for the right type of context id.
      final Iterator activationItr = activations.iterator();
      while (activationItr.hasNext()) {
        final IContextActivation activation = (IContextActivation) activationItr
            .next();
        final String contextId = activation.getContextId();
        if (contextId == IContextService.CONTEXT_ID_DIALOG) {
          return IContextService.TYPE_DIALOG;
        } else if (contextId == IContextService.CONTEXT_ID_WINDOW) {
          return IContextService.TYPE_WINDOW;
        }
      }

      // This shouldn't be possible.
      Assert
          .isTrue(
              false,
              "A registered shell should have at least one submission matching TYPE_WINDOW or TYPE_DIALOG"); //$NON-NLS-1$
      return IContextService.TYPE_NONE; // not reachable

    } else if (shell.getParent() != null) {
      /*
       * The shell is not registered, but it has a parent. It is therefore
       * considered a dialog by default.
       */
      return IContextService.TYPE_DIALOG;

    } else {
      /*
       * The shell is not registered, but has no parent. It gets no key
       * bindings.
       */
      return IContextService.TYPE_NONE;
    }
  }

  /**
   * <p>
   * Registers a shell to automatically promote or demote some basic types of
   * contexts. The "In Dialogs" and "In Windows" contexts are provided by the
   * system. This a convenience method to ensure that these contexts are
   * promoted when the given is shell is active.
   * </p>
   * <p>
   * If a shell is registered as a window, then the "In Windows" context is
   * enabled when that shell is active. If a shell is registered as a dialog --
   * or is not registered, but has a parent shell -- then the "In Dialogs"
   * context is enabled when that shell is active. If the shell is registered
   * as none -- or is not registered, but has no parent shell -- then the
   * neither of the contexts will be enabled (by us -- someone else can always
   * enabled them).
   * </p>
   * <p>
   * If the provided shell has already been registered, then this method will
   * change the registration.
   * </p>
   *
   * @param shell
   *            The shell to register for key bindings; must not be
   *            <code>null</code>.
   * @param type
   *            The type of shell being registered. This value must be one of
   *            the constants given in this interface.
   *
   * @return <code>true</code> if the shell had already been registered
   *         (i.e., the registration has changed); <code>false</code>
   *         otherwise.
   */
  public final boolean registerShell(final Shell shell, final int type) {
    // We do not allow null shell registration. It is reserved.
    if (shell == null) {
      throw new NullPointerException("The shell was null"); //$NON-NLS-1$
    }

    // Debugging output
    if (DEBUG) {
      final StringBuffer buffer = new StringBuffer("register shell '"); //$NON-NLS-1$
      buffer.append(shell);
      buffer.append("' as "); //$NON-NLS-1$
      switch (type) {
      case IContextService.TYPE_DIALOG:
        buffer.append("dialog"); //$NON-NLS-1$
        break;
      case IContextService.TYPE_WINDOW:
        buffer.append("window"); //$NON-NLS-1$
        break;
      case IContextService.TYPE_NONE:
        buffer.append("none"); //$NON-NLS-1$
        break;
      default:
        buffer.append("unknown"); //$NON-NLS-1$
        break;
      }
      Tracing.printTrace(TRACING_COMPONENT, buffer.toString());
    }

    // Build the list of submissions.
    final List activations = new ArrayList();
    Expression expression;
    IContextActivation dialogWindowActivation;
    switch (type) {
    case IContextService.TYPE_DIALOG:
      expression = new ActiveShellExpression(shell);
      dialogWindowActivation = new ContextActivation(
          IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
          contextService);
      activateContext(dialogWindowActivation);
      activations.add(dialogWindowActivation);
      final IContextActivation dialogActivation = new ContextActivation(
          IContextService.CONTEXT_ID_DIALOG, expression,
          contextService);
      activateContext(dialogActivation);
      activations.add(dialogActivation);
      break;
    case IContextService.TYPE_NONE:
      break;
    case IContextService.TYPE_WINDOW:
      expression = new ActiveShellExpression(shell);
      dialogWindowActivation = new ContextActivation(
          IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
          contextService);
      activateContext(dialogWindowActivation);
      activations.add(dialogWindowActivation);
      final IContextActivation windowActivation = new ContextActivation(
          IContextService.CONTEXT_ID_WINDOW, expression,
          contextService);
      activateContext(windowActivation);
      activations.add(windowActivation);
      break;
    default:
      throw new IllegalArgumentException("The type is not recognized: " //$NON-NLS-1$
          + type);
    }

    // Check to see if the activations are already present.
    boolean returnValue = false;
    final Collection previousActivations = (Collection) registeredWindows
        .get(shell);
    if (previousActivations != null) {
      returnValue = true;
      final Iterator previousActivationItr = previousActivations
          .iterator();
      while (previousActivationItr.hasNext()) {
        final IContextActivation activation = (IContextActivation) previousActivationItr
            .next();
        deactivateContext(activation);
      }
    }

    // Add the new submissions, and force some reprocessing to occur.
    registeredWindows.put(shell, activations);

    /*
     * Remember the dispose listener so that we can remove it later if we
     * unregister the shell.
     */
    final DisposeListener shellDisposeListener = new DisposeListener() {

      /*
       * (non-Javadoc)
       *
       * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
       */
      public void widgetDisposed(DisposeEvent e) {
        registeredWindows.remove(shell);
        if (!shell.isDisposed()) {
          shell.removeDisposeListener(this);
        }

        /*
         * In the case where a dispose has happened, we are expecting an
         * activation event to arrive at some point in the future. If we
         * process the submissions now, then we will update the
         * activeShell before checkWindowType is called. This means that
         * dialogs won't be recognized as dialogs.
         */
        final Iterator activationItr = activations.iterator();
        while (activationItr.hasNext()) {
          deactivateContext((IContextActivation) activationItr.next());
        }
      }
    };

    // Make sure the submissions will be removed in event of disposal.
    shell.addDisposeListener(shellDisposeListener);
    shell.setData(DISPOSE_LISTENER, shellDisposeListener);

    return returnValue;
  }

  /**
   * Carries out the actual source change notification. It assumed that by the
   * time this method is called, <code>context</code> is up-to-date with the
   * current state of the application.
   *
   * @param sourcePriority
   *            A bit mask of all the source priorities that have changed.
   */
  protected final void sourceChanged(final int sourcePriority) {
    // If tracing, then track how long it takes to process the activations.
    long startTime = 0L;
    if (DEBUG_PERFORMANCE) {
      startTime = System.currentTimeMillis();
    }

    /*
     * In this first phase, we cycle through all of the activations that
     * could have potentially changed. Each such activation is added to a
     * set for future processing. We add it to a set so that we avoid
     * handling any individual activation more than once.
     */
    final Set activationsToRecompute = new HashSet(
        ACTIVATIONS_TO_RECOMPUTE_SIZE);
    for (int i = 1; i <= 32; i++) {
      if ((sourcePriority & (1 << i)) != 0) {
        final Collection activations = activationsBySourcePriority[i];
        if (activations != null) {
          final Iterator activationItr = activations.iterator();
          while (activationItr.hasNext()) {
            activationsToRecompute.add(activationItr.next());
          }
        }
      }
    }

    /*
     * For every activation, we recompute its active state, and check
     * whether it has changed. If it has changed, then we take note of the
     * context identifier so we can update the context later.
     */
    final Collection changedContextIds = new ArrayList(
        activationsToRecompute.size());
    final Iterator activationItr = activationsToRecompute.iterator();
    while (activationItr.hasNext()) {
      final IContextActivation activation = (IContextActivation) activationItr
          .next();
      final boolean currentActive = evaluate(activation);
      activation.clearResult();
      final boolean newActive = evaluate(activation);
      if (newActive != currentActive) {
        changedContextIds.add(activation.getContextId());
      }
    }

    try {
      contextManager.addActiveContext(DEFER_EVENTS);
      /*
       * For every context identifier with a changed activation, we
       * resolve conflicts and trigger an update.
       */
      final Iterator changedContextIdItr = changedContextIds.iterator();
      while (changedContextIdItr.hasNext()) {
        final String contextId = (String) changedContextIdItr.next();
        final Object value = contextActivationsByContextId
            .get(contextId);
        if (value instanceof IContextActivation) {
          final IContextActivation activation = (IContextActivation) value;
          updateContext(contextId, evaluate(activation));
        } else if (value instanceof Collection) {
          updateContext(contextId, containsActive((Collection) value));
        } else {
          updateContext(contextId, false);
        }
      }
    } finally {
      contextManager.addActiveContext(SEND_EVENTS);
    }

    // If tracing performance, then print the results.
    if (DEBUG_PERFORMANCE) {
      final long elapsedTime = System.currentTimeMillis() - startTime;
      final int size = activationsToRecompute.size();
      if (size > 0) {
        Tracing.printTrace(TRACING_COMPONENT, size
            + " activations recomputed in " + elapsedTime + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
      }
    }
  }

  /**
   * <p>
   * Unregisters a shell that was previously registered. After this method
   * completes, the shell will be treated as if it had never been registered
   * at all. If you have registered a shell, you should ensure that this
   * method is called when the shell is disposed. Otherwise, a potential
   * memory leak will exist.
   * </p>
   * <p>
   * If the shell was never registered, or if the shell is <code>null</code>,
   * then this method returns <code>false</code> and does nothing.
   *
   * @param shell
   *            The shell to be unregistered; does nothing if this value is
   *            <code>null</code>.
   *
   * @return <code>true</code> if the shell had been registered;
   *         <code>false</code> otherwise.
   */
  public final boolean unregisterShell(final Shell shell) {
    // Don't allow this method to play with the special null slot.
    if (shell == null) {
      return false;
    }

    /*
     * If we're unregistering the shell but we're not about to dispose it,
     * then we'll end up leaking the DisposeListener unless we remove it
     * here.
     */
    if (!shell.isDisposed()) {
      final DisposeListener oldListener = (DisposeListener) shell
          .getData(DISPOSE_LISTENER);
      if (oldListener != null) {
        shell.removeDisposeListener(oldListener);
      }
    }

    Collection previousActivations = (Collection) registeredWindows
        .get(shell);
    if (previousActivations != null) {
      registeredWindows.remove(shell);

      final Iterator previousActivationItr = previousActivations
          .iterator();
      while (previousActivationItr.hasNext()) {
        final IContextActivation activation = (IContextActivation) previousActivationItr
            .next();
        deactivateContext(activation);
      }
      return true;
    }

    return false;
  }

  /**
   * Updates the context with the given context activation.
   *
   * @param contextId
   *            The identifier of the context which should be updated; must
   *            not be <code>null</code>.
   * @param active
   *            Whether the context should be active; <code>false</code>
   *            otherwise.
   */
  private final void updateContext(final String contextId,
      final boolean active) {
    if (active) {
      contextManager.addActiveContext(contextId);
    } else {
      contextManager.removeActiveContext(contextId);
    }
  }

  /**
   * Updates this authority's evaluation context. If the changed variable is
   * the <code>ISources.ACTIVE_SHELL_NAME</code> variable, then this also
   * triggers an update of the shell-specific contexts. For example, if a
   * dialog becomes active, then the dialog context will be activated by this
   * method.
   *
   * @param name
   *            The name of the variable to update; must not be
   *            <code>null</code>.
   * @param value
   *            The new value of the variable. If this value is
   *            <code>null</code>, then the variable is removed.
   */
  protected final void updateEvaluationContext(final String name,
      final Object value) {
    /*
     * Bug 84056. If we update the active workbench window, then we risk
     * falling back to that shell when the active shell has registered as
     * "none".
     */
    if ((name != null)
        && (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME.equals(name))) {
      /*
       * We need to track shell activation ourselves, as some special
       * contexts are automatically activated in response to different
       * types of shells becoming active.
       */
      if (ISources.ACTIVE_SHELL_NAME.equals(name)) {
        checkWindowType((Shell) value,
            (Shell) getVariable(ISources.ACTIVE_SHELL_NAME));
      }

      // Update the evaluation context itself.
      changeVariable(name, value);
    }
  }

  /**
   * <p>
   * Bug 95792. A mechanism by which the key binding architecture can force an
   * update of the contexts (based on the active shell) before trying to
   * execute a command. This mechanism is required for GTK+ only.
   * </p>
   * <p>
   * DO NOT CALL THIS METHOD.
   * </p>
   */
  final void updateShellKludge() {
    updateCurrentState();
    sourceChanged(ISources.ACTIVE_SHELL);
  }
}
TOP

Related Classes of org.eclipse.ui.internal.contexts.ContextAuthority

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.