Mercurial > projects > dwt-addons
diff dwtx/jface/action/ToolBarContributionItem.d @ 25:ca63e2bea4bf
CoolBarManager
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 03 Apr 2008 04:50:25 +0200 |
parents | |
children | ea8ff534f622 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/action/ToolBarContributionItem.d Thu Apr 03 04:50:25 2008 +0200 @@ -0,0 +1,691 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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.ToolBarContributionItem; + +import dwtx.jface.action.IContributionItem; +import dwtx.jface.action.ContributionItem; +import dwtx.jface.action.MenuManager; +import dwtx.jface.action.IToolBarManager; +import dwtx.jface.action.ToolBarManager; +import dwtx.jface.action.ActionContributionItem; +import dwtx.jface.action.SubContributionItem; +import dwtx.jface.action.ICoolBarManager; +import dwtx.jface.action.Separator; +import dwtx.jface.action.IContributionManager; + +import tango.util.collection.ArraySeq; +// import java.util.Iterator; + +import dwt.DWT; +import dwt.events.DisposeEvent; +import dwt.events.DisposeListener; +import dwt.events.SelectionAdapter; +import dwt.events.SelectionEvent; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Control; +import dwt.widgets.CoolBar; +import dwt.widgets.CoolItem; +import dwt.widgets.Event; +import dwt.widgets.Listener; +import dwt.widgets.Menu; +import dwt.widgets.ToolBar; +import dwt.widgets.ToolItem; +import dwtx.core.runtime.Assert; +import dwtx.jface.internal.provisional.action.IToolBarContributionItem; +import dwtx.jface.util.Policy; + +import dwt.dwthelper.utils; +import tango.io.Stdout; + +/** + * The <code>ToolBarContributionItem</code> class provides a wrapper for tool + * bar managers when used in cool bar managers. It extends <code>ContributionItem</code> + * but and provides some additional methods to customize the size of the cool + * item and to retrieve the underlying tool bar manager. + * <p> + * This class may be instantiated; it is not intended to be subclassed. + * </p> + * + * @since 3.0 + */ +public class ToolBarContributionItem : ContributionItem, IToolBarContributionItem { + + public IContributionManager getParent() { + return super.getParent(); + } + + /** + * A constant used by <code>setMinimumItemsToShow</code> and <code>getMinimumItemsToShow</code> + * to indicate that all tool items should be shown in the cool item. + */ + public static const int SHOW_ALL_ITEMS = -1; + + /** + * The pull down menu used to list all hidden tool items if the current + * size is less than the preffered size. + */ + private MenuManager chevronMenuManager = null; + + /** + * The widget created for this item; <code>null</code> before creation + * and after disposal. + */ + private CoolItem coolItem = null; + + /** + * Current height of cool item + */ + private int currentHeight = -1; + + /** + * Current width of cool item. + */ + private int currentWidth = -1; + + /** + * A flag indicating that this item has been disposed. This prevents future + * method invocations from doing things they shouldn't. + */ + private bool disposed = false; + + /** + * Mininum number of tool items to show in the cool item widget. + */ + private int minimumItemsToShow = SHOW_ALL_ITEMS; + + /** + * The tool bar manager used to manage the tool items contained in the cool + * item widget. + */ + private ToolBarManager toolBarManager = null; + + /** + * Enable/disable chevron support. + */ + private bool useChevron = true; + + /** + * Convenience method equivalent to <code>ToolBarContributionItem(new ToolBarManager(), null)</code>. + */ + public this() { + this(new ToolBarManager(), null); + } + + /** + * Convenience method equivalent to <code>ToolBarContributionItem(toolBarManager, null)</code>. + * + * @param toolBarManager + * the tool bar manager + */ + public this(IToolBarManager toolBarManager) { + this(toolBarManager, null); + } + + /** + * Creates a tool bar contribution item. + * + * @param toolBarManager + * the tool bar manager to wrap + * @param id + * the contribution item id, or <code>null</code> if none + */ + public this(IToolBarManager toolBarManager, String id) { + super(id); + Assert.isTrue( null !is cast(ToolBarManager)toolBarManager ); + this.toolBarManager = cast(ToolBarManager) toolBarManager; + } + + /** + * Checks whether this contribution item has been disposed. If it has, and + * the tracing options are active, then it prints some debugging + * information. + * + * @return <code>true</code> if the item is disposed; <code>false</code> + * otherwise. + * + */ + private final bool checkDisposed() { + if (disposed) { + if (Policy.TRACE_TOOLBAR) { + Stdout.formatln("Method invocation on a disposed tool bar contribution item."); //$NON-NLS-1$ + ExceptionPrintStackTrace( new Exception(null), Stdout ); + } + + return true; + } + + return false; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IContributionItem#dispose() + */ + public void dispose() { + // Dispose of the ToolBar and all its contributions + if (toolBarManager !is null) { + toolBarManager.dispose(); + toolBarManager = null; + } + + /* + * We need to dispose the cool item or we might be left holding a cool + * item with a disposed control. + */ + if ((coolItem !is null) && (!coolItem.isDisposed())) { + coolItem.dispose(); + coolItem = null; + } + + // Mark this item as disposed. + disposed = true; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IContributionItem#fill(dwt.widgets.CoolBar, + * int) + */ + public void fill(CoolBar coolBar, int index) { + if (checkDisposed()) { + return; + } + + if (coolItem is null && coolBar !is null) { + ToolBar oldToolBar = toolBarManager.getControl(); + ToolBar toolBar = toolBarManager.createControl(coolBar); + if ((oldToolBar !is null) && (oldToolBar.opEquals(toolBar))) { + // We are using an old tool bar, so we need to update. + toolBarManager.update(true); + } + + // Do not create a coolItem if the toolbar is empty + if (toolBar.getItemCount() < 1) { + return; + } + int flags = DWT.DROP_DOWN; + if (index >= 0) { + coolItem = new CoolItem(coolBar, flags, index); + } else { + coolItem = new CoolItem(coolBar, flags); + } + // sets the back reference + coolItem.setData(this); + // Add the toolbar to the CoolItem widget + coolItem.setControl(toolBar); + + // Handle Context Menu + // ToolBarManager.createControl can actually return a pre-existing control. + // Only add the listener if the toolbar was newly created (bug 62097). + if (oldToolBar !is toolBar) { + toolBar.addListener(DWT.MenuDetect, new class Listener { + + public void handleEvent(Event event) { + // if the toolbar does not have its own context menu then + // handle the event + if (toolBarManager.getContextMenuManager() is null) { + handleContextMenu(event); + } + } + }); + } + + // Handle for chevron clicking + if (getUseChevron()) { + // Chevron Support + coolItem.addSelectionListener(new class SelectionAdapter { + + public void widgetSelected(SelectionEvent event) { + if (event.detail is DWT.ARROW) { + handleChevron(event); + } + } + }); + } + + // Handle for disposal + coolItem.addDisposeListener(new class DisposeListener { + + public void widgetDisposed(DisposeEvent event) { + handleWidgetDispose(event); + } + }); + + // Sets the size of the coolItem + updateSize(true); + } + } + + /** + * Returns a consistent set of wrap indices. The return value will always + * include at least one entry and the first entry will always be zero. + * CoolBar.getWrapIndices() is inconsistent in whether or not it returns an + * index for the first row. + */ + private int[] getAdjustedWrapIndices(int[] wraps) { + int[] adjustedWrapIndices; + if (wraps.length is 0) { + adjustedWrapIndices = [ 0 ]; + } else { + if (wraps[0] !is 0) { + adjustedWrapIndices = new int[wraps.length + 1]; + adjustedWrapIndices[0] = 0; + for (int i = 0; i < wraps.length; i++) { + adjustedWrapIndices[i + 1] = wraps[i]; + } + } else { + adjustedWrapIndices = wraps; + } + } + return adjustedWrapIndices; + } + + /** + * Returns the current height of the corresponding cool item. + * + * @return the current height + */ + public int getCurrentHeight() { + if (checkDisposed()) { + return -1; + } + return currentHeight; + } + + /** + * Returns the current width of the corresponding cool item. + * + * @return the current size + */ + public int getCurrentWidth() { + if (checkDisposed()) { + return -1; + } + return currentWidth; + } + + /** + * Returns the minimum number of tool items to show in the cool item. + * + * @return the minimum number of tool items to show, or <code>SHOW_ALL_ITEMS</code> + * if a value was not set + * @see #setMinimumItemsToShow(int) + */ + public int getMinimumItemsToShow() { + if (checkDisposed()) { + return -1; + } + return minimumItemsToShow; + } + + /** + * Returns the internal tool bar manager of the contribution item. + * + * @return the tool bar manager, or <code>null</code> if one is not + * defined. + * @see IToolBarManager + */ + public IToolBarManager getToolBarManager() { + if (checkDisposed()) { + return null; + } + return toolBarManager; + } + + /** + * Returns whether chevron support is enabled. + * + * @return <code>true</code> if chevron support is enabled, <code>false</code> + * otherwise + */ + public bool getUseChevron() { + if (checkDisposed()) { + return false; + } + return useChevron; + } + + /** + * Create and display the chevron menu. + */ + private void handleChevron(SelectionEvent event) { + CoolItem item = cast(CoolItem) event.widget; + Control control = item.getControl(); + if (!(cast(ToolBar)control ) ) { + return; + } + CoolBar coolBar = item.getParent(); + ToolBar toolBar = cast(ToolBar) control; + Rectangle toolBarBounds = toolBar.getBounds(); + ToolItem[] items = toolBar.getItems(); + auto hidden = new ArraySeq!(Object); + for (int i = 0; i < items.length; ++i) { + Rectangle itemBounds = items[i].getBounds(); + if (!((itemBounds.x + itemBounds.width <= toolBarBounds.width) && (itemBounds.y + + itemBounds.height <= toolBarBounds.height))) { + hidden.append(items[i]); + } + } + + // Create a pop-up menu with items for each of the hidden buttons. + if (chevronMenuManager !is null) { + chevronMenuManager.dispose(); + } + chevronMenuManager = new MenuManager(); + foreach( it; hidden ){ + ToolItem toolItem = cast(ToolItem) it; + IContributionItem data = cast(IContributionItem) toolItem.getData(); + if (cast(ActionContributionItem)data ) { + ActionContributionItem contribution = new ActionContributionItem( + (cast(ActionContributionItem) data).getAction()); + chevronMenuManager.add(contribution); + } else if (cast(SubContributionItem)data ) { + IContributionItem innerData = (cast(SubContributionItem) data) + .getInnerItem(); + if (cast(ActionContributionItem)innerData ) { + ActionContributionItem contribution = new ActionContributionItem( + (cast(ActionContributionItem) innerData).getAction()); + chevronMenuManager.add(contribution); + } + } else if (data.isSeparator()) { + chevronMenuManager.add(new Separator()); + } + } + Menu popup = chevronMenuManager.createContextMenu(coolBar); + Point chevronPosition = coolBar.toDisplay(event.x, event.y); + popup.setLocation(chevronPosition.x, chevronPosition.y); + popup.setVisible(true); + } + + /** + * Handles the event when the toobar item does not have its own context + * menu. + * + * @param event + * the event object + */ + private void handleContextMenu(Event event) { + ToolBar toolBar = toolBarManager.getControl(); + // If parent has a menu then use that one + Menu parentMenu = toolBar.getParent().getMenu(); + if ((parentMenu !is null) && (!parentMenu.isDisposed())) { + toolBar.setMenu(parentMenu); + // Hook listener to remove menu once it has disapeared + parentMenu.addListener(DWT.Hide, new class Listener { + + public void handleEvent(Event innerEvent) { + ToolBar innerToolBar = toolBarManager.getControl(); + if (innerToolBar !is null) { + innerToolBar.setMenu(null); + Menu innerParentMenu = innerToolBar.getParent() + .getMenu(); + if (innerParentMenu !is null) { + innerParentMenu.removeListener(DWT.Hide, this); + } + } + } + }); + } + } + + /** + * Handles the disposal of the widget. + * + * @param event + * the event object + */ + private void handleWidgetDispose(DisposeEvent event) { + coolItem = null; + } + + /** + * A contribution item is visible iff its internal state is visible <em>or</em> + * the tool bar manager contains something other than group markers and + * separators. + * + * @return <code>true</code> if the tool bar manager contains something + * other than group marks and separators, and the internal state is + * set to be visible. + */ + public bool isVisible() { + if (checkDisposed()) { + return false; + } + + bool visibleItem = false; + if (toolBarManager !is null) { + IContributionItem[] contributionItems = toolBarManager.getItems(); + for (int i = 0; i < contributionItems.length; i++) { + IContributionItem contributionItem = contributionItems[i]; + if ((!contributionItem.isGroupMarker()) + && (!contributionItem.isSeparator())) { + visibleItem = true; + break; + } + } + } + + return (visibleItem || super.isVisible()); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IContributionItem#saveWidgetState() + */ + public void saveWidgetState() { + if (checkDisposed()) { + return; + } + if (coolItem is null) { + return; + } + + //1. Save current size + CoolBar coolBar = coolItem.getParent(); + bool isLastOnRow = false; + int lastIndex = coolBar.getItemCount() - 1; + int coolItemIndex = coolBar.indexOf(coolItem); + int[] wrapIndicies = getAdjustedWrapIndices(coolBar.getWrapIndices()); + // Traverse through all wrap indicies backwards + for (int row = wrapIndicies.length - 1; row >= 0; row--) { + if (wrapIndicies[row] <= coolItemIndex) { + + int nextRow = row + 1; + int nextRowStartIndex; + if (nextRow > (wrapIndicies.length - 1)) { + nextRowStartIndex = lastIndex + 1; + } else { + nextRowStartIndex = wrapIndicies[nextRow]; + } + + // Check to see if its the last item on the row + if (coolItemIndex is (nextRowStartIndex - 1)) { + isLastOnRow = true; + } + break; + } + } + + // Save the preferred size as actual size for the last item on a row + int nCurrentWidth; + if (isLastOnRow) { + nCurrentWidth = coolItem.getPreferredSize().x; + } else { + nCurrentWidth = coolItem.getSize().x; + } + setCurrentWidth(nCurrentWidth); + setCurrentHeight(coolItem.getSize().y); + } + + /** + * Sets the current height of the cool item. Update(SIZE) should be called + * to adjust the widget. + * + * @param currentHeight + * the current height to set + */ + public void setCurrentHeight(int currentHeight) { + if (checkDisposed()) { + return; + } + this.currentHeight = currentHeight; + } + + /** + * Sets the current width of the cool item. Update(SIZE) should be called + * to adjust the widget. + * + * @param currentWidth + * the current width to set + */ + public void setCurrentWidth(int currentWidth) { + if (checkDisposed()) { + return; + } + this.currentWidth = currentWidth; + } + + /** + * Sets the minimum number of tool items to show in the cool item. If this + * number is less than the total tool items, a chevron will appear and the + * hidden tool items appear in a drop down menu. By default, all the tool + * items are shown in the cool item. + * + * @param minimumItemsToShow + * the minimum number of tool items to show. + * @see #getMinimumItemsToShow() + * @see #setUseChevron(bool) + */ + public void setMinimumItemsToShow(int minimumItemsToShow) { + if (checkDisposed()) { + return; + } + this.minimumItemsToShow = minimumItemsToShow; + } + + /** + * Enables or disables chevron support for the cool item. By default, + * chevron support is enabled. + * + * @param value + * <code>true</code> to enable chevron support, <code>false</code> + * otherwise. + */ + public void setUseChevron(bool value) { + if (checkDisposed()) { + return; + } + useChevron = value; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.action.IContributionItem#update(java.lang.String) + */ + public void update(String propertyName) { + if (checkDisposed()) { + return; + } + if (coolItem !is null) { + IToolBarManager manager = getToolBarManager(); + if (manager !is null) { + manager.update(true); + } + + if ((propertyName is null) + || propertyName.equals(ICoolBarManager.SIZE)) { + updateSize(true); + } + } + } + + /** + * Updates the cool items' preferred, minimum, and current size. The + * preferred size is calculated based on the tool bar size and extra trim. + * + * @param changeCurrentSize + * <code>true</code> if the current size should be changed to + * the preferred size, <code>false</code> to not change the + * current size + */ + private void updateSize(bool changeCurrentSize) { + if (checkDisposed()) { + return; + } + // cannot set size if coolItem is null + if (coolItem is null || coolItem.isDisposed()) { + return; + } + bool locked = false; + CoolBar coolBar = coolItem.getParent(); + try { + // Fix odd behaviour with locked tool bars + if (coolBar !is null) { + if (coolBar.getLocked()) { + coolBar.setLocked(false); + locked = true; + } + } + ToolBar toolBar = cast(ToolBar) coolItem.getControl(); + if ((toolBar is null) || (toolBar.isDisposed()) + || (toolBar.getItemCount() <= 0)) { + // if the toolbar does not contain any items then dispose of + // coolItem + coolItem.setData(null); + Control control = coolItem.getControl(); + if ((control !is null) && !control.isDisposed()) { + control.dispose(); + coolItem.setControl(null); + } + if (!coolItem.isDisposed()) { + coolItem.dispose(); + } + } else { + // If the toolbar item exists then adjust the size of the cool + // item + Point toolBarSize = toolBar.computeSize(DWT.DEFAULT, + DWT.DEFAULT); + // Set the preffered size to the size of the toolbar plus trim + Point preferredSize = coolItem.computeSize(toolBarSize.x, + toolBarSize.y); + coolItem.setPreferredSize(preferredSize); + // note setMinimumSize must be called before setSize, see PR + // 15565 + // Set minimum size + if (getMinimumItemsToShow() !is SHOW_ALL_ITEMS) { + int toolItemWidth = toolBar.getItems()[0].getWidth(); + int minimumWidth = toolItemWidth * getMinimumItemsToShow(); + coolItem.setMinimumSize(minimumWidth, toolBarSize.y); + } else { + coolItem.setMinimumSize(toolBarSize.x, toolBarSize.y); + } + if (changeCurrentSize) { + // Set current size to preferred size + coolItem.setSize(preferredSize); + } + } + } finally { + // If the cool bar was locked, then set it back to locked + if ((locked) && (coolBar !is null)) { + coolBar.setLocked(true); + } + } + } + +}