Mercurial > projects > dwt-addons
diff dwtx/jface/action/ContributionManager.d @ 16:e0f0aaf75edd
PopupDialog, bindings and actions
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 01 Apr 2008 08:00:31 +0200 |
parents | |
children | da5ad8eedf5d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/action/ContributionManager.d Tue Apr 01 08:00:31 2008 +0200 @@ -0,0 +1,594 @@ +/******************************************************************************* + * 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.ContributionManager; + +import dwtx.jface.action.ActionContributionItem; + +import dwtx.jface.action.IContributionManager; +import dwtx.jface.action.IContributionItem; +import dwtx.jface.action.IContributionManagerOverrides; +import dwtx.jface.action.IAction; + +import tango.util.collection.ArraySeq; +import tango.util.collection.model.Seq; + +import dwtx.jface.util.Policy; + +import dwt.dwthelper.utils; +import dwt.dwthelper.Integer; +import tango.io.Stdout; +import tango.core.Exception; +import tango.text.convert.Format; + +/** + * Abstract base class for all contribution managers, and standard + * implementation of <code>IContributionManager</code>. This class provides + * functionality common across the specific managers defined by this framework. + * <p> + * This class maintains a list of contribution items and a dirty flag, both as + * internal state. In addition to providing implementations of most + * <code>IContributionManager</code> methods, this class automatically + * coalesces adjacent separators, hides beginning and ending separators, and + * deals with dynamically changing sets of contributions. When the set of + * contributions does change dynamically, the changes are propagated to the + * control via the <code>update</code> method, which subclasses must + * implement. + * </p> + * <p> + * Note: A <code>ContributionItem</code> cannot be shared between different + * <code>ContributionManager</code>s. + * </p> + */ +public abstract class ContributionManager : IContributionManager { + + // Internal debug flag. + // protected static final bool DEBUG = false; + + /** + * The list of contribution items. + */ + private Seq!(IContributionItem) contributions; + + /** + * Indicates whether the widgets are in sync with the contributions. + */ + private bool isDirty_ = true; + + /** + * Number of dynamic contribution items. + */ + private int dynamicItems = 0; + + /** + * The overrides for items of this manager + */ + private IContributionManagerOverrides overrides; + + /** + * Creates a new contribution manager. + */ + protected this() { + contributions = new ArraySeq!(IContributionItem); + // Do nothing. + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void add(IAction action) { + add(new ActionContributionItem(action)); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void add(IContributionItem item) { + if (allowItem(item)) { + contributions.append(item); + itemAdded(item); + } + } + + /** + * Adds a contribution item to the start or end of the group with the given + * name. + * + * @param groupName + * the name of the group + * @param item + * the contribution item + * @param append + * <code>true</code> to add to the end of the group, and + * <code>false</code> to add the beginning of the group + * @exception IllegalArgumentException + * if there is no group with the given name + */ + private void addToGroup(String groupName, IContributionItem item, + bool append) { + int i; + auto items = contributions.elements(); + for (i = 0; items.more(); i++) { + IContributionItem o = cast(IContributionItem) items.get(); + if (o.isGroupMarker()) { + String id = o.getId(); + if (id !is null && id.equalsIgnoreCase(groupName)) { + i++; + if (append) { + for (; items.more(); i++) { + IContributionItem ci = cast(IContributionItem) items + .get(); + if (ci.isGroupMarker()) { + break; + } + } + } + if (allowItem(item)) { + //TODO: does this corrupt the iterator? + contributions.addAt(i, item); + itemAdded(item); + } + return; + } + } + } + throw new IllegalArgumentException("Group not found: " ~ groupName);//$NON-NLS-1$ + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void appendToGroup(String groupName, IAction action) { + addToGroup(groupName, new ActionContributionItem(action), true); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void appendToGroup(String groupName, IContributionItem item) { + addToGroup(groupName, item, true); + } + + /** + * This method allows subclasses of <code>ContributionManager</code> to + * prevent certain items in the contributions list. + * <code>ContributionManager</code> will either block or allow an addition + * based on the result of this method call. This can be used to prevent + * duplication, for example. + * + * @param itemToAdd + * The contribution item to be added; may be <code>null</code>. + * @return <code>true</code> if the addition should be allowed; + * <code>false</code> otherwise. The default implementation allows + * all items. + * @since 3.0 + */ + protected bool allowItem(IContributionItem itemToAdd) { + return true; + } + + /** + * Internal debug method for printing statistics about this manager to + * <code>System.out</code>. + */ + protected void dumpStatistics() { + int size = 0; + if (contributions !is null) { + size = contributions.size(); + } + + Stdout.formatln(this.toString()); + Stdout.formatln(" Number of elements: {}", size);//$NON-NLS-1$ + int sum = 0; + for (int i = 0; i < size; i++) { + if ((cast(IContributionItem) contributions.get(i)).isVisible()) { + sum++; + } + } + Stdout.formatln(" Number of visible elements: {}", sum);//$NON-NLS-1$ + Stdout.formatln(" Is dirty: {}", isDirty()); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public IContributionItem find(String id) { + auto e = contributions.elements(); + while (e.more()) { + IContributionItem item = cast(IContributionItem) e.get(); + String itemId = item.getId(); + if (itemId !is null && itemId.equalsIgnoreCase(id)) { + return item; + } + } + return null; + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public IContributionItem[] getItems() { + return contributions.toArray(); + } + + /** + * Return the number of contributions in this manager. + * + * @return the number of contributions in this manager + * @since 3.3 + */ + public int getSize() { + return contributions.size(); + } + + /** + * The <code>ContributionManager</code> implementation of this method + * declared on <code>IContributionManager</code> returns the current + * overrides. If there is no overrides it lazily creates one which overrides + * no item state. + * + * @since 2.0 + */ + public IContributionManagerOverrides getOverrides() { + if (overrides is null) { + overrides = new class IContributionManagerOverrides { + public ValueWrapperBool getEnabled(IContributionItem item) { + return null; + } + + public ValueWrapperInt getAccelerator(IContributionItem item) { + return null; + } + + public String getAcceleratorText(IContributionItem item) { + return null; + } + + public String getText(IContributionItem item) { + return null; + } + }; + } + return overrides; + } + + /** + * Returns whether this contribution manager contains dynamic items. A + * dynamic contribution item contributes items conditionally, dependent on + * some internal state. + * + * @return <code>true</code> if this manager contains dynamic items, and + * <code>false</code> otherwise + */ + protected bool hasDynamicItems() { + return (dynamicItems > 0); + } + + /** + * Returns the index of the item with the given id. + * + * @param id + * The id of the item whose index is requested. + * + * @return <code>int</code> the index or -1 if the item is not found + */ + public int indexOf(String id) { + for (int i = 0; i < contributions.size(); i++) { + IContributionItem item = cast(IContributionItem) contributions.get(i); + String itemId = item.getId(); + if (itemId !is null && itemId.equalsIgnoreCase(id)) { + return i; + } + } + return -1; + } + + /** + * Returns the index of the object in the internal structure. This is + * different from <code>indexOf(String id)</code> since some contribution + * items may not have an id. + * + * @param item + * The contribution item + * @return the index, or -1 if the item is not found + * @since 3.0 + */ + protected int indexOf(IContributionItem item) { + int res = -1; + int idx = 0; + foreach( e; contributions ){ + if( e == item ) { + res = idx; + break; + } + idx++; + } + return res; + } + + /** + * Insert the item at the given index. + * + * @param index + * The index to be used for insertion + * @param item + * The item to be inserted + */ + public void insert(int index, IContributionItem item) { + if (index > contributions.size()) { + throw new IndexOutOfBoundsException( Format( + "inserting {} at {}", item.getId(), index)); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (allowItem(item)) { + contributions.addAt(index, item); + itemAdded(item); + } + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void insertAfter(String ID, IAction action) { + insertAfter(ID, new ActionContributionItem(action)); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void insertAfter(String ID, IContributionItem item) { + IContributionItem ci = find(ID); + if (ci is null) { + throw new IllegalArgumentException(Format("can't find ID{}", ID));//$NON-NLS-1$ + } + int ix = SeqIndexOf!(IContributionItem)( contributions, ci ); + if (ix >= 0) { + // System.out.println("insert after: " + ix); + if (allowItem(item)) { + contributions.addAt(ix + 1, item); + itemAdded(item); + } + } + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void insertBefore(String ID, IAction action) { + insertBefore(ID, new ActionContributionItem(action)); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void insertBefore(String ID, IContributionItem item) { + IContributionItem ci = find(ID); + if (ci is null) { + throw new IllegalArgumentException(Format("can't find ID {}", ID));//$NON-NLS-1$ + } + int ix = SeqIndexOf!(IContributionItem)(contributions,ci); + if (ix >= 0) { + // System.out.println("insert before: " + ix); + if (allowItem(item)) { + contributions.addAt(ix, item); + itemAdded(item); + } + } + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public bool isDirty() { + if (isDirty_) { + return true; + } + if (hasDynamicItems()) { + foreach( e; contributions ){ + IContributionItem item = cast(IContributionItem) e; + if (item.isDirty()) { + return true; + } + } + } + return false; + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public bool isEmpty() { + return contributions.drained(); + } + + /** + * The given item was added to the list of contributions. Marks the manager + * as dirty and updates the number of dynamic items, and the memento. + * + * @param item + * the item to be added + * + */ + protected void itemAdded(IContributionItem item) { + item.setParent(this); + markDirty(); + if (item.isDynamic()) { + dynamicItems++; + } + } + + /** + * The given item was removed from the list of contributions. Marks the + * manager as dirty and updates the number of dynamic items. + * + * @param item + * remove given parent from list of contributions + */ + protected void itemRemoved(IContributionItem item) { + item.setParent(null); + markDirty(); + if (item.isDynamic()) { + dynamicItems--; + } + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void markDirty() { + setDirty(true); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void prependToGroup(String groupName, IAction action) { + addToGroup(groupName, new ActionContributionItem(action), false); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void prependToGroup(String groupName, IContributionItem item) { + addToGroup(groupName, item, false); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public IContributionItem remove(String ID) { + IContributionItem ci = find(ID); + if (ci is null) { + return null; + } + return remove(ci); + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public IContributionItem remove(IContributionItem item) { + bool contained = contributions.contains(item); + contributions.remove(item); + if (contained) { + itemRemoved(item); + return item; + } + return null; + } + + /* + * (non-Javadoc) Method declared on IContributionManager. + */ + public void removeAll() { + IContributionItem[] items = getItems(); + contributions.clear(); + for (int i = 0; i < items.length; i++) { + IContributionItem item = items[i]; + itemRemoved(item); + } + dynamicItems = 0; + markDirty(); + } + + /** + * Replaces the item of the given identifier with another contribution item. + * This can be used, for example, to replace large contribution items with + * placeholders to avoid memory leaks. If the identifier cannot be found in + * the current list of items, then this does nothing. If multiple + * occurrences are found, then the replacement items is put in the first + * position and the other positions are removed. + * + * @param identifier + * The identifier to look for in the list of contributions; + * should not be <code>null</code>. + * @param replacementItem + * The contribution item to replace the old item; must not be + * <code>null</code>. Use + * {@link dwtx.jface.action.ContributionManager#remove(java.lang.String) remove} + * if that is what you want to do. + * @return <code>true</code> if the given identifier can be; <code> + * @since 3.0 + */ + public bool replaceItem(String identifier, + IContributionItem replacementItem) { + if (identifier is null) { + return false; + } + + int index = indexOf(identifier); + if (index < 0) { + return false; // couldn't find the item. + } + + // Remove the old item. + IContributionItem oldItem = cast(IContributionItem) contributions + .get(index); + itemRemoved(oldItem); + + // Add the new item. + contributions.replaceAt(index, replacementItem); + itemAdded(replacementItem); // throws NPE if (replacementItem is null) + + // Go through and remove duplicates. + for (int i = contributions.size() - 1; i > index; i--) { + IContributionItem item = cast(IContributionItem) contributions.get(i); + if ((item !is null) && (identifier.equals(item.getId()))) { + if (Policy.TRACE_TOOLBAR) { + Stdout.formatln("Removing duplicate on replace: {}", identifier); //$NON-NLS-1$ + } + contributions.removeAt(i); + itemRemoved(item); + } + } + + return true; // success + } + + /** + * Sets whether this manager is dirty. When dirty, the list of contributions + * is not accurately reflected in the corresponding widgets. + * + * @param dirty + * <code>true</code> if this manager is dirty, and + * <code>false</code> if it is up-to-date + */ + protected void setDirty(bool dirty) { + isDirty_ = dirty; + } + + /** + * Sets the overrides for this contribution manager + * + * @param newOverrides + * the overrides for the items of this manager + * @since 2.0 + */ + public void setOverrides(IContributionManagerOverrides newOverrides) { + overrides = newOverrides; + } + + /** + * An internal method for setting the order of the contribution items. + * + * @param items + * the contribution items in the specified order + * @since 3.0 + */ + protected void internalSetItems(IContributionItem[] items) { + contributions.clear(); + for (int i = 0; i < items.length; i++) { + if (allowItem(items[i])) { + contributions.append(items[i]); + } + } + } +}