| /*=============================================================================# |
| # Copyright (c) 2006, 2021 IBM Corporation and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 |
| # |
| # Contributors: |
| # IBM Corporation - org.eclipse.platform: initial API and implementation |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.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 org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.ui.SharedUIResources; |
| |
| |
| /** |
| * A contribution item |
| */ |
| @NonNullByDefault |
| 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 @Nullable Widget widget; |
| |
| private @Nullable Listener menuItemListener; |
| |
| |
| private @Nullable String label; |
| |
| private @Nullable String mnemonic; |
| |
| private @Nullable String tooltip; |
| |
| private @Nullable ImageDescriptor icon; |
| |
| private @Nullable ImageDescriptor disabledIcon; |
| |
| private @Nullable ImageDescriptor hoverIcon; |
| |
| private boolean checkedState; |
| |
| private final int style; |
| |
| private @Nullable IWorkbenchHelpSystem workbenchHelpSystem; |
| private @Nullable 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.label= contributionParameters.label; |
| this.mnemonic= contributionParameters.mnemonic; |
| this.tooltip= contributionParameters.tooltip; |
| this.icon= contributionParameters.icon; |
| this.disabledIcon= contributionParameters.disabledIcon; |
| this.hoverIcon= contributionParameters.hoverIcon; |
| this.style= contributionParameters.style; |
| this.helpContextId= contributionParameters.helpContextId; |
| } |
| |
| protected SimpleContributionItem(final @Nullable String id, |
| final @Nullable String label, final @Nullable String mnemonic, |
| final @Nullable ImageDescriptor icon, final @Nullable ImageDescriptor disabledIcon, |
| final int style) { |
| super(id); |
| |
| this.label= label; |
| this.mnemonic= mnemonic; |
| this.icon= icon; |
| this.disabledIcon= disabledIcon; |
| this.style= style; |
| } |
| |
| protected SimpleContributionItem(final @Nullable String label, final @Nullable String mnemonic, |
| final @Nullable ImageDescriptor icon, final @Nullable ImageDescriptor disabledIcon, |
| final int style) { |
| this(null, label, mnemonic, icon, disabledIcon, style); |
| } |
| |
| protected SimpleContributionItem(final @Nullable String label, final @Nullable String mnemonic, |
| final int style) { |
| this(null, label, mnemonic, null, null, style); |
| } |
| |
| protected SimpleContributionItem(final @Nullable String label, final @Nullable String mnemonic, |
| final @Nullable ImageDescriptor icon, final @Nullable ImageDescriptor disabledIcon) { |
| this(null, label, mnemonic, icon, disabledIcon, STYLE_PUSH); |
| } |
| |
| protected SimpleContributionItem( |
| final @Nullable String label, final @Nullable String mnemonic) { |
| this(null, label, mnemonic, null, null, STYLE_PUSH); |
| } |
| |
| |
| @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((MenuItem) this.widget); |
| } |
| else if (this.widget instanceof ToolItem) { |
| updateToolItem((ToolItem) this.widget); |
| } |
| else if (this.widget instanceof Button) { |
| updateButton((Button) this.widget); |
| } |
| } |
| } |
| |
| private void updateMenuItem(final MenuItem item) { |
| 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) { |
| 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) { |
| 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.BUNDLE_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.BUNDLE_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 @Nullable 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 @Nullable String text) { |
| this.tooltip= text; |
| if (this.widget instanceof ToolItem) { |
| ((ToolItem) this.widget).setToolTipText(text); |
| } |
| } |
| |
| public void setIcon(final @Nullable ImageDescriptor desc) { |
| this.icon= desc; |
| updateIcons(); |
| } |
| |
| public void setDisabledIcon(final @Nullable ImageDescriptor desc) { |
| this.disabledIcon= desc; |
| updateIcons(); |
| } |
| |
| public void setHoverIcon(final @Nullable 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 { |
| } |
| |
| } |