Package org.eclipse.ui.internal.menus

Source Code of org.eclipse.ui.internal.menus.PulldownDelegateWidgetProxy$MenuLoader

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

import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.CommandException;
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.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.menus.IWidget;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.services.IServiceLocator;

/**
* <p>
* A proxy for a {@link IWorkbenchWindowPulldownDelegate} on a pulldown action
* set action. This delays the class loading until the delegate is really asked
* for information. Asking a proxy for anything (except disposing) will cause
* the proxy to instantiate the proxied delegate.
* </p>
* <p>
* This class is not intended for use outside of the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*/
final class PulldownDelegateWidgetProxy implements IWidget {

  /**
   * A wrapper for loading the menu that defends against possible exceptions
   * triggered outside of the workbench.
   */
  private static final class MenuLoader implements ISafeRunnable {

    /**
     * The parent for the menu to be created. This value is
     * <code>null</code> if the parent is a menu.
     */
    private final Control control;

    /**
     * The delegate from which to load the menu.
     */
    private final IWorkbenchWindowPulldownDelegate delegate;

    /**
     * The loaded menu. This value is <code>null</code> if the load
     * failed, or if it hasn't been loaded yet.
     */
    private Menu menu = null;

    /**
     * The parent for the menu to be created. This value is
     * <code>null</code> if the parent is a control.
     */
    private final Menu parent;

    /**
     * Constructs a new instance of <code>MenuLoader</code>
     *
     * @param delegate
     *            The delegate from which the menu will be loaded; this
     *            value must not be <code>null</code>.
     * @param parent
     *            The parent of the menu to be loaded; this value must not
     *            be <code>null</code>.
     */
    private MenuLoader(final IWorkbenchWindowPulldownDelegate delegate,
        final Control parent) {
      this.delegate = delegate;
      this.parent = null;
      this.control = parent;
    }

    /**
     * Constructs a new instance of <code>MenuLoader</code>
     *
     * @param delegate
     *            The delegate from which the menu will be loaded; this
     *            value must not be <code>null</code>.
     * @param parent
     *            The parent of the menu to be loaded; this value must not
     *            be <code>null</code>.
     */
    private MenuLoader(final IWorkbenchWindowPulldownDelegate2 delegate,
        final Menu parent) {
      this.delegate = delegate;
      this.parent = parent;
      this.control = null;
    }

    /**
     * Returns the menu loaded, if any.
     *
     * @return the loaded menu, or <code>null</code> if none.
     */
    private Menu getMenu() {
      return menu;
    }

    /**
     * @see ISafeRunnable#handleException(java.lang.Throwable)
     */
    public void handleException(Throwable exception) {
      // Do nothing
    }

    /**
     * @see ISafeRunnable#run()
     */
    public void run() throws Exception {
      if (parent == null) {
        menu = delegate.getMenu(control);
      } else {
        menu = ((IWorkbenchWindowPulldownDelegate2) delegate)
            .getMenu(parent);
      }
    }
  }

  /**
   * The command to execute when the pulldown delegate appears in a tool bar,
   * and the arrow is <em>not</em> clicked. This also carries a help context
   * identifier. This value must be <code>null</code>.
   */
  private final ParameterizedCommand command;

  /**
   * The configuration element from which the delegate 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 configurationElement;

  /**
   * The real delegate. This value is <code>null</code> until the proxy is
   * forced to load the real delegate. At this point, the configuration
   * element is converted, nulled out, and this delegate gains a reference.
   */
  private IWorkbenchWindowPulldownDelegate delegate = null;

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

  private final DisposeListener disposeListener = new DisposeListener() {
    public void widgetDisposed(DisposeEvent e) {
      if (e.widget == widget) {
        dispose();
        widget = null;

        // TODO Is this necessary?
        // disposeOldImages();
      }
    }
  };

  /**
   * The service locator from which a handler service can be retrieved. This
   * is needed if the pulldown appears in the tool bar, and the drop-down
   * arrow is <em>not</em> clicked. This value must not be <code>null</code>.
   */
  private final IServiceLocator locator;

  private final Listener selectionListener = new Listener() {
    public final void handleEvent(final Event event) {
      final Widget item = event.widget;
      if (item == null) {
        return;
      }

      final int style = item.getStyle();
      if (((style & SWT.DROP_DOWN) != 0) && (event.detail == SWT.ARROW)
          && (item instanceof ToolItem)) {
        // Create the submenu.
        final ToolItem toolItem = (ToolItem) item;
        final ToolBar toolBar = toolItem.getParent();
        if (loadDelegate()
            && (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
          final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
          final MenuLoader loader = new MenuLoader(delegate2, toolBar);
          SafeRunner.run(loader);
          final Menu subMenu = loader.getMenu();
          if (subMenu != null) {
            // position the menu below the drop down item
            final Rectangle bounds = toolItem.getBounds();
            final Point location = toolBar.toDisplay(new Point(
                bounds.x, bounds.y + bounds.height));
            subMenu.setLocation(location);
            subMenu.setVisible(true);
            return; // we don't fire the command
          }
        }
      }

      final IHandlerService service = (IHandlerService) locator
          .getService(IHandlerService.class);
      try {
        service.executeCommand(command, event);
      } catch (final CommandException e) {
        /*
         * TODO There should be an API on IHandlerService that handles
         * the exceptions.
         */
      }
    }

  };

  /**
   * The widget created for this pulldown delegate. If this proxy has not been
   * asked to fill or it has been disposed, then this value is
   * <code>null</code>.
   */
  private Widget widget = null;

  /**
   * Constructs a new instance of <code>PulldownDelegateWidgetProxy</code>
   * with all the information it needs to try to avoid loading until it is
   * needed.
   *
   * @param configurationElement
   *            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 delegate;
   *            must not be <code>null</code>.
   * @param command
   *            The command to execute if this the pulldown is not shown; must
   *            not be <code>null</code>.
   * @param locator
   *            A service locator from which a handler service can be
   *            retrieved; must not be <code>null</code>.
   */
  public PulldownDelegateWidgetProxy(
      final IConfigurationElement configurationElement,
      final String delegateAttributeName,
      final ParameterizedCommand command, final IServiceLocator locator) {
    if (configurationElement == 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 handler class must be known"); //$NON-NLS-1$
    }

    if (command == null) {
      throw new NullPointerException("The command cannot be null"); //$NON-NLS-1$
    }

    this.configurationElement = configurationElement;
    this.delegateAttributeName = delegateAttributeName;
    this.command = command;
    this.locator = locator;
  }

  /**
   * Passes the dipose on to the proxied handler, if it has been loaded.
   */
  public final void dispose() {
    if (delegate != null) {
      delegate.dispose();
    }
  }

  public final void fill(final Composite parent) {
    // This does not need to be supported.
  }

  public final void fill(CoolBar parent, final int index) {
    // This does not need to be supported.
  }

  public final void fill(final Menu parent, final int index) {
    if ((widget != null) || (parent == null)) {
      return;
    }

    // Create the menu item.
    final MenuItem menuItem;
    if (index >= 0) {
      menuItem = new MenuItem(parent, SWT.CASCADE, index);
    } else {
      menuItem = new MenuItem(parent, SWT.CASCADE);
    }
    menuItem.setData(this);
    widget = menuItem;

    // Create the submenu.
    if (loadDelegate()
        && (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
      final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
      final MenuLoader loader = new MenuLoader(delegate2, parent);
      SafeRunner.run(loader);
      final Menu subMenu = loader.getMenu();
      if (subMenu != null) {
        menuItem.setMenu(subMenu);
      }
    }

    menuItem.addDisposeListener(disposeListener);
    menuItem.addListener(SWT.Selection, selectionListener);

    // TODO Needs a way to be linked to a command.
    // if (action.getHelpListener() != null)
    // menuItem.addHelpListener(action.getHelpListener());

    // TODO Needs a way of updating itself
    // update(null);
  }

  public final void fill(final ToolBar parent, final int index) {
    if ((widget != null) && (parent == null)) {
      return;
    }

    final ToolItem toolItem;
    if (index >= 0) {
      toolItem = new ToolItem(parent, SWT.DROP_DOWN, index);
    } else {
      toolItem = new ToolItem(parent, SWT.DROP_DOWN);
    }
    toolItem.setData(this);
    widget = toolItem;

    // Attach some listeners.
    toolItem.addDisposeListener(disposeListener);
    toolItem.addListener(SWT.Selection, selectionListener);

    // TODO Needs a way to be linked to a command.
    // toolItem.addListener(SWT.Selection, getToolItemListener());
    // action.addPropertyChangeListener(propertyListener);
    // if (action != null) {
    // String commandId = action.getActionDefinitionId();
    // ExternalActionManager.ICallback callback = ExternalActionManager
    // .getInstance().getCallback();
    //
    // if ((callback != null) && (commandId != null)) {
    // callback.addPropertyChangeListener(commandId,
    // actionTextListener);
    // }
    // }

    // TODO Needs a way of updating itself
    // update(null);
  }

  /**
   * 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() {
    if (delegate == null) {
      // Load the handler.
      try {
        delegate = (IWorkbenchWindowPulldownDelegate) configurationElement
            .createExecutableExtension(delegateAttributeName);
        configurationElement = null;
        return true;

      } 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 '" + configurationElement.getAttribute(delegateAttributeName) //$NON-NLS-1$
            + "' 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;
  }

  public final String toString() {
    if (delegate == null) {
      return configurationElement.getAttribute(delegateAttributeName);
    }

    return delegate.toString();
  }
}
TOP

Related Classes of org.eclipse.ui.internal.menus.PulldownDelegateWidgetProxy$MenuLoader

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.