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

Java tutorial

Introduction

Here is the source code for de.walware.ecommons.ui.actions.SimpleContributionItem.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 org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IMenuListener2;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
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.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.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.help.IWorkbenchHelpSystem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.statushandlers.StatusManager;

import de.walware.ecommons.ui.SharedUIResources;

/**
 * A contribution item
 */
public abstract class SimpleContributionItem extends ContributionItem {

    /**
     * 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 LocalResourceManager localResourceManager;

    private Listener menuItemListener;

    private Widget widget;

    private ImageDescriptor icon;

    private String label;

    private String tooltip;

    private ImageDescriptor disabledIcon;

    private ImageDescriptor hoverIcon;

    private String mnemonic;

    private boolean checkedState;

    private final int style;

    private IWorkbenchHelpSystem workbenchHelpSystem;

    private String helpContextId;

    private final int mode = 0;

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

        this.icon = contributionParameters.icon;
        this.disabledIcon = contributionParameters.disabledIcon;
        this.hoverIcon = contributionParameters.hoverIcon;
        this.label = contributionParameters.label;
        this.mnemonic = contributionParameters.mnemonic;
        this.tooltip = contributionParameters.tooltip;
        this.style = contributionParameters.style;
        this.helpContextId = contributionParameters.helpContextId;
    }

    protected SimpleContributionItem(final ImageDescriptor icon, final ImageDescriptor disabledIcon,
            final String label, final String mnemonic) {
        super();

        this.icon = icon;
        this.disabledIcon = disabledIcon;
        this.label = label;
        this.mnemonic = mnemonic;
        this.style = STYLE_PUSH;
    }

    protected SimpleContributionItem(final String label, final String mnemonic) {
        super();

        this.label = label;
        this.mnemonic = mnemonic;
        this.style = STYLE_PUSH;
    }

    protected SimpleContributionItem(final ImageDescriptor icon, final ImageDescriptor disabledIcon,
            final String label, final String mnemonic, final int style) {
        super();

        this.icon = icon;
        this.disabledIcon = disabledIcon;
        this.label = label;
        this.mnemonic = mnemonic;
        this.style = style;
    }

    protected SimpleContributionItem(final String label, final String mnemonic, final int style) {
        super();

        this.label = label;
        this.mnemonic = mnemonic;
        this.style = style;
    }

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

        // Menus don't support the pulldown style
        int tmpStyle = this.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 (this.workbenchHelpSystem != null) {
            this.workbenchHelpSystem.setHelp(item, this.helpContextId);
        }
        item.addListener(SWT.Dispose, getItemListener());
        item.addListener(SWT.Selection, getItemListener());
        this.widget = item;

        update(null);
        updateIcons();
    }

    @Override
    public void fill(final ToolBar parent, final int index) {
        if (this.widget != null || parent == null) {
            return;
        }

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

        item.setData(this);

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

        update(null);
        updateIcons();
    }

    @Override
    public void fill(final Composite parent) {
        if (this.widget != null || parent == null) {
            return;
        }

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

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

        update(null);
        updateIcons();
    }

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

    @Override
    public void update(final String id) {
        if (this.widget != null) {
            if (this.widget instanceof MenuItem) {
                updateMenuItem();
            } else if (this.widget instanceof ToolItem) {
                updateToolItem();
            } else if (this.widget instanceof Button) {
                updateButton();
            }
        }
    }

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

        final boolean shouldBeEnabled = isEnabled();

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

        String text = this.label;
        text = updateMnemonic(text);

        final String keyBindingText = null;
        if (text != null) {
            if (keyBindingText == null) {
                item.setText(text);
            } else {
                item.setText(text + '\t' + keyBindingText);
            }
        }

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

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

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

        final boolean shouldBeEnabled = isEnabled();

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

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

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

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

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

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

        final boolean shouldBeEnabled = isEnabled();

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

        final String text = this.label;
        if (text != null) {
            item.setText(text);
        }

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

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

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

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

        return tooltipText;
    }

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

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

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

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

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

    private Listener getItemListener() {
        if (this.menuItemListener == null) {
            this.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 this.menuItemListener;
    }

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

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

        try {
            execute(event);
        } catch (final ExecutionException e) {
            StatusManager.getManager().handle(
                    new Status(IStatus.ERROR, SharedUIResources.PLUGIN_ID, "Failed to execute item " + getId(), e)); //$NON-NLS-1$
        }
    }

    /**
     * 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 (this.workbenchHelpSystem != null) {
                        this.workbenchHelpSystem.setHelp(menu, this.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) {
        final Menu menu = menuManager.getMenu();
        menuManager.addMenuListener(new IMenuListener2() {
            @Override
            public void menuAboutToShow(final IMenuManager manager) {
                dropDownMenuAboutToShow(manager);
            }

            @Override
            public void menuAboutToHide(final IMenuManager manager) {
                menu.getDisplay().asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        menuManager.dispose();
                    }
                });
            }
        });
    }

    private void updateIcons() {
        if (this.widget instanceof MenuItem) {
            final MenuItem item = (MenuItem) this.widget;
            final LocalResourceManager m = new LocalResourceManager(JFaceResources.getResources());
            try {
                item.setImage(this.icon == null ? null : m.createImage(this.icon));
            } catch (final DeviceResourceException e) {
                this.icon = ImageDescriptor.getMissingImageDescriptor();
                item.setImage(m.createImage(this.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();
            this.localResourceManager = m;
        } else if (this.widget instanceof ToolItem) {
            final ToolItem item = (ToolItem) this.widget;
            final LocalResourceManager m = new LocalResourceManager(JFaceResources.getResources());
            item.setDisabledImage(this.disabledIcon == null ? null : m.createImage(this.disabledIcon));
            item.setHotImage(this.hoverIcon == null ? null : m.createImage(this.hoverIcon));
            item.setImage(this.icon == null ? null : m.createImage(this.icon));
            disposeOldImages();
            this.localResourceManager = m;
        }
    }

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

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

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

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

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

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

    protected void dropDownMenuAboutToShow(final IMenuManager manager) {
    }

    protected void execute(final Event event) throws ExecutionException {
        execute();
    }

    @Deprecated
    protected void execute() throws ExecutionException {
    }

}