Package org.eclipse.ui.internal.handlers

Source Code of org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy

/*******************************************************************************
* 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.handlers;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.core.commands.IObjectWithState;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.State;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IActionDelegate2;
import org.eclipse.ui.IActionDelegateWithEvent;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.WorkbenchPlugin;

/**
* <p>
* This proxies an {@link IActionDelegate} so that it can impersonate an
* {@link IHandler}.
* </p>
* <p>
* This class is not intended for use outside of the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*/
public final class ActionDelegateHandlerProxy implements ISelectionListener,
    ISelectionChangedListener, INullSelectionListener, IHandler,
    IObjectWithState {

  /**
   * The fake action that proxies all of the command-based services. This
   * value is never <code>null</code>.
   */
  private CommandLegacyActionWrapper action;

  /**
   * The identifier of the actions to create as a wrapper to the command
   * architecture. This value may be <code>null</code>.
   */
  private String actionId;

  /**
   * The command that will back the dummy actions exposed to this delegate.
   * This value is never <code>null</code>.
   */
  private ParameterizedCommand command;

  /**
   * This is the current selection, as seen by this proxy.
   */
  private ISelection currentSelection;

  /**
   * The delegate, if it has been created yet.
   */
  private IActionDelegate delegate;

  //
  // instead of casting, which is unreliable, pick
  // a delegate type based on the IConfigurationElement
  //
  private IEditorActionDelegate editorDelegate = null;
  private IViewActionDelegate viewDelegate = null;
  private IObjectActionDelegate objectDelegate = null;
  private IWorkbenchWindowActionDelegate windowDelegate = null;

  /**
   * The name of the configuration element attribute which contains the
   * information necessary to instantiate the real handler.
   */
  private String delegateAttributeName;

  /**
   * The configuration element from which the handler can be created. This
   * value will exist until the element is converted into a real class -- at
   * which point this value will be set to <code>null</code>.
   */
  private IConfigurationElement element;

  /**
   * The <code>enabledWhen</code> expression for the handler. Only if this
   * expression evaluates to <code>true</code> (or the value is
   * <code>null</code>) should we consult the handler.
   */
  private final Expression enabledWhenExpression;

  /**
   * A collection of objects listening to changes to this manager. This
   * collection is <code>null</code> if there are no listeners.
   */
  private transient ListenerList listenerList = null;

  /**
   * The image style to use when selecting the images to display for this
   * delegate. This value may be <code>null</code>, if the default style
   * should be used.
   */
  private final String style;

  /**
   * The identifier of the view with which this delegate must be associated.
   * This value is not <code>null</code> iff the delegate is an
   * {@link IViewActionDelegate}.
   */
  private final String viewId;

  /**
   * The workbench window in which this delegate is active. This value is
   * never <code>null</code>.
   */
  private final IWorkbenchWindow window;

  /**
   * Constructs a new instance of <code>ActionDelegateHandlerProxy</code>
   * with all the information it needs to try to avoid loading until it is
   * needed.
   *
   * @param element
   *            The configuration element from which the real class can be
   *            loaded at run-time; must not be <code>null</code>.
   * @param delegateAttributeName
   *            The name of the attibute or element containing the action
   *            delegate; must not be <code>null</code>.
   * @param actionId
   *            The identifier of the underlying action; may be
   *            <code>null</code>.
   * @param command
   *            The command with which the action delegate will be associated;
   *            must not be <code>null</code>.
   * @param window
   *            The workbench window in which this delegate will be active;
   *            must not be <code>null</code>.
   * @param style
   *            The image style with which the icons are associated; may be
   *            <code>null</code>.
   * @param enabledWhenExpression
   *            The name of the element containing the enabledWhen expression.
   *            This should be a child of the
   *            <code>configurationElement</code>. If this value is
   *            <code>null</code>, then there is no enablement expression
   *            (i.e., enablement will be delegated to the handler when
   *            possible).
   * @param viewId
   *            The identifier of the view to which this proxy is bound; may
   *            be <code>null</code> if this proxy is not for an
   *            {@link IViewActionDelegate}.
   */
  public ActionDelegateHandlerProxy(final IConfigurationElement element,
      final String delegateAttributeName, final String actionId,
      final ParameterizedCommand command, final IWorkbenchWindow window,
      final String style, final Expression enabledWhenExpression,
      final String viewId) {
    if (element == null) {
      throw new NullPointerException(
          "The configuration element backing a handler proxy cannot be null"); //$NON-NLS-1$
    }

    if (delegateAttributeName == null) {
      throw new NullPointerException(
          "The attribute containing the action delegate must be known"); //$NON-NLS-1$
    }

    if (window == null) {
      throw new NullPointerException(
          "The workbench window for a delegate must not be null"); //$NON-NLS-1$
    }

    this.element = element;
    this.enabledWhenExpression = enabledWhenExpression;
    this.delegateAttributeName = delegateAttributeName;
    this.window = window;
    this.command = command;
    this.actionId = actionId;
    this.style = style;
    this.viewId = viewId;
  }

  public final void addHandlerListener(final IHandlerListener handlerListener) {
    if (listenerList == null) {
      listenerList = new ListenerList(ListenerList.IDENTITY);
    }

    listenerList.add(handlerListener);
  }

  public void addState(String id, State state) {
    // TODO Auto-generated method stub

  }

  public final void dispose() {
    final IActionDelegate delegate = getDelegate();
    if (delegate instanceof IWorkbenchWindowActionDelegate) {
      final IWorkbenchWindowActionDelegate workbenchWindowDelegate = (IWorkbenchWindowActionDelegate) delegate;
      workbenchWindowDelegate.dispose();
    } else if (delegate instanceof IActionDelegate2) {
      final IActionDelegate2 delegate2 = (IActionDelegate2) delegate;
      delegate2.dispose();
    }
  }

  public final Object execute(final ExecutionEvent event) {
    final IAction action = getAction();
    if (loadDelegate() && (action != null)) {
      final Object trigger = event.getTrigger();

      // Attempt to update the selection.
      final Object applicationContext = event.getApplicationContext();
      if (applicationContext instanceof IEvaluationContext) {
        final IEvaluationContext context = (IEvaluationContext) applicationContext;
        updateDelegate(action, context);
      }

      // Decide what type of delegate we have.
      if ((delegate instanceof IActionDelegate2)
          && (trigger instanceof Event)) {
        // This supports Eclipse 2.1 to Eclipse 3.1.
        final IActionDelegate2 delegate2 = (IActionDelegate2) delegate;
        final Event triggeringEvent = (Event) trigger;
        delegate2.runWithEvent(action, triggeringEvent);
      } else if ((delegate instanceof IActionDelegateWithEvent)
          && (trigger instanceof Event)) {
        // This supports Eclipse 2.0
        final IActionDelegateWithEvent delegateWithEvent = (IActionDelegateWithEvent) delegate;
        final Event triggeringEvent = (Event) trigger;
        delegateWithEvent.runWithEvent(action, triggeringEvent);
      } else {
        delegate.run(action);
      }
    }

    return null;
  }

  /**
   * @param action
   * @param context
   */
  private void updateDelegate(final IAction action,
      final IEvaluationContext context) {
    if (action == null || delegate == null) {
      return;
    }

    if (editorDelegate != null) {
      final Object activeEditor = context
          .getVariable(ISources.ACTIVE_EDITOR_NAME);
      if (activeEditor != null) {
        editorDelegate.setActiveEditor(action,
            (IEditorPart) activeEditor);
      }
    } else if (objectDelegate != null) {
      final Object activePart = context
          .getVariable(ISources.ACTIVE_PART_NAME);
      if (activePart != null) {
        objectDelegate.setActivePart(action,
            (IWorkbenchPart) activePart);
      }
    }

    final Object selectionObject = getCurrentSelection(context);
    if (selectionObject instanceof ISelection) {
      currentSelection = (ISelection) selectionObject;
      delegate.selectionChanged(action, currentSelection);
    } else {
      currentSelection = null;
      delegate.selectionChanged(action, null);
    }
  }

  /**
   * @param context
   * @return
   */
  private Object getCurrentSelection(final IEvaluationContext context) {
    Object obj = context
        .getVariable(ISources.ACTIVE_MENU_EDITOR_INPUT_NAME);
    if (obj == null) {
      obj = context.getVariable(ISources.ACTIVE_MENU_SELECTION_NAME);
      if (obj == null) {
        obj = context
            .getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
      }
    }
    return obj;
  }

  /**
   * Retrieves the action corresponding to the currently active workbench
   * window, if any.
   *
   * @return The current action; <code>null</code> if there is no currently
   *         active workbench window.
   */
  private final CommandLegacyActionWrapper getAction() {
    if (action == null) {
      action = new CommandLegacyActionWrapper(actionId, command, style,
          window);
      action.addPropertyChangeListener(new IPropertyChangeListener() {
        public final void propertyChange(final PropertyChangeEvent event) {
          // TODO Update the state somehow.
        }
      });
    }
    return action;
  }

  /**
   * Retrieves the delegate corresponding to the currently active workbench
   * window, if any. This does not trigger loading of the delegate.
   *
   * @return The current delegate; or <code>null</code> if none.
   */
  private final IActionDelegate getDelegate() {
    return delegate;
  }

  public State getState(String stateId) {
    // TODO Auto-generated method stub
    return null;
  }

  public String[] getStateIds() {
    // TODO Auto-generated method stub
    return null;
  }

  public final void handleStateChange(final State state, final Object oldValue) {
    // TODO What should we do here?
  }

  /**
   * Initialize the action delegate by calling its lifecycle method.
   */
  private final boolean initDelegate() {
    final IWorkbenchPage page = window.getActivePage();
    final IWorkbenchPart activePart;
    final IEditorPart activeEditor;
    if (page == null) {
      activePart = null;
      activeEditor = null;
    } else {
      activePart = page.getActivePart();
      activeEditor = page.getActiveEditor();
    }
    final IActionDelegate delegate = getDelegate();
    final IAction action = getAction();

    // Check to see if the view delegate should be initialized.
    if ((viewId != null) && (page != null) && (viewDelegate != null)) {
      final IViewPart viewPart = page.findView(viewId);
      if (viewPart == null) {
        return false;
      }
    }

    // Initialize the delegate.
    final ISafeRunnable runnable = new ISafeRunnable() {
      public final void handleException(final Throwable exception) {
        // Do nothing.
      }

      public final void run() {
        // Handle IActionDelegate2
        if (delegate instanceof IActionDelegate2) {
          final IActionDelegate2 delegate2 = (IActionDelegate2) delegate;
          delegate2.init(action);
        }

        // Handle IObjectActionDelegates
        if ((objectDelegate != null) && (activePart != null)) {
          objectDelegate.setActivePart(action, activePart);
        } else if (editorDelegate != null) {
          editorDelegate.setActiveEditor(action, activeEditor);
        } else if ((viewId != null) && (page != null)
            && (viewDelegate != null)) {
          final IViewPart viewPart = page.findView(viewId);
          viewDelegate.init(viewPart);
        } else if (windowDelegate != null) {
          windowDelegate.init(window);
        }
      }
    };
    SafeRunner.run(runnable);
    return true;
  }

  public final boolean isEnabled() {
    final IHandlerService service = (IHandlerService) window
        .getService(IHandlerService.class);
    IEvaluationContext context = service.getCurrentState();
    return isEnabled(context);
  }

  public final boolean isEnabled(IEvaluationContext context) {
    final CommandLegacyActionWrapper action = getAction();
    if (enabledWhenExpression != null) {
      try {
        final EvaluationResult result = enabledWhenExpression
            .evaluate(context);
        if (result == EvaluationResult.TRUE) {
          updateDelegate(action, context);
          return (action == null)
              || action.isEnabledDisregardingCommand();
        }
      } catch (final CoreException e) {
        // We will just fall through an let it return false.
        final StringBuffer message = new StringBuffer(
            "An exception occurred while evaluating the enabledWhen expression for "); //$NON-NLS-1$
        if (element == null) {
          message.append(delegate);
        } else {
          message.append(element.getAttribute(delegateAttributeName));
        }
        message.append("' could not be loaded"); //$NON-NLS-1$
        final IStatus status = new Status(IStatus.WARNING,
            WorkbenchPlugin.PI_WORKBENCH, 0, e.getMessage(), e);
        WorkbenchPlugin.log(message.toString(), status);
      }

      return false;
    }

    updateDelegate(action, context);
    return (action == null) || action.isEnabledDisregardingCommand();
  }

  public final boolean isHandled() {
    return true;
  }

  /**
   * Checks if the declaring plugin has been loaded. This means that there
   * will be no need to delay creating the delegate.
   *
   * @return <code>true</code> if the bundle containing the delegate is
   *         already loaded -- making it safe to load the delegate.
   */
  private final boolean isSafeToLoadDelegate() {
    return false;
    // TODO This causes problem because some people expect their selections
    // to be a particular class.
    // final String bundleId = element.getNamespace();
    // return BundleUtility.isActive(bundleId);
  }

  /**
   * Loads the delegate, if possible. If the delegate is loaded, then the
   * member variables are updated accordingly.
   *
   * @return <code>true</code> if the delegate is now non-null;
   *         <code>false</code> otherwise.
   */
  private final boolean loadDelegate() {
    // Try to load the delegate, if it hasn't been loaded already.
    if (delegate == null) {
      /*
       * If this is an IViewActionDelegate, then check to see if we have a
       * view ready yet. If not, then we'll have to wait.
       */
      if (viewId != null) {
        final IWorkbenchPage activePage = window.getActivePage();
        if (activePage != null) {
          final IViewPart part = activePage.findView(viewId);
          if (part == null) {
            return false;
          }
        } else {
          return false;
        }
      }

      // Load the delegate.
      try {
        delegate = (IActionDelegate) element
            .createExecutableExtension(delegateAttributeName);
        String name = element.getDeclaringExtension()
            .getExtensionPointUniqueIdentifier();
        if ("org.eclipse.ui.actionSets".equals(name) //$NON-NLS-1$
            && delegate instanceof IWorkbenchWindowActionDelegate) {
          windowDelegate = (IWorkbenchWindowActionDelegate) delegate;
        } else if ("org.eclipse.ui.editorActions".equals(name) //$NON-NLS-1$
            && delegate instanceof IEditorActionDelegate) {
          editorDelegate = (IEditorActionDelegate) delegate;
        } else if ("org.eclipse.ui.viewActions".equals(name) //$NON-NLS-1$
            && delegate instanceof IViewActionDelegate) {
          viewDelegate = (IViewActionDelegate) delegate;
        } else if ("org.eclipse.ui.popupMenus".equals(name)) { //$NON-NLS-1$
          IConfigurationElement parent = (IConfigurationElement) element
              .getParent();
          if ("objectContribution".equals(parent.getName()) //$NON-NLS-1$
              && delegate instanceof IObjectActionDelegate) {
            objectDelegate = (IObjectActionDelegate) delegate;
          } else if (viewId == null
              && delegate instanceof IEditorActionDelegate) {
            editorDelegate = (IEditorActionDelegate) delegate;
          } else if (viewId != null
              && delegate instanceof IViewActionDelegate) {
            viewDelegate = (IViewActionDelegate) delegate;
          }
        }
        if (initDelegate()) {
          element = null;
          delegateAttributeName = null;
          return true;
        }

        delegate = null;
        objectDelegate = null;
        viewDelegate = null;
        editorDelegate = null;
        windowDelegate = null;
        return false;

      } catch (final ClassCastException e) {
        final String message = "The proxied delegate was the wrong class"; //$NON-NLS-1$
        final IStatus status = new Status(IStatus.ERROR,
            WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
        WorkbenchPlugin.log(message, status);
        return false;

      } catch (final CoreException e) {
        final String message = "The proxied delegate for '" //$NON-NLS-1$
            + element.getAttribute(delegateAttributeName)
            + "' could not be loaded"; //$NON-NLS-1$
        IStatus status = new Status(IStatus.ERROR,
            WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
        WorkbenchPlugin.log(message, status);
        return false;
      }
    }

    return true;
  }

  /**
   * Refresh the action enablement.
   */
  private final void refreshEnablement() {
    final IActionDelegate delegate = getDelegate();
    final IAction action = getAction();
    if ((delegate != null) && (action != null)) {
      delegate.selectionChanged(action, currentSelection);
    }
  }

  public void removeHandlerListener(IHandlerListener handlerListener) {
    if (listenerList != null) {
      listenerList.remove(handlerListener);

      if (listenerList.isEmpty()) {
        listenerList = null;
      }
    }
  }

  public void removeState(String stateId) {
    // TODO Auto-generated method stub

  }

  private final void selectionChanged(final ISelection selection) {
    // Update selection.
    currentSelection = selection;
    if (currentSelection == null) {
      currentSelection = StructuredSelection.EMPTY;
    }

    // The selection is passed to the delegate as-is without
    // modification. If the selection needs to be modified
    // the action contributors should do so.

    // If the delegate can be loaded, do so.
    // Otherwise, just update the enablement.
    final IActionDelegate delegate = getDelegate();
    if (delegate == null && isSafeToLoadDelegate()) {
      loadDelegate();
    }
    refreshEnablement();
  }

  public final void selectionChanged(final IWorkbenchPart part,
      final ISelection selection) {
    selectionChanged(selection);

  }

  public final void selectionChanged(final SelectionChangedEvent event) {
    final ISelection selection = event.getSelection();
    selectionChanged(selection);
  }

  public final String toString() {
    final StringBuffer buffer = new StringBuffer();
    buffer.append("ActionDelegateHandlerProxy("); //$NON-NLS-1$
    buffer.append(getDelegate());
    if (element != null) {
      buffer.append(',');
      try {
        final String className = element
            .getAttribute(delegateAttributeName);
        buffer.append(className);
      } catch (InvalidRegistryObjectException e) {
        buffer.append(actionId);
      }
    }
    buffer.append(')');
    return buffer.toString();
  }
}
TOP

Related Classes of org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy

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.