de.walware.ecommons.ui.actions.HandlerContributionItem.java Source code

Java tutorial

Introduction

Here is the source code for de.walware.ecommons.ui.actions.HandlerContributionItem.java

Source

/*=============================================================================#
 # Copyright (c) 2006-2015 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
 #     Stephan Wahlbrink - modified to use handlers
 #=============================================================================*/

package de.walware.ecommons.ui.actions;

import java.util.Collections;
import java.util.Map;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.HandlerEvent;
import org.eclipse.core.commands.IHandler2;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.bindings.BindingManagerEvent;
import org.eclipse.jface.bindings.IBindingManagerListener;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.resource.DeviceResourceException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
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.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.commands.ICommandImageService;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.commands.IElementReference;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.help.IWorkbenchHelpSystem;
import org.eclipse.ui.internal.services.IWorkbenchLocationService;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.menus.UIElement;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.statushandlers.StatusManager;

import de.walware.ecommons.ui.SharedUIResources;
import de.walware.ecommons.ui.util.MenuUtil;

/**
 * A contribution item which delegates to a handler of a command (not using all service).
 * It was created as workaround for toolbars in views (wrong enablement when lost focus).
 * <p>
 * It currently supports placement in menus and toolbars.
 * </p>
 * <p>
 * This class may be instantiated; it is not intended to be subclassed.
 * </p>
 */
public class HandlerContributionItem extends ContributionItem {

    public static final String NO_COMMAND_ID = "NO_COMMAND"; //$NON-NLS-1$

    /**
     * A push button tool item or menu item.
     */
    public static final int STYLE_PUSH = SWT.PUSH;

    /**
     * A checked tool item or menu item.
     */
    public static final int STYLE_CHECK = SWT.CHECK;

    /**
     * A radio-button style menu item.
     */
    public static final int STYLE_RADIO = SWT.RADIO;

    /**
     * A ToolBar pulldown item.
     */
    public static final int STYLE_PULLDOWN = SWT.DROP_DOWN;

    /**
     * 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.4
     */
    public static final int MODE_FORCE_TEXT = 1;

    private static final int MODE_NO_COMMAND = 1 << 28;

    private static final int MODE_CALLBACK_CALL = 1 << 24;
    private static final int MODE_CALLBACK_EXPL = 1 << 25;

    private LocalResourceManager localResourceManager;

    private Listener menuItemListener;

    private Widget widget;

    private IMenuService menuService;

    private ICommandService commandService;
    private IHandlerService handlerService;
    private IBindingService bindingService;

    protected final Display display;

    private ParameterizedCommand command;
    private IHandler2 commandHandler;

    private ImageDescriptor icon;

    private String label;

    private String tooltip;

    private ImageDescriptor disabledIcon;

    private ImageDescriptor hoverIcon;

    private String mnemonic;

    private IElementReference elementRef;

    private boolean checkedState;

    private int style;

    private IHandlerListener commandListener;

    private String dropDownMenuOverride;

    private IWorkbenchHelpSystem workbenchHelpSystem;

    private String helpContextId;

    private int mode = 0;

    private boolean visibleEnabled;

    // items contributed
    private String contributedLabel;

    private String contributedTooltip;

    private ImageDescriptor contributedIcon;

    private ImageDescriptor contributedDisabledIcon;

    private ImageDescriptor contributedHoverIcon;

    private IServiceLocator serviceLocator;

    private final UIElement callback;

    private final IBindingManagerListener bindingManagerListener = new IBindingManagerListener() {
        @Override
        public void bindingManagerChanged(final BindingManagerEvent event) {
            if (event.isActiveBindingsChanged() && event.isActiveBindingsChangedFor(getCommand())) {
                update();
            }
        }
    };

    /**
     * Create a CommandContributionItem to place in a ContributionManager.
     * 
     * @param contributionParameters
     *            paramters necessary to render this contribution item.
     */
    public HandlerContributionItem(final CommandContributionItemParameter contributionParameters,
            final IHandler2 handler) {
        super(contributionParameters.id);

        this.contributedIcon = this.icon = contributionParameters.icon;
        this.contributedTooltip = this.tooltip = contributionParameters.tooltip;
        this.contributedDisabledIcon = this.disabledIcon = contributionParameters.disabledIcon;
        this.contributedHoverIcon = this.hoverIcon = contributionParameters.hoverIcon;
        this.contributedLabel = this.label = contributionParameters.label;
        this.mnemonic = contributionParameters.mnemonic;
        this.style = contributionParameters.style;
        this.helpContextId = contributionParameters.helpContextId;
        this.visibleEnabled = contributionParameters.visibleEnabled;
        this.serviceLocator = contributionParameters.serviceLocator;

        try {
            menuService = (IMenuService) serviceLocator.getService(IMenuService.class);
        } catch (final NullPointerException e) {
        }
        commandService = (ICommandService) serviceLocator.getService(ICommandService.class);
        handlerService = (IHandlerService) serviceLocator.getService(IHandlerService.class);
        bindingService = (IBindingService) serviceLocator.getService(IBindingService.class);
        final IWorkbenchLocationService workbenchLocationService = (IWorkbenchLocationService) serviceLocator
                .getService(IWorkbenchLocationService.class);
        display = workbenchLocationService.getWorkbench().getDisplay();

        createCommand(contributionParameters.commandId, contributionParameters.parameters);
        commandHandler = handler;

        callback = (handler instanceof IElementUpdater) ? new UIElement(contributionParameters.serviceLocator) {

            private boolean beginCallback() {
                if ((mode & MODE_NO_COMMAND) != 0) {
                    mode |= MODE_CALLBACK_CALL;
                    return true;
                }
                if (command.getCommand().getHandler() == commandHandler) {
                    mode |= MODE_CALLBACK_CALL;
                    return true;
                }
                return false;
            }

            private void endCallback() {
                mode &= ~MODE_CALLBACK_CALL;
            }

            @Override
            public void setChecked(final boolean checked) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setChecked(checked);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setDisabledIcon(final ImageDescriptor desc) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setDisabledIcon(desc);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setHoverIcon(final ImageDescriptor desc) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setHoverIcon(desc);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setIcon(final ImageDescriptor desc) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setIcon(desc);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setText(final String text) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setText(text);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setTooltip(final String text) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.setTooltip(text);
                    } finally {
                        endCallback();
                    }
                }
            }

            @Override
            public void setDropDownId(final String id) {
                if (beginCallback()) {
                    try {
                        HandlerContributionItem.this.dropDownMenuOverride = id;
                    } finally {
                        endCallback();
                    }
                }
            }
        } : null;

        if (command != null) {
            setImages(contributionParameters.serviceLocator, contributionParameters.iconStyle);
        }
    }

    protected IServiceLocator getServiceLocator() {
        return this.serviceLocator;
    }

    private void setImages(final IServiceLocator locator, final String iconStyle) {
        if (icon == null && command != null) {
            final ICommandImageService service = (ICommandImageService) locator
                    .getService(ICommandImageService.class);
            icon = service.getImageDescriptor(command.getId(), ICommandImageService.TYPE_DEFAULT, iconStyle);
            disabledIcon = service.getImageDescriptor(command.getId(), ICommandImageService.TYPE_DISABLED,
                    iconStyle);
            hoverIcon = service.getImageDescriptor(command.getId(), ICommandImageService.TYPE_HOVER, iconStyle);

            if (contributedIcon == null) {
                contributedIcon = icon;
            }
            if (contributedDisabledIcon == null) {
                contributedDisabledIcon = disabledIcon;
            }
            if (contributedHoverIcon == null) {
                contributedHoverIcon = hoverIcon;
            }
        }
    }

    private IHandlerListener getHandlerListener() {
        if (commandListener == null) {
            commandListener = new IHandlerListener() {
                @Override
                public void handlerChanged(final HandlerEvent commandEvent) {
                    if (commandEvent.isHandledChanged() || commandEvent.isEnabledChanged()) {
                        updateCommandProperties(commandEvent);
                    }
                }
            };
        }
        return commandListener;
    }

    private void updateCommandProperties(final HandlerEvent commandEvent) {
        if (commandEvent.isHandledChanged()) {
            dropDownMenuOverride = null;
        }
        final Runnable update = new Runnable() {
            @Override
            public void run() {
                update(null);
            }
        };
        if (display.getThread() == Thread.currentThread()) {
            update.run();
        } else {
            display.asyncExec(update);
        }
    }

    /**
     * Returns the ParameterizedCommand for this contribution.
     * <p>
     * <strong>NOTE:</strong> The returned object should be treated
     * as 'read-only', do <b>not</b> execute this instance or attempt
     * to modify its state.
     * </p>
     * @return The parameterized command for this contribution. May be
     *         <code>null</code>.
     */
    public ParameterizedCommand getCommand() {
        return command;
    }

    void createCommand(final String commandId, final Map parameters) {
        if (commandId == null) {
            StatusManager.getManager().handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID,
                    "Unable to create menu item \"" + getId() + "\", no command id")); //$NON-NLS-1$ //$NON-NLS-2$
            return;
        }
        if (commandId == NO_COMMAND_ID) {
            mode |= MODE_NO_COMMAND;
            return;
        }
        final Command cmd = commandService.getCommand(commandId);
        if (!cmd.isDefined()) {
            StatusManager.getManager().handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID,
                    "Unable to create menu item \"" + getId() + "\", command \"" + commandId + "\" not defined")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            return;
        }
        command = ParameterizedCommand.generateCommand(cmd, parameters);
    }

    /**
     * Provide info on the rendering data contained in this item.
     * 
     * @return a {@link CommandContributionItemParameter}. Valid fields are
     *         serviceLocator, id, style, icon, disabledIcon, hoverIcon, label,
     *         helpContextId, mnemonic, tooltip. The Object will never be
     *         <code>null</code>, although any of the fields may be
     *         <code>null</code>.
     * @since 3.7
     */
    public CommandContributionItemParameter getData() {
        final CommandContributionItemParameter data = new CommandContributionItemParameter(serviceLocator, getId(),
                null, style);
        data.icon = contributedIcon;
        data.disabledIcon = contributedDisabledIcon;
        data.hoverIcon = contributedHoverIcon;
        data.label = contributedLabel;
        data.tooltip = contributedTooltip;
        data.helpContextId = helpContextId;
        data.mnemonic = mnemonic;
        return data;
    }

    @Override
    public void fill(final Menu parent, final int index) {
        if (command == null && (mode & MODE_NO_COMMAND) == 0) {
            return;
        }
        if (widget != null || parent == null) {
            return;
        }

        // Menus don't support the pulldown style
        int tmpStyle = style;
        if (tmpStyle == STYLE_PULLDOWN) {
            tmpStyle = STYLE_PUSH;
        }

        MenuItem item = null;
        if (index >= 0) {
            item = new MenuItem(parent, tmpStyle, index);
        } else {
            item = new MenuItem(parent, tmpStyle);
        }
        item.setData(this);
        if (workbenchHelpSystem != null) {
            workbenchHelpSystem.setHelp(item, helpContextId);
        }
        item.addListener(SWT.Dispose, getItemListener());
        item.addListener(SWT.Selection, getItemListener());
        widget = item;

        update(null);
        updateIcons();

        establishReferences();
    }

    @Override
    public void fill(final ToolBar parent, final int index) {
        if (command == null && (mode & MODE_NO_COMMAND) == 0) {
            return;
        }
        if (widget != null || parent == null) {
            return;
        }

        ToolItem item = null;
        if (index >= 0) {
            item = new ToolItem(parent, style, index);
        } else {
            item = new ToolItem(parent, style);
        }

        item.setData(this);

        item.addListener(SWT.Selection, getItemListener());
        item.addListener(SWT.Dispose, getItemListener());
        widget = item;

        update(null);
        updateIcons();

        establishReferences();
    }

    @Override
    public void fill(final Composite parent) {
        if (command == null && (mode & MODE_NO_COMMAND) == 0) {
            return;
        }
        if (widget != null || parent == null) {
            return;
        }

        // Buttons don't support the pulldown style
        int tmpStyle = style;
        if (tmpStyle == STYLE_PULLDOWN) {
            tmpStyle = STYLE_PUSH;
        }

        final Button item = new Button(parent, tmpStyle);
        item.setData(this);
        if (workbenchHelpSystem != null) {
            workbenchHelpSystem.setHelp(item, helpContextId);
        }
        item.addListener(SWT.Dispose, getItemListener());
        item.addListener(SWT.Selection, getItemListener());
        widget = item;

        update(null);
        updateIcons();

        establishReferences();
    }

    @Override
    public void update() {
        update(null);
    }

    @Override
    public void update(final String id) {
        if (widget != null) {
            if ((mode & MODE_CALLBACK_EXPL) == MODE_CALLBACK_EXPL) {
                return;
            }
            if ((mode & (MODE_NO_COMMAND | MODE_CALLBACK_CALL)) == (MODE_NO_COMMAND) && callback != null) {
                mode |= MODE_CALLBACK_EXPL;
                try {
                    label = contributedLabel;
                    tooltip = contributedTooltip;
                    icon = contributedIcon;
                    disabledIcon = contributedDisabledIcon;
                    hoverIcon = contributedHoverIcon;
                    ((IElementUpdater) commandHandler).updateElement(callback, Collections.EMPTY_MAP);
                } finally {
                    mode &= ~MODE_CALLBACK_EXPL;
                }
            }

            if (widget instanceof MenuItem) {
                updateMenuItem();
            } else if (widget instanceof ToolItem) {
                updateToolItem();
            } else if (widget instanceof Button) {
                updateButton();
            }
        }
    }

    private void updateMenuItem() {
        final MenuItem item = (MenuItem) widget;

        final boolean shouldBeEnabled = isEnabled();

        // disabled command + visibility follows enablement == disposed
        if (item.isDisposed()) {
            return;
        }

        String text = label;
        if (text == null) {
            if (command != null) {
                try {
                    text = command.getCommand().getName();
                } catch (final NotDefinedException e) {
                    StatusManager.getManager().handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID,
                            "Update item failed " + getId(), e)); //$NON-NLS-1$
                }
            }
        }
        text = updateMnemonic(text);

        String keyBindingText = null;
        if (command != null) {
            final TriggerSequence binding = bindingService.getBestActiveBindingFor(command);
            if (binding != null) {
                keyBindingText = binding.format();
            }
        }
        if (text != null) {
            if (keyBindingText == null) {
                item.setText(text);
            } else {
                item.setText(text + '\t' + keyBindingText);
            }
        }

        if (item.getSelection() != checkedState) {
            item.setSelection(checkedState);
        }

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

    private void updateToolItem() {
        final ToolItem item = (ToolItem) widget;

        final boolean shouldBeEnabled = isEnabled();

        // disabled command + visibility follows enablement == disposed
        if (item.isDisposed()) {
            return;
        }

        String text = label;
        if (text == null) {
            if (command != null) {
                try {
                    text = command.getCommand().getName();
                } catch (final NotDefinedException e) {
                    StatusManager.getManager().handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID,
                            "Update item failed " + getId(), e)); //$NON-NLS-1$
                }
            }
        }

        if ((icon == null || (mode & MODE_FORCE_TEXT) == MODE_FORCE_TEXT) && text != null) {
            item.setText(text);
        }

        final String toolTipText = getToolTipText(text);
        item.setToolTipText(toolTipText);

        if (item.getSelection() != checkedState) {
            item.setSelection(checkedState);
        }

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

    private void updateButton() {
        final Button item = (Button) widget;

        final boolean shouldBeEnabled = isEnabled();

        // disabled command + visibility follows enablement == disposed
        if (item.isDisposed()) {
            return;
        }

        String text = label;
        if (text == null) {
            if (command != null) {
                try {
                    text = command.getCommand().getName();
                } catch (final NotDefinedException e) {
                    StatusManager.getManager().handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID,
                            "Update item failed " + getId(), e)); //$NON-NLS-1$
                }
            }
        }

        if (text != null) {
            item.setText(text);
        }

        final String toolTipText = getToolTipText(text);
        item.setToolTipText(toolTipText);

        if (item.getSelection() != checkedState) {
            item.setSelection(checkedState);
        }

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

    private String getToolTipText(final String text) {
        String tooltipText = tooltip;
        if (tooltip == null) {
            if (text != null) {
                tooltipText = text;
            } else {
                tooltipText = ""; //$NON-NLS-1$
            }
        }

        if (command != null) {
            final TriggerSequence activeBinding = bindingService.getBestActiveBindingFor(command);
            if (activeBinding != null && !activeBinding.isEmpty()) {
                final String acceleratorText = activeBinding.format();
                if (acceleratorText != null && acceleratorText.length() != 0) {
                    tooltipText = NLS.bind("{0} ({1})", tooltipText, acceleratorText); //$NON-NLS-1$
                }
            }
        }

        return tooltipText;
    }

    private String updateMnemonic(final String s) {
        if (mnemonic == null || s == null) {
            return s;
        }
        final int idx = s.indexOf(mnemonic);
        if (idx == -1) {
            return s;
        }

        return s.substring(0, idx) + '&' + s.substring(idx);
    }

    private void handleWidgetDispose(final Event event) {
        if (event.widget == widget) {
            disconnectReferences();
            widget.removeListener(SWT.Selection, getItemListener());
            widget.removeListener(SWT.Dispose, getItemListener());
            widget = null;
            disposeOldImages();
        }
    }

    private void establishReferences() {
        if (command != null || (mode & MODE_NO_COMMAND) != 0) {
            commandHandler.addHandlerListener(getHandlerListener());
        }
        if (command != null) {
            if (callback != null) {
                try {
                    elementRef = commandService.registerElementForCommand(command, callback);
                } catch (final NotDefinedException e) {
                    StatusManager.getManager().handle(
                            new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID, "Unable to register menu item \"" //$NON-NLS-1$
                                    + getId() + "\", command \"" + command.getId() + "\" not defined")); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
        }
        bindingService.addBindingManagerListener(bindingManagerListener);
    }

    private void disconnectReferences() {
        if (elementRef != null) {
            commandService.unregisterElement(elementRef);
            elementRef = null;
        }
        if (commandListener != null) {
            commandHandler.removeHandlerListener(commandListener);
            commandListener = null;
        }
        if (bindingService != null) {
            bindingService.removeBindingManagerListener(bindingManagerListener);
        }
    }

    @Override
    public void dispose() {
        if (widget != null) {
            widget.dispose();
            widget = null;
        }

        disconnectReferences();

        command = null;
        commandHandler = null;
        commandService = null;
        bindingService = null;
        menuService = null;
        handlerService = null;
        disposeOldImages();
        super.dispose();
    }

    private void disposeOldImages() {
        if (localResourceManager != null) {
            localResourceManager.dispose();
            localResourceManager = null;
        }
    }

    private Listener getItemListener() {
        if (menuItemListener == null) {
            menuItemListener = new Listener() {
                @Override
                public void handleEvent(final Event event) {
                    switch (event.type) {
                    case SWT.Dispose:
                        handleWidgetDispose(event);
                        break;
                    case SWT.Selection:
                        if (event.widget != null) {
                            handleWidgetSelection(event);
                        }
                        break;
                    }
                }
            };
        }
        return menuItemListener;
    }

    private void handleWidgetSelection(final Event event) {
        // Special check for ToolBar dropdowns...
        if (openDropDownMenu(event)) {
            return;
        }

        if ((style & (SWT.TOGGLE | SWT.CHECK)) != 0) {
            if (event.widget instanceof ToolItem) {
                checkedState = ((ToolItem) event.widget).getSelection();
            } else if (event.widget instanceof MenuItem) {
                checkedState = ((MenuItem) event.widget).getSelection();
            }
        }

        try {
            final ExecutionEvent executionEvent = command != null
                    ? handlerService.createExecutionEvent(command, event)
                    : new ExecutionEvent(null, Collections.EMPTY_MAP, null,
                            handlerService.createContextSnapshot(true));
            commandHandler.execute(executionEvent);
        } catch (final ExecutionException e) {
            StatusManager.getManager().handle(
                    new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID, "Failed to execute item " + getId(), e)); //$NON-NLS-1$
            //      } catch (NotDefinedException e) {
            //         WorkbenchPlugin.log("Failed to execute item " //$NON-NLS-1$
            //               + getId(), e);
            //      } catch (NotEnabledException e) {
            //         WorkbenchPlugin.log("Failed to execute item " //$NON-NLS-1$
            //               + getId(), e);
            //      } catch (NotHandledException e) {
            //         WorkbenchPlugin.log("Failed to execute item " //$NON-NLS-1$
            //               + getId(), e);
        }
    }

    /**
     * Determines if the selection was on the dropdown affordance and, if so,
     * opens the drop down menu (populated using the same id as this item...
     * 
     * @param event
     *            The <code>SWT.Selection</code> event to be tested
     * 
     * @return <code>true</code> iff a drop down menu was opened
     */
    private boolean openDropDownMenu(final Event event) {
        final Widget item = event.widget;
        if (item != null) {
            final int style = item.getStyle();
            if ((style & SWT.DROP_DOWN) != 0) {
                if (event.detail == 4) { // on drop-down button
                    final ToolItem ti = (ToolItem) item;

                    final MenuManager menuManager = new MenuManager();
                    final Menu menu = menuManager.createContextMenu(ti.getParent());
                    if (workbenchHelpSystem != null) {
                        workbenchHelpSystem.setHelp(menu, helpContextId);
                    }
                    initDropDownMenu(menuManager);

                    // position the menu below the drop down item
                    final Point point = ti.getParent().toDisplay(new Point(event.x, event.y));
                    menu.setLocation(point.x, point.y); // waiting for SWT
                    // 0.42
                    menu.setVisible(true);
                    return true; // we don't fire the action
                }
            }
        }

        return false;
    }

    protected void initDropDownMenu(final MenuManager menuManager) {
        String id = dropDownMenuOverride;
        if (id == null) {
            id = getId();
        }
        MenuUtil.registerOneWayMenu(menuManager, id);
    }

    private void updateIcons() {
        if (widget instanceof MenuItem) {
            final MenuItem item = (MenuItem) widget;
            final LocalResourceManager m = new LocalResourceManager(JFaceResources.getResources());
            try {
                item.setImage(icon == null ? null : m.createImage(icon));
            } catch (final DeviceResourceException e) {
                icon = ImageDescriptor.getMissingImageDescriptor();
                item.setImage(m.createImage(icon));
                // as we replaced the failed icon, log the message once.
                StatusManager.getManager()
                        .handle(new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID, "Failed to load image", e)); //$NON-NLS-1$
            }
            disposeOldImages();
            localResourceManager = m;
        } else if (widget instanceof ToolItem) {
            final ToolItem item = (ToolItem) widget;
            final LocalResourceManager m = new LocalResourceManager(JFaceResources.getResources());
            item.setDisabledImage(disabledIcon == null ? null : m.createImage(disabledIcon));
            item.setHotImage(hoverIcon == null ? null : m.createImage(hoverIcon));
            item.setImage(icon == null ? null : m.createImage(icon));
            disposeOldImages();
            localResourceManager = m;
        }
    }

    public void setText(final String text) {
        label = text;
        update(null);
    }

    public void setChecked(final boolean checked) {
        if (checkedState == checked) {
            return;
        }
        checkedState = checked;
        if (widget instanceof MenuItem) {
            ((MenuItem) widget).setSelection(checkedState);
        } else if (widget instanceof ToolItem) {
            ((ToolItem) widget).setSelection(checkedState);
        }
    }

    public void setTooltip(final String text) {
        tooltip = text;
        if (widget instanceof ToolItem) {
            ((ToolItem) widget).setToolTipText(text);
        }
    }

    public void setIcon(final ImageDescriptor desc) {
        icon = desc;
        updateIcons();
    }

    public void setDisabledIcon(final ImageDescriptor desc) {
        disabledIcon = desc;
        updateIcons();
    }

    public void setHoverIcon(final ImageDescriptor desc) {
        hoverIcon = desc;
        updateIcons();
    }

    @Override
    public boolean isEnabled() {
        if (commandHandler != null) {
            commandHandler.setEnabled((menuService != null) ? menuService.getCurrentState() : null);
            return commandHandler.isEnabled();
        }
        return false;
    }

    @Override
    public boolean isVisible() {
        if (visibleEnabled) {
            return super.isVisible() && isEnabled();
        }
        return super.isVisible();
    }

}