org.eclipse.jface.action.ContributionManager Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.action;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.util.Policy;
/**
* Abstract base class for all contribution managers, and standard
* implementation of IContributionManager
. This class provides
* functionality common across the specific managers defined by this framework.
*
* This class maintains a list of contribution items and a dirty flag, both as
* internal state. In addition to providing implementations of most
* IContributionManager
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 update
method, which subclasses must
* implement.
*
*
* Note: A ContributionItem
cannot be shared between different
* ContributionManager
s.
*
*/
public abstract class ContributionManager implements IContributionManager {
// Internal debug flag.
// protected static final boolean DEBUG = false;
/**
* The list of contribution items.
*/
private List contributions = new ArrayList<>();
/**
* Indicates whether the widgets are in sync with the contributions.
*/
private boolean 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 ContributionManager() {
// Do nothing.
}
@Override
public void add(IAction action) {
Assert.isNotNull(action, "Action must not be null"); //$NON-NLS-1$
add(new ActionContributionItem(action));
}
@Override
public void add(IContributionItem item) {
Assert.isNotNull(item, "Item must not be null"); //$NON-NLS-1$
if (allowItem(item)) {
contributions.add(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
* true
to add to the end of the group, and
* false
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,
boolean append) {
int i;
Iterator items = contributions.iterator();
for (i = 0; items.hasNext(); i++) {
IContributionItem o = items.next();
if (o.isGroupMarker()) {
String id = o.getId();
if (id != null && id.equalsIgnoreCase(groupName)) {
i++;
if (append) {
for (; items.hasNext(); i++) {
IContributionItem ci = items
.next();
if (ci.isGroupMarker()) {
break;
}
}
}
if (allowItem(item)) {
contributions.add(i, item);
itemAdded(item);
}
return;
}
}
}
throw new IllegalArgumentException("Group not found: " + groupName);//$NON-NLS-1$
}
@Override
public void appendToGroup(String groupName, IAction action) {
addToGroup(groupName, new ActionContributionItem(action), true);
}
@Override
public void appendToGroup(String groupName, IContributionItem item) {
addToGroup(groupName, item, true);
}
/**
* This method allows subclasses of ContributionManager
to
* prevent certain items in the contributions list.
* ContributionManager
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 null
.
* @return true
if the addition should be allowed;
* false
otherwise. The default implementation allows
* all items.
* @since 3.0
*/
protected boolean allowItem(IContributionItem itemToAdd) {
return true;
}
/**
* Internal debug method for printing statistics about this manager to
* System.out
.
*/
protected void dumpStatistics() {
int size = 0;
if (contributions != null) {
size = contributions.size();
}
System.out.println(this.toString());
System.out.println(" Number of elements: " + size);//$NON-NLS-1$
int sum = 0;
for (int i = 0; i < size; i++) {
if (contributions.get(i).isVisible()) {
sum++;
}
}
System.out.println(" Number of visible elements: " + sum);//$NON-NLS-1$
System.out.println(" Is dirty: " + isDirty()); //$NON-NLS-1$
}
@Override
public IContributionItem find(String id) {
Iterator e = contributions.iterator();
while (e.hasNext()) {
IContributionItem item = e.next();
String itemId = item.getId();
if (itemId != null && itemId.equalsIgnoreCase(id)) {
return item;
}
}
return null;
}
@Override
public IContributionItem[] getItems() {
IContributionItem[] items = new IContributionItem[contributions.size()];
contributions.toArray(items);
return items;
}
/**
* 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 ContributionManager
implementation of this method
* declared on IContributionManager
returns the current
* overrides. If there is no overrides it lazily creates one which overrides
* no item state.
*
* @since 2.0
*/
@Override
public IContributionManagerOverrides getOverrides() {
if (overrides == null) {
overrides = new IContributionManagerOverrides() {
@Override
public Boolean getEnabled(IContributionItem item) {
return null;
}
@Override
public Integer getAccelerator(IContributionItem item) {
return null;
}
@Override
public String getAcceleratorText(IContributionItem item) {
return null;
}
@Override
public String getText(IContributionItem item) {
return null;
}
@Override
public Boolean getVisible(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 true
if this manager contains dynamic items, and
* false
otherwise
*/
protected boolean 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 int
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 = contributions.get(i);
String itemId = item.getId();
if (itemId != null && itemId.equalsIgnoreCase(id)) {
return i;
}
}
return -1;
}
/**
* Returns the index of the object in the internal structure. This is
* different from indexOf(String id)
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) {
return contributions.indexOf(item);
}
/**
* 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(
"inserting " + item.getId() + " at " + index); //$NON-NLS-1$ //$NON-NLS-2$
}
if (allowItem(item)) {
contributions.add(index, item);
itemAdded(item);
}
}
@Override
public void insertAfter(String ID, IAction action) {
insertAfter(ID, new ActionContributionItem(action));
}
@Override
public void insertAfter(String ID, IContributionItem item) {
IContributionItem ci = find(ID);
if (ci == null) {
throw new IllegalArgumentException("can't find ID" + ID);//$NON-NLS-1$
}
int ix = contributions.indexOf(ci);
if (ix >= 0) {
// System.out.println("insert after: " + ix);
if (allowItem(item)) {
contributions.add(ix + 1, item);
itemAdded(item);
}
}
}
@Override
public void insertBefore(String ID, IAction action) {
insertBefore(ID, new ActionContributionItem(action));
}
@Override
public void insertBefore(String ID, IContributionItem item) {
IContributionItem ci = find(ID);
if (ci == null) {
throw new IllegalArgumentException("can't find ID " + ID);//$NON-NLS-1$
}
int ix = contributions.indexOf(ci);
if (ix >= 0) {
// System.out.println("insert before: " + ix);
if (allowItem(item)) {
contributions.add(ix, item);
itemAdded(item);
}
}
}
@Override
public boolean isDirty() {
if (isDirty) {
return true;
}
if (hasDynamicItems()) {
for (IContributionItem item : contributions) {
if (item.isDirty()) {
return true;
}
}
}
return false;
}
@Override
public boolean isEmpty() {
return contributions.isEmpty();
}
/**
* 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--;
}
}
@Override
public void markDirty() {
setDirty(true);
}
@Override
public void prependToGroup(String groupName, IAction action) {
addToGroup(groupName, new ActionContributionItem(action), false);
}
@Override
public void prependToGroup(String groupName, IContributionItem item) {
addToGroup(groupName, item, false);
}
@Override
public IContributionItem remove(String ID) {
IContributionItem ci = find(ID);
if (ci == null) {
return null;
}
return remove(ci);
}
@Override
public IContributionItem remove(IContributionItem item) {
if (contributions.remove(item)) {
itemRemoved(item);
return item;
}
return null;
}
@Override
public void removeAll() {
IContributionItem[] items = getItems();
contributions.clear();
for (IContributionItem item : items) {
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 null
.
* @param replacementItem The contribution item to replace the old item; must
* not be null
. Use
* {@link org.eclipse.jface.action.ContributionManager#remove(java.lang.String)
* remove} if that is what you want to do.
* @return true
if the given identifier can be;
* @since 3.0
*/
public boolean replaceItem(final String identifier,
final IContributionItem replacementItem) {
if (identifier == null) {
return false;
}
final int index = indexOf(identifier);
if (index < 0) {
return false; // couldn't find the item.
}
// Remove the old item.
final IContributionItem oldItem = contributions
.get(index);
itemRemoved(oldItem);
// Add the new item.
contributions.set(index, replacementItem);
itemAdded(replacementItem); // throws NPE if (replacementItem == null)
// Go through and remove duplicates.
for (int i = contributions.size() - 1; i > index; i--) {
IContributionItem item = contributions.get(i);
if ((item != null) && (identifier.equals(item.getId()))) {
if (Policy.TRACE_TOOLBAR) {
System.out
.println("Removing duplicate on replace: " + identifier); //$NON-NLS-1$
}
contributions.remove(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
* true
if this manager is dirty, and
* false
if it is up-to-date
*/
protected void setDirty(boolean 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 (IContributionItem item : items) {
if (allowItem(item)) {
contributions.add(item);
}
}
}
}