Package org.eclipse.jface.action

Source Code of org.eclipse.jface.action.ActionContributionItem

/*******************************************************************************
* Copyright (c) 2000, 2008 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.jface.action;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.jface.action.ExternalActionManager.IBindingManagerCallback;
import org.eclipse.jface.bindings.Trigger;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.IKeyLookup;
import org.eclipse.jface.bindings.keys.KeyLookupFactory;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.Util;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
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;

/**
* A contribution item which delegates to an action.
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
* @noextend This class is not intended to be subclassed by clients.
*/
public class ActionContributionItem extends ContributionItem {
  /**
   * Mode bit: Show text on tool items or buttons, even if an image is
   * present. If this mode bit is not set, text is only shown on tool items if
   * there is no image present.
   *
   * @since 3.0
   */
  public static int MODE_FORCE_TEXT = 1;

  /** a string inserted in the middle of text that has been shortened */
  private static final String ellipsis = "..."; //$NON-NLS-1$

  /**
   * Stores the result of the action. False when the action returned failure.
   */
  private Boolean result = null;

  private static boolean USE_COLOR_ICONS = true;

  /**
   * Returns whether color icons should be used in toolbars.
   *
   * @return <code>true</code> if color icons should be used in toolbars,
   *         <code>false</code> otherwise
   */
  public static boolean getUseColorIconsInToolbars() {
    return USE_COLOR_ICONS;
  }

  /**
   * Sets whether color icons should be used in toolbars.
   *
   * @param useColorIcons
   *            <code>true</code> if color icons should be used in toolbars,
   *            <code>false</code> otherwise
   */
  public static void setUseColorIconsInToolbars(boolean useColorIcons) {
    USE_COLOR_ICONS = useColorIcons;
  }

  /**
   * The presentation mode.
   */
  private int mode = 0;

  /**
   * The action.
   */
  private IAction action;

  /**
   * The listener for changes to the text of the action contributed by an
   * external source.
   */
  private final IPropertyChangeListener actionTextListener = new IPropertyChangeListener() {

    /**
     * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent event) {
      update(event.getProperty());
    }
  };

  /**
   * Remembers all images in use by this contribution item
   */
  private LocalResourceManager imageManager;

  /**
   * Listener for SWT button widget events.
   */
  private Listener buttonListener;

  /**
   * Listener for SWT menu item widget events.
   */
  private Listener menuItemListener;

  /**
   * Listener for action property change notifications.
   */
  private final IPropertyChangeListener propertyListener = new IPropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent event) {
      actionPropertyChange(event);
    }
  };

  /**
   * Listener for SWT tool item widget events.
   */
  private Listener toolItemListener;

  /**
   * The widget created for this item; <code>null</code> before creation and
   * after disposal.
   */
  private Widget widget = null;

  private Listener menuCreatorListener;

  /**
   * Creates a new contribution item from the given action. The id of the
   * action is used as the id of the item.
   *
   * @param action
   *            the action
   */
  public ActionContributionItem(IAction action) {
    super(action.getId());
    this.action = action;
  }

  /**
   * Handles a property change event on the action (forwarded by nested
   * listener).
   */
  private void actionPropertyChange(final PropertyChangeEvent e) {
    // This code should be removed. Avoid using free asyncExec

    if (isVisible() && widget != null) {
      Display display = widget.getDisplay();
      if (display.getThread() == Thread.currentThread()) {
        update(e.getProperty());
      } else {
        display.asyncExec(new Runnable() {
          public void run() {
            update(e.getProperty());
          }
        });
      }

    }
  }

  /**
   * Compares this action contribution item with another object. Two action
   * contribution items are equal if they refer to the identical Action.
   */
  public boolean equals(Object o) {
    if (!(o instanceof ActionContributionItem)) {
      return false;
    }
    return action.equals(((ActionContributionItem) o).action);
  }

  /**
   * The <code>ActionContributionItem</code> implementation of this
   * <code>IContributionItem</code> method creates an SWT
   * <code>Button</code> for the action using the action's style. If the
   * action's checked property has been set, the button is created and primed
   * to the value of the checked property.
   */
  public void fill(Composite parent) {
    if (widget == null && parent != null) {
      int flags = SWT.PUSH;
      if (action != null) {
        if (action.getStyle() == IAction.AS_CHECK_BOX) {
          flags = SWT.TOGGLE;
        }
        if (action.getStyle() == IAction.AS_RADIO_BUTTON) {
          flags = SWT.RADIO;
        }
      }

      Button b = new Button(parent, flags);
      b.setData(this);
      b.addListener(SWT.Dispose, getButtonListener());
      // Don't hook a dispose listener on the parent
      b.addListener(SWT.Selection, getButtonListener());
      if (action.getHelpListener() != null) {
        b.addHelpListener(action.getHelpListener());
      }
      widget = b;

      update(null);

      // Attach some extra listeners.
      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);
        }
      }
    }
  }

  /**
   * The <code>ActionContributionItem</code> implementation of this
   * <code>IContributionItem</code> method creates an SWT
   * <code>MenuItem</code> for the action using the action's style. If the
   * action's checked property has been set, a button is created and primed to
   * the value of the checked property. If the action's menu creator property
   * has been set, a cascading submenu is created.
   */
  public void fill(Menu parent, int index) {
    if (widget == null && parent != null) {
      int flags = SWT.PUSH;
      if (action != null) {
        int style = action.getStyle();
        if (style == IAction.AS_CHECK_BOX) {
          flags = SWT.CHECK;
        } else if (style == IAction.AS_RADIO_BUTTON) {
          flags = SWT.RADIO;
        } else if (style == IAction.AS_DROP_DOWN_MENU) {
          flags = SWT.CASCADE;
        }
      }

      MenuItem mi = null;
      if (index >= 0) {
        mi = new MenuItem(parent, flags, index);
      } else {
        mi = new MenuItem(parent, flags);
      }
      widget = mi;

      mi.setData(this);
      mi.addListener(SWT.Dispose, getMenuItemListener());
      mi.addListener(SWT.Selection, getMenuItemListener());
      if (action.getHelpListener() != null) {
        mi.addHelpListener(action.getHelpListener());
      }

      if (flags == SWT.CASCADE) {
        // just create a proxy for now, if the user shows it then
        // fill it in
        Menu subMenu = new Menu(parent);
        subMenu.addListener(SWT.Show, getMenuCreatorListener());
        subMenu.addListener(SWT.Hide, getMenuCreatorListener());
        mi.setMenu(subMenu);
      }

      update(null);

      // Attach some extra listeners.
      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);
        }
      }
    }
  }

  /**
   * The <code>ActionContributionItem</code> implementation of this ,
   * <code>IContributionItem</code> method creates an SWT
   * <code>ToolItem</code> for the action using the action's style. If the
   * action's checked property has been set, a button is created and primed to
   * the value of the checked property. If the action's menu creator property
   * has been set, a drop-down tool item is created.
   */
  public void fill(ToolBar parent, int index) {
    if (widget == null && parent != null) {
      int flags = SWT.PUSH;
      if (action != null) {
        int style = action.getStyle();
        if (style == IAction.AS_CHECK_BOX) {
          flags = SWT.CHECK;
        } else if (style == IAction.AS_RADIO_BUTTON) {
          flags = SWT.RADIO;
        } else if (style == IAction.AS_DROP_DOWN_MENU) {
          flags = SWT.DROP_DOWN;
        }
      }

      ToolItem ti = null;
      if (index >= 0) {
        ti = new ToolItem(parent, flags, index);
      } else {
        ti = new ToolItem(parent, flags);
      }
      ti.setData(this);
      ti.addListener(SWT.Selection, getToolItemListener());
      ti.addListener(SWT.Dispose, getToolItemListener());

      widget = ti;

      update(null);

      // Attach some extra listeners.
      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);
        }
      }
    }
  }

  /**
   * Returns the action associated with this contribution item.
   *
   * @return the action
   */
  public IAction getAction() {
    return action;
  }

  /**
   * Returns the listener for SWT button widget events.
   *
   * @return a listener for button events
   */
  private Listener getButtonListener() {
    if (buttonListener == null) {
      buttonListener = new Listener() {
        public void handleEvent(Event event) {
          switch (event.type) {
          case SWT.Dispose:
            handleWidgetDispose(event);
            break;
          case SWT.Selection:
            Widget ew = event.widget;
            if (ew != null) {
              handleWidgetSelection(event, ((Button) ew)
                  .getSelection());
            }
            break;
          }
        }
      };
    }
    return buttonListener;
  }

  /**
   * Returns the listener for SWT menu item widget events.
   *
   * @return a listener for menu item events
   */
  private Listener getMenuItemListener() {
    if (menuItemListener == null) {
      menuItemListener = new Listener() {
        public void handleEvent(Event event) {
          switch (event.type) {
          case SWT.Dispose:
            handleWidgetDispose(event);
            break;
          case SWT.Selection:
            Widget ew = event.widget;
            if (ew != null) {
              handleWidgetSelection(event, ((MenuItem) ew)
                  .getSelection());
            }
            break;
          }
        }
      };
    }
    return menuItemListener;
  }

  /**
   * Returns the presentation mode, which is the bitwise-or of the
   * <code>MODE_*</code> constants. The default mode setting is 0, meaning
   * that for menu items, both text and image are shown (if present), but for
   * tool items, the text is shown only if there is no image.
   *
   * @return the presentation mode settings
   *
   * @since 3.0
   */
  public int getMode() {
    return mode;
  }

  /**
   * Returns the listener for SWT tool item widget events.
   *
   * @return a listener for tool item events
   */
  private Listener getToolItemListener() {
    if (toolItemListener == null) {
      toolItemListener = new Listener() {
        public void handleEvent(Event event) {
          switch (event.type) {
          case SWT.Dispose:
            handleWidgetDispose(event);
            break;
          case SWT.Selection:
            Widget ew = event.widget;
            if (ew != null) {
              handleWidgetSelection(event, ((ToolItem) ew)
                  .getSelection());
            }
            break;
          }
        }
      };
    }
    return toolItemListener;
  }

  /**
   * Handles a widget dispose event for the widget corresponding to this item.
   */
  private void handleWidgetDispose(Event e) {
    // Check if our widget is the one being disposed.
    if (e.widget == widget) {
      // Dispose of the menu creator.
      if (action.getStyle() == IAction.AS_DROP_DOWN_MENU
          && menuCreatorCalled) {
        IMenuCreator mc = action.getMenuCreator();
        if (mc != null) {
          mc.dispose();
        }
      }

      // Unhook all of the listeners.
      action.removePropertyChangeListener(propertyListener);
      if (action != null) {
        String commandId = action.getActionDefinitionId();
        ExternalActionManager.ICallback callback = ExternalActionManager
            .getInstance().getCallback();

        if ((callback != null) && (commandId != null)) {
          callback.removePropertyChangeListener(commandId,
              actionTextListener);
        }
      }

      // Clear the widget field.
      widget = null;

      disposeOldImages();
    }
  }

  /**
   * Handles a widget selection event.
   */
  private void handleWidgetSelection(Event e, boolean selection) {

    Widget item = e.widget;
    if (item != null) {
      int style = item.getStyle();

      if ((style & (SWT.TOGGLE | SWT.CHECK)) != 0) {
        if (action.getStyle() == IAction.AS_CHECK_BOX) {
          action.setChecked(selection);
        }
      } else if ((style & SWT.RADIO) != 0) {
        if (action.getStyle() == IAction.AS_RADIO_BUTTON) {
          action.setChecked(selection);
        }
      } else if ((style & SWT.DROP_DOWN) != 0) {
        if (e.detail == 4) { // on drop-down button
          if (action.getStyle() == IAction.AS_DROP_DOWN_MENU) {
            IMenuCreator mc = action.getMenuCreator();
            menuCreatorCalled = true;
            ToolItem ti = (ToolItem) item;
            // we create the menu as a sub-menu of "dummy" so that
            // we can use
            // it in a cascading menu too.
            // If created on a SWT control we would get an SWT
            // error...
            // Menu dummy= new Menu(ti.getParent());
            // Menu m= mc.getMenu(dummy);
            // dummy.dispose();
            if (mc != null) {
              Menu m = mc.getMenu(ti.getParent());
              if (m != null) {
                // position the menu below the drop down item
                Point point = ti.getParent().toDisplay(
                    new Point(e.x, e.y));
                m.setLocation(point.x, point.y); // waiting
                                  // for SWT
                // 0.42
                m.setVisible(true);
                return; // we don't fire the action
              }
            }
          }
        }
      }

      ExternalActionManager.IExecuteCallback callback = null;
      String actionDefinitionId = action.getActionDefinitionId();
      if (actionDefinitionId != null) {
        Object obj = ExternalActionManager.getInstance()
            .getCallback();
        if (obj instanceof ExternalActionManager.IExecuteCallback) {
          callback = (ExternalActionManager.IExecuteCallback) obj;
        }
      }

      // Ensure action is enabled first.
      // See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be
      // executed while disabled.
      if (action.isEnabled()) {
        boolean trace = Policy.TRACE_ACTIONS;

        long ms = 0L;
        if (trace) {
          ms = System.currentTimeMillis();
          System.out.println("Running action: " + action.getText()); //$NON-NLS-1$
        }       
       
        IPropertyChangeListener resultListener = null;
        if (callback != null) {
          resultListener = new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
              // Check on result
              if (event.getProperty().equals(IAction.RESULT)) {
                if (event.getNewValue() instanceof Boolean) {
                  result = (Boolean) event.getNewValue();
                }
              }
            }
          };
          action.addPropertyChangeListener(resultListener);
          callback.preExecute(action, e);
        }

        action.runWithEvent(e);

        if (callback != null) {
          if (result == null || result.equals(Boolean.TRUE)) {
            callback.postExecuteSuccess(action, Boolean.TRUE);
          } else {
            callback.postExecuteFailure(action,
                new ExecutionException(action.getText()
                    + " returned failure.")); //$NON-NLS-1$
          }
        }

        if (resultListener!=null) {
          result = null;
          action.removePropertyChangeListener(resultListener);
        }
        if (trace) {
          System.out.println((System.currentTimeMillis() - ms)
              + " ms to run action: " + action.getText()); //$NON-NLS-1$
        }
      } else {
        if (callback != null) {
          callback.notEnabled(action, new NotEnabledException(action
              .getText()
              + " is not enabled.")); //$NON-NLS-1$
        }
      }
    }
  }

  /*
   * (non-Javadoc) Method declared on Object.
   */
  public int hashCode() {
    return action.hashCode();
  }

  /**
   * Returns whether the given action has any images.
   *
   * @param actionToCheck
   *            the action
   * @return <code>true</code> if the action has any images,
   *         <code>false</code> if not
   */
  private boolean hasImages(IAction actionToCheck) {
    return actionToCheck.getImageDescriptor() != null
        || actionToCheck.getHoverImageDescriptor() != null
        || actionToCheck.getDisabledImageDescriptor() != null;
  }

  /**
   * Returns whether the command corresponding to this action is active.
   */
  private boolean isCommandActive() {
    IAction actionToCheck = getAction();

    if (actionToCheck != null) {
      String commandId = actionToCheck.getActionDefinitionId();
      ExternalActionManager.ICallback callback = ExternalActionManager
          .getInstance().getCallback();

      if (callback != null) {
        return callback.isActive(commandId);
      }
    }
    return true;
  }

  /**
   * The action item implementation of this <code>IContributionItem</code>
   * method returns <code>true</code> for menu items and <code>false</code>
   * for everything else.
   */
  public boolean isDynamic() {
    if (widget instanceof MenuItem) {
      // Optimization. Only recreate the item is the check or radio style
      // has changed.
      boolean itemIsCheck = (widget.getStyle() & SWT.CHECK) != 0;
      boolean actionIsCheck = getAction() != null
          && getAction().getStyle() == IAction.AS_CHECK_BOX;
      boolean itemIsRadio = (widget.getStyle() & SWT.RADIO) != 0;
      boolean actionIsRadio = getAction() != null
          && getAction().getStyle() == IAction.AS_RADIO_BUTTON;
      return (itemIsCheck != actionIsCheck)
          || (itemIsRadio != actionIsRadio);
    }
    return false;
  }

  /*
   * (non-Javadoc) Method declared on IContributionItem.
   */
  public boolean isEnabled() {
    return action != null && action.isEnabled();
  }

  /**
   * Returns <code>true</code> if this item is allowed to enable,
   * <code>false</code> otherwise.
   *
   * @return if this item is allowed to be enabled
   * @since 2.0
   */
  protected boolean isEnabledAllowed() {
    if (getParent() == null) {
      return true;
    }
    Boolean value = getParent().getOverrides().getEnabled(this);
    return (value == null) ? true : value.booleanValue();
  }

  /**
   * The <code>ActionContributionItem</code> implementation of this
   * <code>ContributionItem</code> method extends the super implementation
   * by also checking whether the command corresponding to this action is
   * active.
   */
  public boolean isVisible() {
    return super.isVisible() && isCommandActive();
  }

  /**
   * Sets the presentation mode, which is the bitwise-or of the
   * <code>MODE_*</code> constants.
   *
   * @param mode
   *            the presentation mode settings
   *
   * @since 3.0
   */
  public void setMode(int mode) {
    this.mode = mode;
    update();
  }

  /**
   * The action item implementation of this <code>IContributionItem</code>
   * method calls <code>update(null)</code>.
   */
  public final void update() {
    update(null);
  }

  /**
   * Synchronizes the UI with the given property.
   *
   * @param propertyName
   *            the name of the property, or <code>null</code> meaning all
   *            applicable properties
   */
  public void update(String propertyName) {
    if (widget != null) {
      // determine what to do
      boolean textChanged = propertyName == null
          || propertyName.equals(IAction.TEXT);
      boolean imageChanged = propertyName == null
          || propertyName.equals(IAction.IMAGE);
      boolean tooltipTextChanged = propertyName == null
          || propertyName.equals(IAction.TOOL_TIP_TEXT);
      boolean enableStateChanged = propertyName == null
          || propertyName.equals(IAction.ENABLED)
          || propertyName
              .equals(IContributionManagerOverrides.P_ENABLED);
      boolean checkChanged = (action.getStyle() == IAction.AS_CHECK_BOX || action
          .getStyle() == IAction.AS_RADIO_BUTTON)
          && (propertyName == null || propertyName
              .equals(IAction.CHECKED));

      if (widget instanceof ToolItem) {
        ToolItem ti = (ToolItem) widget;
        String text = action.getText();
        // the set text is shown only if there is no image or if forced
        // by MODE_FORCE_TEXT
        boolean showText = text != null
            && ((getMode() & MODE_FORCE_TEXT) != 0 || !hasImages(action));

        // only do the trimming if the text will be used
        if (showText && text != null) {
          text = Action.removeAcceleratorText(text);
          text = Action.removeMnemonics(text);
        }

        if (textChanged) {
          String textToSet = showText ? text : ""; //$NON-NLS-1$
          boolean rightStyle = (ti.getParent().getStyle() & SWT.RIGHT) != 0;
          if (rightStyle || !ti.getText().equals(textToSet)) {
            // In addition to being required to update the text if
            // it
            // gets nulled out in the action, this is also a
            // workaround
            // for bug 50151: Using SWT.RIGHT on a ToolBar leaves
            // blank space
            ti.setText(textToSet);
          }
        }

        if (imageChanged) {
          // only substitute a missing image if it has no text
          updateImages(!showText);
        }

        if (tooltipTextChanged || textChanged) {
          String toolTip = action.getToolTipText();
          if ((toolTip == null) || (toolTip.length() == 0)) {
            toolTip = text;
          }

          ExternalActionManager.ICallback callback = ExternalActionManager
              .getInstance().getCallback();
          String commandId = action.getActionDefinitionId();
          if ((callback != null) && (commandId != null)
              && (toolTip != null)) {
            String acceleratorText = callback
                .getAcceleratorText(commandId);
            if (acceleratorText != null
                && acceleratorText.length() != 0) {
              toolTip = JFaceResources.format(
                  "Toolbar_Tooltip_Accelerator", //$NON-NLS-1$
                  new Object[] { toolTip, acceleratorText });
            }
          }

          // if the text is showing, then only set the tooltip if
          // different
          if (!showText || toolTip != null && !toolTip.equals(text)) {
            ti.setToolTipText(toolTip);
          } else {
            ti.setToolTipText(null);
          }
        }

        if (enableStateChanged) {
          boolean shouldBeEnabled = action.isEnabled()
              && isEnabledAllowed();

          if (ti.getEnabled() != shouldBeEnabled) {
            ti.setEnabled(shouldBeEnabled);
          }
        }

        if (checkChanged) {
          boolean bv = action.isChecked();

          if (ti.getSelection() != bv) {
            ti.setSelection(bv);
          }
        }
        return;
      }

      if (widget instanceof MenuItem) {
        MenuItem mi = (MenuItem) widget;

        if (textChanged) {
          int accelerator = 0;
          String acceleratorText = null;
          IAction updatedAction = getAction();
          String text = null;
          accelerator = updatedAction.getAccelerator();
          ExternalActionManager.ICallback callback = ExternalActionManager
              .getInstance().getCallback();

          // Block accelerators that are already in use.
          if ((accelerator != 0) && (callback != null)
              && (callback.isAcceleratorInUse(accelerator))) {
            accelerator = 0;
          }

          /*
           * Process accelerators on GTK in a special way to avoid Bug
           * 42009. We will override the native input method by
           * allowing these reserved accelerators to be placed on the
           * menu. We will only do this for "Ctrl+Shift+[0-9A-FU]".
           */
          final String commandId = updatedAction
              .getActionDefinitionId();
          if ((Util.isGtk()) && (callback instanceof IBindingManagerCallback)
              && (commandId != null)) {
            final IBindingManagerCallback bindingManagerCallback = (IBindingManagerCallback) callback;
            final IKeyLookup lookup = KeyLookupFactory.getDefault();
            final TriggerSequence[] triggerSequences = bindingManagerCallback
                .getActiveBindingsFor(commandId);
            for (int i = 0; i < triggerSequences.length; i++) {
              final TriggerSequence triggerSequence = triggerSequences[i];
              final Trigger[] triggers = triggerSequence
                  .getTriggers();
              if (triggers.length == 1) {
                final Trigger trigger = triggers[0];
                if (trigger instanceof KeyStroke) {
                  final KeyStroke currentKeyStroke = (KeyStroke) trigger;
                  final int currentNaturalKey = currentKeyStroke
                      .getNaturalKey();
                  if ((currentKeyStroke.getModifierKeys() == (lookup
                      .getCtrl() | lookup.getShift()))
                      && ((currentNaturalKey >= '0' && currentNaturalKey <= '9')
                          || (currentNaturalKey >= 'A' && currentNaturalKey <= 'F') || (currentNaturalKey == 'U'))) {
                    accelerator = currentKeyStroke
                        .getModifierKeys()
                        | currentNaturalKey;
                    acceleratorText = triggerSequence
                        .format();
                    break;
                  }
                }
              }
            }
          }

          if (accelerator == 0) {
            if ((callback != null) && (commandId != null)) {
              acceleratorText = callback
                  .getAcceleratorText(commandId);
            }
          }

          IContributionManagerOverrides overrides = null;

          if (getParent() != null) {
            overrides = getParent().getOverrides();
          }

          if (overrides != null) {
            text = getParent().getOverrides().getText(this);
          }

          mi.setAccelerator(accelerator);

          if (text == null) {
            text = updatedAction.getText();
          }

          if (text != null && acceleratorText == null) {
            // use extracted accelerator text in case accelerator
            // cannot be fully represented in one int (e.g.
            // multi-stroke keys)
            acceleratorText = LegacyActionTools
                .extractAcceleratorText(text);
            if (acceleratorText == null && accelerator != 0) {
              acceleratorText = Action
                  .convertAccelerator(accelerator);
            }
          }

          if (text == null) {
            text = ""; //$NON-NLS-1$
          } else {
            text = Action.removeAcceleratorText(text);
          }

          if (acceleratorText == null) {
            mi.setText(text);
          } else {
            mi.setText(text + '\t' + acceleratorText);
          }
        }

        if (imageChanged) {
          updateImages(false);
        }

        if (enableStateChanged) {
          boolean shouldBeEnabled = action.isEnabled()
              && isEnabledAllowed();

          if (mi.getEnabled() != shouldBeEnabled) {
            mi.setEnabled(shouldBeEnabled);
          }
        }

        if (checkChanged) {
          boolean bv = action.isChecked();

          if (mi.getSelection() != bv) {
            mi.setSelection(bv);
          }
        }

        return;
      }

      if (widget instanceof Button) {
        Button button = (Button) widget;

        if (imageChanged) {
          updateImages(false);
        }

        if (textChanged) {
          String text = action.getText();
          boolean showText = text != null && ((getMode() & MODE_FORCE_TEXT) != 0 || !hasImages(action));
          // only do the trimming if the text will be used
          if (showText) {
            text = Action.removeAcceleratorText(text);
          }
          String textToSet = showText ? text : ""; //$NON-NLS-1$
          button.setText(textToSet);
        }

        if (tooltipTextChanged) {
          button.setToolTipText(action.getToolTipText());
        }

        if (enableStateChanged) {
          boolean shouldBeEnabled = action.isEnabled()
              && isEnabledAllowed();

          if (button.getEnabled() != shouldBeEnabled) {
            button.setEnabled(shouldBeEnabled);
          }
        }

        if (checkChanged) {
          boolean bv = action.isChecked();

          if (button.getSelection() != bv) {
            button.setSelection(bv);
          }
        }
        return;
      }
    }
  }

  /**
   * Updates the images for this action.
   *
   * @param forceImage
   *            <code>true</code> if some form of image is compulsory, and
   *            <code>false</code> if it is acceptable for this item to have
   *            no image
   * @return <code>true</code> if there are images for this action,
   *         <code>false</code> if not
   */
  private boolean updateImages(boolean forceImage) {

    ResourceManager parentResourceManager = JFaceResources.getResources();

    if (widget instanceof ToolItem) {
      if (USE_COLOR_ICONS) {
        ImageDescriptor image = action.getHoverImageDescriptor();
        if (image == null) {
          image = action.getImageDescriptor();
        }
        ImageDescriptor disabledImage = action
            .getDisabledImageDescriptor();

        // Make sure there is a valid image.
        if (image == null && forceImage) {
          image = ImageDescriptor.getMissingImageDescriptor();
        }

        LocalResourceManager localManager = new LocalResourceManager(
            parentResourceManager);

        // performance: more efficient in SWT to set disabled and hot
        // image before regular image
        ((ToolItem) widget)
            .setDisabledImage(disabledImage == null ? null
                : localManager
                    .createImageWithDefault(disabledImage));
        ((ToolItem) widget).setImage(image == null ? null
            : localManager.createImageWithDefault(image));

        disposeOldImages();
        imageManager = localManager;

        return image != null;
      }
      ImageDescriptor image = action.getImageDescriptor();
      ImageDescriptor hoverImage = action.getHoverImageDescriptor();
      ImageDescriptor disabledImage = action.getDisabledImageDescriptor();

      // If there is no regular image, but there is a hover image,
      // convert the hover image to gray and use it as the regular image.
      if (image == null && hoverImage != null) {
        image = ImageDescriptor.createWithFlags(action
            .getHoverImageDescriptor(), SWT.IMAGE_GRAY);
      } else {
        // If there is no hover image, use the regular image as the
        // hover image,
        // and convert the regular image to gray
        if (hoverImage == null && image != null) {
          hoverImage = image;
          image = ImageDescriptor.createWithFlags(action
              .getImageDescriptor(), SWT.IMAGE_GRAY);
        }
      }

      // Make sure there is a valid image.
      if (hoverImage == null && image == null && forceImage) {
        image = ImageDescriptor.getMissingImageDescriptor();
      }

      // Create a local resource manager to remember the images we've
      // allocated for this tool item
      LocalResourceManager localManager = new LocalResourceManager(
          parentResourceManager);

      // performance: more efficient in SWT to set disabled and hot image
      // before regular image
      ((ToolItem) widget).setDisabledImage(disabledImage == null ? null
          : localManager.createImageWithDefault(disabledImage));
      ((ToolItem) widget).setHotImage(hoverImage == null ? null
          : localManager.createImageWithDefault(hoverImage));
      ((ToolItem) widget).setImage(image == null ? null : localManager
          .createImageWithDefault(image));

      // Now that we're no longer referencing the old images, clear them
      // out.
      disposeOldImages();
      imageManager = localManager;

      return image != null;
    } else if (widget instanceof Item || widget instanceof Button) {

      // Use hover image if there is one, otherwise use regular image.
      ImageDescriptor image = action.getHoverImageDescriptor();
      if (image == null) {
        image = action.getImageDescriptor();
      }
      // Make sure there is a valid image.
      if (image == null && forceImage) {
        image = ImageDescriptor.getMissingImageDescriptor();
      }

      // Create a local resource manager to remember the images we've
      // allocated for this widget
      LocalResourceManager localManager = new LocalResourceManager(
          parentResourceManager);

      if (widget instanceof Item) {
        ((Item) widget).setImage(image == null ? null : localManager
            .createImageWithDefault(image));
      } else if (widget instanceof Button) {
        ((Button) widget).setImage(image == null ? null : localManager
            .createImageWithDefault(image));
      }

      // Now that we're no longer referencing the old images, clear them
      // out.
      disposeOldImages();
      imageManager = localManager;

      return image != null;
    }
    return false;
  }

  /**
   * Dispose any images allocated for this contribution item
   */
  private void disposeOldImages() {
    if (imageManager != null) {
      imageManager.dispose();
      imageManager = null;
    }
  }

  /**
   * Shorten the given text <code>t</code> so that its length doesn't exceed
   * the width of the given ToolItem.The default implementation replaces
   * characters in the center of the original string with an ellipsis ("...").
   * Override if you need a different strategy.
   *
   * @param textValue
   *            the text to shorten
   * @param item
   *            the tool item the text belongs to
   * @return the shortened string
   *
   */
  protected String shortenText(String textValue, ToolItem item) {
    if (textValue == null) {
      return null;
    }

    GC gc = new GC(item.getParent());

    int maxWidth = item.getImage().getBounds().width * 4;

    if (gc.textExtent(textValue).x < maxWidth) {
      gc.dispose();
      return textValue;
    }

    for (int i = textValue.length(); i > 0; i--) {
      String test = textValue.substring(0, i);
      test = test + ellipsis;
      if (gc.textExtent(test).x < maxWidth) {
        gc.dispose();
        return test;
      }

    }
    gc.dispose();
    // If for some reason we fall through abort
    return textValue;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.action.ContributionItem#dispose()
   */
  public void dispose() {
    if (widget != null) {
      widget.dispose();
      widget = null;
    }
    holdMenu = null;
  }
 
  /**
   * Handle show and hide on the proxy menu for IAction.AS_DROP_DOWN_MENU
   * actions.
   *
   * @return the appropriate listener
   * @since 3.4
   */
  private Listener getMenuCreatorListener() {
    if (menuCreatorListener == null) {
      menuCreatorListener = new Listener() {
        public void handleEvent(Event event) {
          switch (event.type) {
          case SWT.Show:
            handleShowProxy((Menu) event.widget);
            break;
          case SWT.Hide:
            handleHideProxy((Menu) event.widget);
            break;
          }
        }
      };
    }
    return menuCreatorListener;
  }
 
  /**
   * This is the easiest way to hold the menu until we can swap it in to the
   * proxy.
   */
  private Menu holdMenu = null;

  private boolean menuCreatorCalled = false;
 
  /**
   * The proxy menu is being shown, we better get the real menu.
   *
   * @param proxy
   *            the proxy menu
   * @since 3.4
   */
  private void handleShowProxy(Menu proxy) {
    proxy.removeListener(SWT.Show, getMenuCreatorListener());
    IMenuCreator mc = action.getMenuCreator();
    menuCreatorCalled  = true;
    if (mc == null) {
      return;
    }
    holdMenu = mc.getMenu(proxy.getParentMenu());
    if (holdMenu == null) {
      return;
    }
    copyMenu(holdMenu, proxy);
  }

  /**
   * Create MenuItems in the proxy menu that can execute the real menu items
   * if selected. Create proxy menus for any real item submenus.
   *
   * @param realMenu
   *            the real menu to copy from
   * @param proxy
   *            the proxy menu to populate
   * @since 3.4
   */
  private void copyMenu(Menu realMenu, Menu proxy) {
    if (realMenu.isDisposed() || proxy.isDisposed()) {
      return;
    }
   
    // we notify the real menu so it can populate itself if it was
    // listening for SWT.Show
    realMenu.notifyListeners(SWT.Show, null);

    final Listener passThrough = new Listener() {
      public void handleEvent(Event event) {
        if (!event.widget.isDisposed()) {
          Widget realItem = (Widget) event.widget.getData();
          if (!realItem.isDisposed()) {
            int style = event.widget.getStyle();
            if (event.type == SWT.Selection
                && ((style & (SWT.TOGGLE | SWT.CHECK | SWT.RADIO)) != 0)
                && realItem instanceof MenuItem) {
              ((MenuItem) realItem)
                  .setSelection(((MenuItem) event.widget)
                      .getSelection());
            }
            event.widget = realItem;
            realItem.notifyListeners(event.type, event);
          }
        }
      }
    };

    MenuItem[] items = realMenu.getItems();
    for (int i = 0; i < items.length; i++) {
      final MenuItem realItem = items[i];
      final MenuItem proxyItem = new MenuItem(proxy, realItem.getStyle());
      proxyItem.setData(realItem);
      proxyItem.setAccelerator(realItem.getAccelerator());
      proxyItem.setEnabled(realItem.getEnabled());
      proxyItem.setImage(realItem.getImage());
      proxyItem.setSelection(realItem.getSelection());
      proxyItem.setText(realItem.getText());

      // pass through any events
      proxyItem.addListener(SWT.Selection, passThrough);
      proxyItem.addListener(SWT.Arm, passThrough);
      proxyItem.addListener(SWT.Help, passThrough);

      final Menu itemMenu = realItem.getMenu();
      if (itemMenu != null) {
        // create a proxy for any sub menu items
        final Menu subMenu = new Menu(proxy);
        subMenu.setData(itemMenu);
        proxyItem.setMenu(subMenu);
        subMenu.addListener(SWT.Show, new Listener() {
          public void handleEvent(Event event) {
            event.widget.removeListener(SWT.Show, this);
            if (event.type == SWT.Show) {
              copyMenu(itemMenu, subMenu);
            }
          }
        });
        subMenu.addListener(SWT.Help, passThrough);
        subMenu.addListener(SWT.Hide, passThrough);
      }
    }
  }
 
  /**
   * The proxy menu is being hidden, so we need to make it go away.
   *
   * @param proxy
   *            the proxy menu
   * @since 3.4
   */
  private void handleHideProxy(final Menu proxy) {
    proxy.removeListener(SWT.Hide, getMenuCreatorListener());
    proxy.getDisplay().asyncExec(new Runnable() {
      public void run() {
        if (!proxy.isDisposed()) {
          MenuItem parentItem = proxy.getParentItem();
          proxy.dispose();
          parentItem.setMenu(holdMenu);
        }
        if (holdMenu != null && !holdMenu.isDisposed()) {
          holdMenu.notifyListeners(SWT.Hide, null);
        }
        holdMenu = null;
      }
    });
  }
 
  /**
   * Return the widget associated with this contribution item. It should not
   * be cached, as it can be disposed and re-created by its containing
   * ContributionManager, which controls all of the widgets lifecycle methods.
   * <p>
   * This can be used to set layout data on the widget if appropriate. The
   * actual type of the widget can be any valid control for this
   * ContributionItem's current ContributionManager.
   * </p>
   *
   * @return the widget, or <code>null</code> depending on the lifecycle.
   * @since 3.4
   */
  public Widget getWidget() {
    return widget;
  }
}
TOP

Related Classes of org.eclipse.jface.action.ActionContributionItem

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.