org.kalypso.contribs.eclipse.ui.actions.DropDownToolbarItem.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.contribs.eclipse.ui.actions.DropDownToolbarItem.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.contribs.eclipse.ui.actions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.CommandEvent;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.ICommandListener;
import org.eclipse.core.commands.IExecutionListener;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
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.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.PlatformUI;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.commands.ICommandImageService;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.commands.IElementReference;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.menus.UIElement;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.services.IServiceLocator;
import org.kalypso.contribs.eclipse.core.commands.ExecutionAdapter;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.contribs.eclipse.jface.resource.DisabledImageDescriptor;

/**
 * @author Dirk Kuch, kurzbach
 */
public class DropDownToolbarItem extends CompoundContributionItem implements IExecutableExtension {
    private final IExecutionListener executionListener = new ExecutionAdapter() {
        /**
         * Listen for pre-execution: if any of my commands is executed, put it as the current command on top.<br>
         * TODO: is this always intended? This happens also if the command is executed by another mean (key-binding, etc.)
         */
        @Override
        public void preExecute(final String commandId, final ExecutionEvent event) {
            final Command cmd = m_commandService.getCommand(commandId);
            final ParameterizedCommand thisCommand = ParameterizedCommand.generateCommand(cmd,
                    event.getParameters());

            // TODO: for each call to getContribution items, we must dispose the items; that is quite difficult, as this also
            // holds for the current item
            for (final CommandContributionItem item : getContributionItems()) {
                if (item.getCommand().equals(thisCommand)) {
                    setCurrentCommand(item);
                    update();
                }
            }
        }
    };

    /**
     * Command-Listener: any change of the current command will update this widget.
     */
    private final ICommandListener m_commandListener = new ICommandListener() {
        @Override
        public void commandChanged(final CommandEvent commandEvent) {
            if (m_currentCommand != null && commandEvent.getCommand() == m_currentCommand.getCommand().getCommand())
                update();
        }
    };

    protected Command[] m_commands = new Command[] {};

    private final Map<Command, IExecutionListener> m_executionListeners = new HashMap<>();

    private final Map<Command, ICommandListener> m_commandListeners = new HashMap<>();

    protected CommandContributionItem m_currentCommand;

    protected final IHandlerService m_handlerService;

    public DropDownToolbarItem() {
        final IServiceLocator serviceLocator = getServiceLocator();
        m_commandService = (ICommandService) serviceLocator.getService(ICommandService.class);
        m_handlerService = (IHandlerService) serviceLocator.getService(IHandlerService.class);
    }

    protected IServiceLocator getServiceLocator() {
        // REMARK: we are using the most global service locator here, that is not
        // the very best choice... however, how do we find a better one?
        return PlatformUI.getWorkbench();
    }

    @Override
    protected CommandContributionItem[] getContributionItems() {
        final IServiceLocator locator = PlatformUI.getWorkbench();

        final CommandContributionItem[] items = new CommandContributionItem[m_commands.length];
        for (int i = 0; i < m_commands.length; i++) {
            final CommandContributionItemParameter data = new CommandContributionItemParameter(locator,
                    m_commands[i].getId(), m_commands[i].getId(), SWT.PUSH);
            // items[i] = new CommandContributionItem( locator, m_commands[i].getId(), m_commands[i].getId(), new
            // HashMap<Object,
            // Object>(), null, null, null, null, null, null, SWT.PUSH );
            items[i] = new CommandContributionItem(data);
        }

        return items;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void setInitializationData(final IConfigurationElement config, final String propertyName,
            final Object data) {
        final Set<Command> commands = new LinkedHashSet<>();
        if (data instanceof Map<?, ?>) {
            /* REMARK: map ht is unsorted - sort commands by param id! */
            final Map<String, String> ht = (Map<String, String>) data;

            final List<String> keys = new ArrayList<>();
            keys.addAll(ht.keySet());
            Collections.sort(keys);

            for (final String key : keys) {
                final String value = ht.get(key);
                if (key.toLowerCase().startsWith("command")) {
                    commands.add(m_commandService.getCommand(value));
                }
            }
            m_commands = commands.toArray(new Command[commands.size()]);
        }

        if (m_commands.length > 0)
            setCurrentCommand(getContributionItems()[0]);

        registerCommandListeners(commands.toArray(new Command[commands.size()]));
    }

    // COPIED FROM COMMAND CONTRIBUTION ITEM

    protected void registerCommandListeners(final Command[] commands) {
        for (final Command command : commands) {
            command.addCommandListener(m_commandListener);
            command.addExecutionListener(executionListener);
            m_commandListeners.put(command, m_commandListener);
            m_executionListeners.put(command, executionListener);
        }
    }

    private LocalResourceManager localResourceManager;

    private Listener menuItemListener;

    private Widget widget;

    protected ICommandService m_commandService;

    private IElementReference m_elementReference = null;

    private boolean checkedState;

    private final int style = CommandContributionItem.STYLE_PULLDOWN;

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

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

        MenuItem item = null;
        if (index >= 0) {
            item = new MenuItem(parent, tmpStyle, index);
        } else {
            item = new MenuItem(parent, tmpStyle);
        }
        item.setData(this);

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

        update(null);
    }

    @Override
    public void fill(final ToolBar parent, final int index) {
        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);
    }

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

    @Override
    public void update(final String id) {
        if (widget != null) {
            if (m_currentCommand != null) {
                final IServiceLocator locator = getServiceLocator();
                final ICommandImageService service = (ICommandImageService) locator
                        .getService(ICommandImageService.class);

                ImageDescriptor icon = service.getImageDescriptor(m_currentCommand.getId(),
                        ICommandImageService.TYPE_DEFAULT);
                ImageDescriptor disabledIcon = service.getImageDescriptor(m_currentCommand.getId(),
                        ICommandImageService.TYPE_DISABLED);
                ImageDescriptor hoverIcon = service.getImageDescriptor(m_currentCommand.getId(),
                        ICommandImageService.TYPE_HOVER);

                final CommandContributionItemParameter data = m_currentCommand.getData();

                if (icon == null)
                    icon = data.icon;
                if (disabledIcon == null)
                    disabledIcon = data.disabledIcon;
                if (hoverIcon == null)
                    hoverIcon = data.hoverIcon;

                updateIcons(icon, disabledIcon, hoverIcon);

                final String label = data.label;
                final String tooltip = data.tooltip;

                updateText(label, tooltip);

                if (widget instanceof MenuItem) {
                    final MenuItem item = (MenuItem) widget;

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

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

                    item.setEnabled(m_currentCommand.isEnabled());
                    final boolean shouldBeEnabled = isEnabled();
                    if (item.getEnabled() != shouldBeEnabled) {
                        item.setEnabled(shouldBeEnabled);
                    }
                } else if (widget instanceof ToolItem) {
                    final ToolItem item = (ToolItem) widget;

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

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

    private void updateIcons(final ImageDescriptor icon, final ImageDescriptor disabledIcon,
            final ImageDescriptor hoverIcon) {
        final LocalResourceManager m = new LocalResourceManager(JFaceResources.getResources());

        final Image imageIcon = icon == null ? null : m.createImage(icon);
        final Image disabledImageIcon = disabledIcon == null ? null : m.createImage(disabledIcon);

        // If the command is currently not enabled, show a disabled icon as the default image
        Image imageIcon2;
        if (m_currentCommand.isEnabled() || imageIcon == null)
            imageIcon2 = imageIcon;
        else if (disabledImageIcon != null)
            imageIcon2 = disabledImageIcon;
        else {
            final ImageDescriptor disabledDescriptor = new DisabledImageDescriptor(imageIcon);
            imageIcon2 = m.createImage(disabledDescriptor);
        }

        if (widget instanceof MenuItem) {
            final MenuItem item = (MenuItem) widget;
            item.setImage(imageIcon2);
        } else if (widget instanceof ToolItem) {
            final Image hoverImageIcon = hoverIcon == null ? null : m.createImage(hoverIcon);

            final ToolItem item = (ToolItem) widget;
            item.setDisabledImage(disabledImageIcon);
            item.setHotImage(hoverImageIcon);
            item.setImage(imageIcon2);
        }

        disposeOldImages();
        localResourceManager = m;
    }

    private void updateText(final String label, final String tooltip) {
        if (widget instanceof MenuItem) {
            final MenuItem itm = (MenuItem) widget;
            itm.setText(label);
        } else if (widget instanceof ToolItem) {
            final ToolItem itm = (ToolItem) widget;
            // itm.setText( label );
            itm.setToolTipText(tooltip);
        } else
            throw new UnsupportedOperationException();

    }

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

    /**
     * @see org.eclipse.jface.action.ContributionItem#dispose()
     */
    @Override
    public void dispose() {
        if (m_elementReference != null) {
            m_commandService.unregisterElement(m_elementReference);
            m_elementReference = null;
        }

        m_commandService = null;
        disposeOldImages();

        final Set<Entry<Command, IExecutionListener>> entrySet = m_executionListeners.entrySet();
        for (final Entry<Command, IExecutionListener> entry : entrySet)
            entry.getKey().removeExecutionListener(entry.getValue());

        m_executionListeners.clear();

        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;
    }

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

        if ((event.type & SWT.MouseDown) != 0) {
            if (m_currentCommand == null || !m_currentCommand.isEnabled())
                return;

            new UIJob("executing comannd...") {
                @Override
                public IStatus runInUIThread(final IProgressMonitor monitor) {
                    try {
                        m_handlerService.executeCommand(m_currentCommand.getCommand(), event);
                    } catch (final ExecutionException e) {
                        return Status.CANCEL_STATUS;
                    } catch (final NotHandledException e) {
                        return Status.CANCEL_STATUS;
                    } catch (final NotDefinedException e) {
                        e.printStackTrace();
                        return StatusUtilities.statusFromThrowable(e);
                    } catch (final NotEnabledException e) {
                        e.printStackTrace();
                        return StatusUtilities.statusFromThrowable(e);
                    }
                    return Status.OK_STATUS;
                }
            }.schedule();
        }

    }

    /**
     * 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 myStyle = item.getStyle();
            if ((myStyle & SWT.DROP_DOWN) != 0) {
                if (event.detail == 4) { // on drop-down button
                    final ToolItem ti = (ToolItem) item;

                    final MenuManager menuManager = new MenuManager();
                    menuManager.setRemoveAllWhenShown(true);
                    final Menu menu = menuManager.createContextMenu(ti.getParent());
                    menuManager.addMenuListener(new IMenuListener() {
                        @Override
                        public void menuAboutToShow(final IMenuManager manager) {
                            final IContributionItem[] contributionItems = getContributionItems();
                            for (final IContributionItem contributionItem : contributionItems)
                                manager.add(contributionItem);
                        }
                    });

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

        return false;
    }

    @Override
    public boolean isEnabled() {
        final CommandContributionItem[] contributionItems = getContributionItems();
        for (final ContributionItem item : contributionItems) {
            if (item.isEnabled())
                return true;
        }

        return false;
    }

    void setCurrentCommand(final CommandContributionItem item) {
        if (m_elementReference != null) {
            m_commandService.unregisterElement(m_elementReference);
            m_elementReference = null;
        }

        m_currentCommand = item;

        if (m_currentCommand == null)
            return;

        final UIElement callback = new UIElement(getServiceLocator()) {
            @Override
            public void setChecked(final boolean checked) {
                update(null);
            }

            @Override
            public void setDisabledIcon(final ImageDescriptor desc) {
                update(null);
            }

            @Override
            public void setHoverIcon(final ImageDescriptor desc) {
                update(null);
            }

            @Override
            public void setIcon(final ImageDescriptor desc) {
                update(null);
            }

            @Override
            public void setText(final String text) {
                update(null);
            }

            @Override
            public void setTooltip(final String text) {
                update(null);
            }

            @Override
            public void setDropDownId(final String id) {
                update(null);
            }
        };

        try {
            final ParameterizedCommand command = m_currentCommand.getCommand();
            m_elementReference = m_commandService.registerElementForCommand(command, callback);
        } catch (final NotDefinedException e) {
            e.printStackTrace();
        }
    }

}