Mercurial > projects > dwt-addons
view dwtx/jface/action/ActionContributionItem.d @ 16:e0f0aaf75edd
PopupDialog, bindings and actions
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 01 Apr 2008 08:00:31 +0200 |
parents | |
children | 644f1334b451 |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2007 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 * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.jface.action.ActionContributionItem; import dwtx.jface.action.ContributionItem; import dwtx.jface.action.IAction; import dwtx.jface.action.LegacyActionTools; import dwtx.jface.action.Action; import dwtx.jface.action.IMenuCreator; import dwtx.jface.action.IContributionManagerOverrides; import dwt.DWT; import dwt.graphics.GC; import dwt.graphics.Point; import dwt.graphics.Rectangle; import dwt.widgets.Button; import dwt.widgets.Composite; import dwt.widgets.Display; import dwt.widgets.Event; import dwt.widgets.Item; import dwt.widgets.Listener; import dwt.widgets.Menu; import dwt.widgets.MenuItem; import dwt.widgets.ToolBar; import dwt.widgets.ToolItem; import dwt.widgets.Widget; import dwtx.jface.action.ExternalActionManager; import dwtx.jface.bindings.Trigger; import dwtx.jface.bindings.TriggerSequence; import dwtx.jface.bindings.keys.IKeyLookup; import dwtx.jface.bindings.keys.KeyLookupFactory; import dwtx.jface.bindings.keys.KeyStroke; import dwtx.jface.resource.ImageDescriptor; import dwtx.jface.resource.JFaceResources; import dwtx.jface.resource.LocalResourceManager; import dwtx.jface.resource.ResourceManager; import dwtx.jface.util.IPropertyChangeListener; import dwtx.jface.util.Policy; import dwtx.jface.util.PropertyChangeEvent; import dwt.dwthelper.utils; import dwt.dwthelper.Runnable; import tango.core.Thread; import tango.io.Stdout; /** * A contribution item which delegates to an action. * <p> * This class may be instantiated; it is not intended to be subclassed. * </p> */ public class ActionContributionItem : ContributionItem { /** * Mode bit: Show text on tool items, 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 const String ellipsis = "..."; //$NON-NLS-1$ private static bool 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 bool 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(bool 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 const IPropertyChangeListener actionTextListener; /** * Remembers all images in use by this contribution item */ private LocalResourceManager imageManager; /** * Listener for DWT button widget events. */ private Listener buttonListener; /** * Listener for DWT menu item widget events. */ private Listener menuItemListener; /** * Listener for action property change notifications. */ private const IPropertyChangeListener propertyListener; /** * Listener for DWT 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; /** * 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 this(IAction action) { super(action.getId()); this.action = action; actionTextListener = new class IPropertyChangeListener { /** * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { update(event.getProperty()); } }; propertyListener = new class IPropertyChangeListener { public void propertyChange(PropertyChangeEvent event) { actionPropertyChange(event); } }; } /** * Handles a property change event on the action (forwarded by nested * listener). */ private void actionPropertyChange(PropertyChangeEvent e) { // This code should be removed. Avoid using free asyncExec if (isVisible() && widget !is null) { Display display = widget.getDisplay(); if (display.getThread() is Thread.getThis()) { update(e.getProperty()); } else { display.asyncExec(new class Runnable { PropertyChangeEvent e_; this(){ e_=e; } 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 override int opEquals(Object o) { if (!(cast(ActionContributionItem)o )) { return false; } return (cast(Object)action).opEquals(cast(Object)(cast(ActionContributionItem) o).action); } /** * The <code>ActionContributionItem</code> implementation of this * <code>IContributionItem</code> method creates an DWT * <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 is null && parent !is null) { int flags = DWT.PUSH; if (action !is null) { if (action.getStyle() is IAction.AS_CHECK_BOX) { flags = DWT.TOGGLE; } if (action.getStyle() is IAction.AS_RADIO_BUTTON) { flags = DWT.RADIO; } } Button b = new Button(parent, flags); b.setData(this); b.addListener(DWT.Dispose, getButtonListener()); // Don't hook a dispose listener on the parent b.addListener(DWT.Selection, getButtonListener()); if (action.getHelpListener() !is null) { b.addHelpListener(action.getHelpListener()); } widget = b; update(null); // Attach some extra listeners. action.addPropertyChangeListener(propertyListener); if (action !is null) { String commandId = action.getActionDefinitionId(); ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); if ((callback !is null) && (commandId !is null)) { callback.addPropertyChangeListener(commandId, actionTextListener); } } } } /** * The <code>ActionContributionItem</code> implementation of this * <code>IContributionItem</code> method creates an DWT * <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 is null && parent !is null) { Menu subMenu = null; int flags = DWT.PUSH; if (action !is null) { int style = action.getStyle(); if (style is IAction.AS_CHECK_BOX) { flags = DWT.CHECK; } else if (style is IAction.AS_RADIO_BUTTON) { flags = DWT.RADIO; } else if (style is IAction.AS_DROP_DOWN_MENU) { IMenuCreator mc = action.getMenuCreator(); if (mc !is null) { subMenu = mc.getMenu(parent); flags = DWT.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(DWT.Dispose, getMenuItemListener()); mi.addListener(DWT.Selection, getMenuItemListener()); if (action.getHelpListener() !is null) { mi.addHelpListener(action.getHelpListener()); } if (subMenu !is null) { mi.setMenu(subMenu); } update(null); // Attach some extra listeners. action.addPropertyChangeListener(propertyListener); if (action !is null) { String commandId = action.getActionDefinitionId(); ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); if ((callback !is null) && (commandId !is null)) { callback.addPropertyChangeListener(commandId, actionTextListener); } } } } /** * The <code>ActionContributionItem</code> implementation of this , * <code>IContributionItem</code> method creates an DWT * <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 is null && parent !is null) { int flags = DWT.PUSH; if (action !is null) { int style = action.getStyle(); if (style is IAction.AS_CHECK_BOX) { flags = DWT.CHECK; } else if (style is IAction.AS_RADIO_BUTTON) { flags = DWT.RADIO; } else if (style is IAction.AS_DROP_DOWN_MENU) { flags = DWT.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(DWT.Selection, getToolItemListener()); ti.addListener(DWT.Dispose, getToolItemListener()); widget = ti; update(null); // Attach some extra listeners. action.addPropertyChangeListener(propertyListener); if (action !is null) { String commandId = action.getActionDefinitionId(); ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); if ((callback !is null) && (commandId !is 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 DWT button widget events. * * @return a listener for button events */ private Listener getButtonListener() { if (buttonListener is null) { buttonListener = new class Listener { public void handleEvent(Event event) { switch (event.type) { case DWT.Dispose: handleWidgetDispose(event); break; case DWT.Selection: Widget ew = event.widget; if (ew !is null) { handleWidgetSelection(event, (cast(Button) ew) .getSelection()); } break; } } }; } return buttonListener; } /** * Returns the listener for DWT menu item widget events. * * @return a listener for menu item events */ private Listener getMenuItemListener() { if (menuItemListener is null) { menuItemListener = new class Listener { public void handleEvent(Event event) { switch (event.type) { case DWT.Dispose: handleWidgetDispose(event); break; case DWT.Selection: Widget ew = event.widget; if (ew !is null) { handleWidgetSelection(event, (cast(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 DWT tool item widget events. * * @return a listener for tool item events */ private Listener getToolItemListener() { if (toolItemListener is null) { toolItemListener = new class Listener { public void handleEvent(Event event) { switch (event.type) { case DWT.Dispose: handleWidgetDispose(event); break; case DWT.Selection: Widget ew = event.widget; if (ew !is null) { handleWidgetSelection(event, (cast(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 is widget) { // Dispose of the menu creator. if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { IMenuCreator mc = action.getMenuCreator(); if (mc !is null) { mc.dispose(); } } // Unhook all of the listeners. action.removePropertyChangeListener(propertyListener); if (action !is null) { String commandId = action.getActionDefinitionId(); ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); if ((callback !is null) && (commandId !is null)) { callback.removePropertyChangeListener(commandId, actionTextListener); } } // Clear the widget field. widget = null; disposeOldImages(); } } /** * Handles a widget selection event. */ private void handleWidgetSelection(Event e, bool selection) { Widget item = e.widget; if (item !is null) { int style = item.getStyle(); if ((style & (DWT.TOGGLE | DWT.CHECK)) !is 0) { if (action.getStyle() is IAction.AS_CHECK_BOX) { action.setChecked(selection); } } else if ((style & DWT.RADIO) !is 0) { if (action.getStyle() is IAction.AS_RADIO_BUTTON) { action.setChecked(selection); } } else if ((style & DWT.DROP_DOWN) !is 0) { if (e.detail is 4) { // on drop-down button if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { IMenuCreator mc = action.getMenuCreator(); ToolItem ti = cast(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 DWT control we would get an DWT // error... // Menu dummy= new Menu(ti.getParent()); // Menu m= mc.getMenu(dummy); // dummy.dispose(); if (mc !is null) { Menu m = mc.getMenu(ti.getParent()); if (m !is null) { // position the menu below the drop down item Rectangle b = ti.getBounds(); Point p = ti.getParent().toDisplay( new Point(b.x, b.y + b.height)); m.setLocation(p.x, p.y); // waiting for DWT // 0.42 m.setVisible(true); return; // we don't fire the action } } } } } // Ensure action is enabled first. // See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be // executed while disabled. if (action.isEnabled()) { bool trace = Policy.TRACE_ACTIONS; long ms = 0L; if (trace) { ms = System.currentTimeMillis(); Stdout.formatln("Running action: {}", action.getText()); //$NON-NLS-1$ } action.runWithEvent(e); if (trace) { Stdout.formatln("{} ms to run action: {}",(System.currentTimeMillis() - ms), action.getText()); //$NON-NLS-1$ } } } } /* * (non-Javadoc) Method declared on Object. */ public override hash_t toHash() { return (cast(Object)action).toHash(); } /** * 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 bool hasImages(IAction actionToCheck) { return actionToCheck.getImageDescriptor() !is null || actionToCheck.getHoverImageDescriptor() !is null || actionToCheck.getDisabledImageDescriptor() !is null; } /** * Returns whether the command corresponding to this action is active. */ private bool isCommandActive() { IAction actionToCheck = getAction(); if (actionToCheck !is null) { String commandId = actionToCheck.getActionDefinitionId(); ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); if (callback !is 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 bool isDynamic() { if (cast(MenuItem)widget ) { // Optimization. Only recreate the item is the check or radio style // has changed. bool itemIsCheck = (widget.getStyle() & DWT.CHECK) !is 0; bool actionIsCheck = getAction() !is null && getAction().getStyle() is IAction.AS_CHECK_BOX; bool itemIsRadio = (widget.getStyle() & DWT.RADIO) !is 0; bool actionIsRadio = getAction() !is null && getAction().getStyle() is IAction.AS_RADIO_BUTTON; return (itemIsCheck !is actionIsCheck) || (itemIsRadio !is actionIsRadio); } return false; } /* * (non-Javadoc) Method declared on IContributionItem. */ public bool isEnabled() { return action !is 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 bool isEnabledAllowed() { if (getParent() is null) { return true; } auto value = getParent().getOverrides().getEnabled(this); return (value is null) ? true : value.value; } /** * 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 bool 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 !is null) { // determine what to do bool textChanged = propertyName is null || propertyName.equals(IAction.TEXT); bool imageChanged = propertyName is null || propertyName.equals(IAction.IMAGE); bool tooltipTextChanged = propertyName is null || propertyName.equals(IAction.TOOL_TIP_TEXT); bool enableStateChanged = propertyName is null || propertyName.equals(IAction.ENABLED) || propertyName .equals(IContributionManagerOverrides.P_ENABLED); bool checkChanged = (action.getStyle() is IAction.AS_CHECK_BOX || action .getStyle() is IAction.AS_RADIO_BUTTON) && (propertyName is null || propertyName .equals(IAction.CHECKED)); if (cast(ToolItem)widget ) { ToolItem ti = cast(ToolItem) widget; String text = action.getText(); // the set text is shown only if there is no image or if forced // by MODE_FORCE_TEXT bool showText = text !is null && ((getMode() & MODE_FORCE_TEXT) !is 0 || !hasImages(action)); // only do the trimming if the text will be used if (showText && text !is null) { text = Action.removeAcceleratorText(text); text = Action.removeMnemonics(text); } if (textChanged) { String textToSet = showText ? text : ""; //$NON-NLS-1$ bool rightStyle = (ti.getParent().getStyle() & DWT.RIGHT) !is 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 DWT.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 is null) || (toolTip.length is 0)) { toolTip = text; } ExternalActionManager.ICallback callback = ExternalActionManager .getInstance().getCallback(); String commandId = action.getActionDefinitionId(); if ((callback !is null) && (commandId !is null) && (toolTip !is null)) { String acceleratorText = callback.getAcceleratorText(commandId); if (acceleratorText !is null && acceleratorText.length !is 0) { toolTip = JFaceResources.format( "Toolbar_Tooltip_Accelerator", //$NON-NLS-1$ [ toolTip, acceleratorText ]); } } // if the text is showing, then only set the tooltip if // different if (!showText || toolTip !is null && !toolTip.equals(text)) { ti.setToolTipText(toolTip); } else { ti.setToolTipText(null); } } if (enableStateChanged) { bool shouldBeEnabled = action.isEnabled() && isEnabledAllowed(); if (ti.getEnabled() !is shouldBeEnabled) { ti.setEnabled(shouldBeEnabled); } } if (checkChanged) { bool bv = action.isChecked(); if (ti.getSelection() !is bv) { ti.setSelection(bv); } } return; } if (cast(MenuItem)widget ) { MenuItem mi = cast(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 !is 0) && (callback !is 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]". */ String commandId = updatedAction .getActionDefinitionId(); if (("gtk".equals(DWT.getPlatform())) && (cast(ExternalActionManager.IBindingManagerCallback)callback ) //$NON-NLS-1$ && (commandId !is null)) { ExternalActionManager.IBindingManagerCallback bindingManagerCallback = cast(ExternalActionManager.IBindingManagerCallback) callback; IKeyLookup lookup = KeyLookupFactory.getDefault(); TriggerSequence[] triggerSequences = bindingManagerCallback .getActiveBindingsFor(commandId); for (int i = 0; i < triggerSequences.length; i++) { TriggerSequence triggerSequence = triggerSequences[i]; Trigger[] triggers = triggerSequence .getTriggers(); if (triggers.length is 1) { Trigger trigger = triggers[0]; if (cast(KeyStroke)trigger ) { KeyStroke currentKeyStroke = cast(KeyStroke) trigger; int currentNaturalKey = currentKeyStroke .getNaturalKey(); if ((currentKeyStroke.getModifierKeys() is (lookup .getCtrl() | lookup.getShift())) && ((currentNaturalKey >= '0' && currentNaturalKey <= '9') || (currentNaturalKey >= 'A' && currentNaturalKey <= 'F') || (currentNaturalKey is 'U'))) { accelerator = currentKeyStroke .getModifierKeys() | currentNaturalKey; acceleratorText = triggerSequence .format(); break; } } } } } if (accelerator is 0) { if ((callback !is null) && (commandId !is null)) { acceleratorText = callback .getAcceleratorText(commandId); } } IContributionManagerOverrides overrides = null; if (getParent() !is null) { overrides = getParent().getOverrides(); } if (overrides !is null) { text = getParent().getOverrides().getText(this); } mi.setAccelerator(accelerator); if (text is null) { text = updatedAction.getText(); } if (text !is null && acceleratorText is 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 is null && accelerator !is 0) { acceleratorText= Action.convertAccelerator(accelerator); } } if (text is null) { text = ""; //$NON-NLS-1$ } else { text = Action.removeAcceleratorText(text); } if (acceleratorText is null) { mi.setText(text); } else { mi.setText(text ~ '\t' ~ acceleratorText); } } if (imageChanged) { updateImages(false); } if (enableStateChanged) { bool shouldBeEnabled = action.isEnabled() && isEnabledAllowed(); if (mi.getEnabled() !is shouldBeEnabled) { mi.setEnabled(shouldBeEnabled); } } if (checkChanged) { bool bv = action.isChecked(); if (mi.getSelection() !is bv) { mi.setSelection(bv); } } return; } if (cast(Button)widget ) { Button button = cast(Button) widget; if (imageChanged && updateImages(false)) { textChanged = false; // don't update text if it has an // image } if (textChanged) { String text = action.getText(); if (text is null) { text = ""; //$NON-NLS-1$ } else { text = Action.removeAcceleratorText(text); } button.setText(text); } if (tooltipTextChanged) { button.setToolTipText(action.getToolTipText()); } if (enableStateChanged) { bool shouldBeEnabled = action.isEnabled() && isEnabledAllowed(); if (button.getEnabled() !is shouldBeEnabled) { button.setEnabled(shouldBeEnabled); } } if (checkChanged) { bool bv = action.isChecked(); if (button.getSelection() !is 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 bool updateImages(bool forceImage) { ResourceManager parentResourceManager = JFaceResources.getResources(); if (cast(ToolItem)widget ) { if (USE_COLOR_ICONS) { ImageDescriptor image = action.getHoverImageDescriptor(); if (image is null) { image = action.getImageDescriptor(); } ImageDescriptor disabledImage = action .getDisabledImageDescriptor(); // Make sure there is a valid image. if (image is null && forceImage) { image = ImageDescriptor.getMissingImageDescriptor(); } LocalResourceManager localManager = new LocalResourceManager( parentResourceManager); // performance: more efficient in DWT to set disabled and hot // image before regular image (cast(ToolItem) widget) .setDisabledImage(disabledImage is null ? null : localManager .createImageWithDefault(disabledImage)); (cast(ToolItem) widget).setImage(image is null ? null : localManager.createImageWithDefault(image)); disposeOldImages(); imageManager = localManager; return image !is 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 is null && hoverImage !is null) { image = ImageDescriptor.createWithFlags(action .getHoverImageDescriptor(), DWT.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 is null && image !is null) { hoverImage = image; image = ImageDescriptor.createWithFlags(action .getImageDescriptor(), DWT.IMAGE_GRAY); } } // Make sure there is a valid image. if (hoverImage is null && image is 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 DWT to set disabled and hot image // before regular image (cast(ToolItem) widget).setDisabledImage(disabledImage is null ? null : localManager.createImageWithDefault(disabledImage)); (cast(ToolItem) widget).setHotImage(hoverImage is null ? null : localManager.createImageWithDefault(hoverImage)); (cast(ToolItem) widget).setImage(image is null ? null : localManager .createImageWithDefault(image)); // Now that we're no longer referencing the old images, clear them // out. disposeOldImages(); imageManager = localManager; return image !is null; } else if (cast(Item)widget || cast(Button)widget ) { // Use hover image if there is one, otherwise use regular image. ImageDescriptor image = action.getHoverImageDescriptor(); if (image is null) { image = action.getImageDescriptor(); } // Make sure there is a valid image. if (image is 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 (cast(Item)widget) { (cast(Item) widget).setImage(image is null ? null : localManager .createImageWithDefault(image)); } else if (cast(Button)widget) { (cast(Button) widget).setImage(image is null ? null : localManager .createImageWithDefault(image)); } // Now that we're no longer referencing the old images, clear them // out. disposeOldImages(); imageManager = localManager; return image !is null; } return false; } /** * Dispose any images allocated for this contribution item */ private void disposeOldImages() { if (imageManager !is 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 is 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; } }