Mercurial > projects > dwt-addons
diff dwtx/jface/action/ActionContributionItem.d @ 70:46a6e0e6ccd4
Merge with d-fied sources of 3.4M7
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 22 May 2008 01:36:46 +0200 |
parents | ea8ff534f622 |
children | 4878bef4a38e |
line wrap: on
line diff
--- a/dwtx/jface/action/ActionContributionItem.d Mon May 19 13:41:06 2008 +0200 +++ b/dwtx/jface/action/ActionContributionItem.d Thu May 22 01:36:46 2008 +0200 @@ -22,7 +22,6 @@ 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; @@ -35,6 +34,8 @@ import dwt.widgets.ToolItem; import dwt.widgets.Widget; import dwtx.jface.action.ExternalActionManager; +import dwtx.core.commands.ExecutionException; +import dwtx.core.commands.NotEnabledException; import dwtx.jface.bindings.Trigger; import dwtx.jface.bindings.TriggerSequence; import dwtx.jface.bindings.keys.IKeyLookup; @@ -61,11 +62,11 @@ */ public class ActionContributionItem : ContributionItem { alias ContributionItem.fill fill; - + /** - * 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. + * 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.0 */ @@ -74,6 +75,11 @@ /** a string inserted in the middle of text that has been shortened */ private static const String ellipsis = "..."; //$NON-NLS-1$ + /** + * Stores the result of the action. False when the action returned failure. + */ + private Boolean result = null; + private static bool USE_COLOR_ICONS = true; /** @@ -144,6 +150,8 @@ */ private Widget widget = null; + private Listener menuCreatorListener; + /** * Creates a new contribution item from the given action. The id of the * action is used as the id of the item. @@ -262,7 +270,6 @@ */ public override 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(); @@ -271,11 +278,7 @@ } 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; - } + flags = DWT.CASCADE; } } @@ -294,7 +297,12 @@ mi.addHelpListener(action.getHelpListener()); } - if (subMenu !is null) { + if (flags is DWT.CASCADE) { + // just create a proxy for now, if the user shows it then + // fill it in + Menu subMenu = new Menu(parent); + subMenu.addListener(DWT.Show, getMenuCreatorListener()); + subMenu.addListener(DWT.Hide, getMenuCreatorListener()); mi.setMenu(subMenu); } @@ -477,7 +485,8 @@ // 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) { + if (action.getStyle() is IAction.AS_DROP_DOWN_MENU + && menuCreatorCalled) { IMenuCreator mc = action.getMenuCreator(); if (mc !is null) { mc.dispose(); @@ -525,6 +534,7 @@ if (e.detail is 4) { // on drop-down button if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { IMenuCreator mc = action.getMenuCreator(); + menuCreatorCalled = true; ToolItem ti = cast(ToolItem) item; // we create the menu as a sub-menu of "dummy" so that // we can use @@ -538,11 +548,11 @@ 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 + Point point = ti.getParent().toDisplay( + new Point(e.x, e.y)); + m.setLocation(point.x, point.y); // waiting + // for DWT + // 0.42 m.setVisible(true); return; // we don't fire the action } @@ -551,6 +561,16 @@ } } + ExternalActionManager.IExecuteCallback callback = null; + String actionDefinitionId = action.getActionDefinitionId(); + if (actionDefinitionId !is null) { + Object obj = ExternalActionManager.getInstance() + .getCallback(); + if (obj instanceof ExternalActionManager.IExecuteCallback) { + callback = (ExternalActionManager.IExecuteCallback) obj; + } + } + // Ensure action is enabled first. // See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be // executed while disabled. @@ -561,13 +581,49 @@ if (trace) { ms = System.currentTimeMillis(); Stdout.formatln("Running action: {}", action.getText()); //$NON-NLS-1$ + } + + IPropertyChangeListener resultListener = null; + if (callback !is null) { + resultListener = new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + // Check on result + if (event.getProperty().equals(IAction.RESULT)) { + if (event.getNewValue() instanceof Boolean) { + result = (Boolean) event.getNewValue(); + } + } + } + }; + action.addPropertyChangeListener(resultListener); + callback.preExecute(action, e); } action.runWithEvent(e); + if (callback !is null) { + if (result is null || result.equals(Boolean.TRUE)) { + callback.postExecuteSuccess(action, Boolean.TRUE); + } else { + callback.postExecuteFailure(action, + new ExecutionException(action.getText() + + " returned failure.")); //$NON-NLS-1$ + } + } + + if (resultListener!isnull) { + result = null; + action.removePropertyChangeListener(resultListener); + } if (trace) { Stdout.formatln("{} ms to run action: {}",(System.currentTimeMillis() - ms), action.getText()); //$NON-NLS-1$ } + } else { + if (callback !is null) { + callback.notEnabled(action, new NotEnabledException(action + .getText() + + " is not enabled.")); //$NON-NLS-1$ + } } } } @@ -753,9 +809,12 @@ 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) { + 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 ]); @@ -872,10 +931,14 @@ } 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); + // 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); + acceleratorText = Action + .convertAccelerator(accelerator); } } @@ -919,19 +982,19 @@ 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 (imageChanged) { + updateImages(false); } if (textChanged) { String text = action.getText(); - if (text is null) { - text = ""; //$NON-NLS-1$ - } else { + 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 = Action.removeAcceleratorText(text); } - button.setText(text); + String textToSet = showText ? text : ""; //$NON-NLS-1$ + button.setText(textToSet); } if (tooltipTextChanged) { @@ -1134,4 +1197,187 @@ // If for some reason we fall through abort return textValue; } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.ContributionItem#dispose() + */ + public void dispose() { + if (widget !is null) { + widget.dispose(); + widget = null; + } + holdMenu = null; + } + + /** + * Handle show and hide on the proxy menu for IAction.AS_DROP_DOWN_MENU + * actions. + * + * @return the appropriate listener + * @since 3.4 + */ + private Listener getMenuCreatorListener() { + if (menuCreatorListener is null) { + menuCreatorListener = new Listener() { + public void handleEvent(Event event) { + switch (event.type) { + case DWT.Show: + handleShowProxy((Menu) event.widget); + break; + case DWT.Hide: + handleHideProxy((Menu) event.widget); + break; + } + } + }; + } + return menuCreatorListener; + } + + /** + * This is the easiest way to hold the menu until we can swap it in to the + * proxy. + */ + private Menu holdMenu = null; + + private bool menuCreatorCalled = false; + + /** + * The proxy menu is being shown, we better get the real menu. + * + * @param proxy + * the proxy menu + * @since 3.4 + */ + private void handleShowProxy(Menu proxy) { + proxy.removeListener(DWT.Show, getMenuCreatorListener()); + IMenuCreator mc = action.getMenuCreator(); + menuCreatorCalled = true; + if (mc is null) { + return; + } + holdMenu = mc.getMenu(proxy.getParentMenu()); + if (holdMenu is null) { + return; + } + copyMenu(holdMenu, proxy); + } + + /** + * Create MenuItems in the proxy menu that can execute the real menu items + * if selected. Create proxy menus for any real item submenus. + * + * @param realMenu + * the real menu to copy from + * @param proxy + * the proxy menu to populate + * @since 3.4 + */ + private void copyMenu(Menu realMenu, Menu proxy) { + if (realMenu.isDisposed() || proxy.isDisposed()) { + return; + } + + // we notify the real menu so it can populate itself if it was + // listening for DWT.Show + realMenu.notifyListeners(DWT.Show, null); + + final Listener passThrough = new Listener() { + public void handleEvent(Event event) { + if (!event.widget.isDisposed()) { + Widget realItem = (Widget) event.widget.getData(); + if (!realItem.isDisposed()) { + int style = event.widget.getStyle(); + if (event.type is DWT.Selection + && ((style & (DWT.TOGGLE | DWT.CHECK)) !is 0) + && realItem instanceof MenuItem) { + ((MenuItem) realItem) + .setSelection(((MenuItem) event.widget) + .getSelection()); + } + event.widget = realItem; + realItem.notifyListeners(event.type, event); + } + } + } + }; + + MenuItem[] items = realMenu.getItems(); + for (int i = 0; i < items.length; i++) { + final MenuItem realItem = items[i]; + final MenuItem proxyItem = new MenuItem(proxy, realItem.getStyle()); + proxyItem.setData(realItem); + proxyItem.setAccelerator(realItem.getAccelerator()); + proxyItem.setEnabled(realItem.getEnabled()); + proxyItem.setImage(realItem.getImage()); + proxyItem.setSelection(realItem.getSelection()); + proxyItem.setText(realItem.getText()); + + // pass through any events + proxyItem.addListener(DWT.Selection, passThrough); + proxyItem.addListener(DWT.Arm, passThrough); + proxyItem.addListener(DWT.Help, passThrough); + + final Menu itemMenu = realItem.getMenu(); + if (itemMenu !is null) { + // create a proxy for any sub menu items + final Menu subMenu = new Menu(proxy); + subMenu.setData(itemMenu); + proxyItem.setMenu(subMenu); + subMenu.addListener(DWT.Show, new Listener() { + public void handleEvent(Event event) { + event.widget.removeListener(DWT.Show, this); + if (event.type is DWT.Show) { + copyMenu(itemMenu, subMenu); + } + } + }); + subMenu.addListener(DWT.Help, passThrough); + subMenu.addListener(DWT.Hide, passThrough); + } + } + } + + /** + * The proxy menu is being hidden, so we need to make it go away. + * + * @param proxy + * the proxy menu + * @since 3.4 + */ + private void handleHideProxy(final Menu proxy) { + proxy.removeListener(DWT.Hide, getMenuCreatorListener()); + proxy.getDisplay().asyncExec(new Runnable() { + public void run() { + if (!proxy.isDisposed()) { + MenuItem parentItem = proxy.getParentItem(); + proxy.dispose(); + parentItem.setMenu(holdMenu); + } + if (holdMenu !is null && !holdMenu.isDisposed()) { + holdMenu.notifyListeners(DWT.Hide, null); + } + holdMenu = null; + } + }); + } + + /** + * Return the widget associated with this contribution item. It should not + * be cached, as it can be disposed and re-created by its containing + * ContributionManager, which controls all of the widgets lifecycle methods. + * <p> + * This can be used to set layout data on the widget if appropriate. The + * actual type of the widget can be any valid control for this + * ContributionItem's current ContributionManager. + * </p> + * + * @return the widget, or <code>null</code> depending on the lifecycle. + * @since 3.4 + */ + public Widget getWidget() { + return widget; + } }