blob: f77dad766ae417d63f7a0ddd2b1ff1396acbb420 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2010 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
*******************************************************************************/
package org.eclipse.ui.internal.menus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionDelta;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.AbstractGroupMarker;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.ContributionManager;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.ISourceProvider;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.activities.ActivityManagerEvent;
import org.eclipse.ui.activities.IActivityManagerListener;
import org.eclipse.ui.activities.IIdentifier;
import org.eclipse.ui.activities.IIdentifierListener;
import org.eclipse.ui.activities.IdentifierEvent;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.expressions.AlwaysEnabledExpression;
import org.eclipse.ui.internal.layout.LayoutUtil;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.services.IWorkbenchLocationService;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.menus.AbstractContributionFactory;
import org.eclipse.ui.menus.MenuUtil;
import org.eclipse.ui.services.IEvaluationReference;
import org.eclipse.ui.services.IEvaluationService;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.statushandlers.StatusManager;
/**
* <p>
* Provides services related to contributing menu elements to the workbench.
* </p>
* <p>
* This class is only intended for internal use within the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*/
public final class WorkbenchMenuService extends InternalMenuService {
private static final String INDEX_AFTER_ADDITIONS = "after=additions"; //$NON-NLS-1$
/**
* A combined property and activity listener that updates the visibility of
* contribution items in the new menu system.
*
* @since 3.3
*/
private final class ContributionItemUpdater implements
IPropertyChangeListener, IIdentifierListener {
private final IContributionItem item;
private IIdentifier identifier;
private boolean lastExpressionResult = true;
private ContributionItemUpdater(IContributionItem item,
IIdentifier identifier) {
this.item = item;
if (identifier != null) {
this.identifier = identifier;
this.identifier.addIdentifierListener(this);
updateVisibility(); // force initial visibility to fall in line
// with activity enablement
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty() == PROP_VISIBLE) {
if (event.getNewValue() != null) {
this.lastExpressionResult = ((Boolean) event.getNewValue())
.booleanValue();
} else {
this.lastExpressionResult = false;
}
updateVisibility();
}
}
private void updateVisibility() {
boolean visible = identifier != null ? (identifier.isEnabled() && lastExpressionResult)
: lastExpressionResult;
item.setVisible(visible);
IContributionManager parent = null;
if (item instanceof ContributionItem) {
parent = ((ContributionItem) item).getParent();
} else if (item instanceof MenuManager) {
parent = ((MenuManager) item).getParent();
}
if (parent != null) {
parent.markDirty();
managersAwaitingUpdates.add(parent);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.activities.IIdentifierListener#identifierChanged(org.eclipse.ui.activities.IdentifierEvent)
*/
public void identifierChanged(IdentifierEvent identifierEvent) {
updateVisibility();
}
/**
* Dispose of this updater
*/
public void dispose() {
if (identifier != null)
identifier.removeIdentifierListener(this);
}
}
private final class ManagerPopulationRecord {
public IServiceLocator serviceLocatorToUse;
public Set restriction;
public String uri;
public boolean recurse;
Map factoryToItems = new HashMap();
public ManagerPopulationRecord(IServiceLocator serviceLocatorToUse, Set restriction,
String uri, boolean recurse) {
this.serviceLocatorToUse = serviceLocatorToUse;
this.restriction = restriction;
this.uri = uri;
this.recurse = recurse;
}
public void addFactoryContribution(AbstractContributionFactory factory, ContributionRoot ciList) {
// Remove any existing cache info for this factory
removeFactoryContribution(factory);
// save the new info
factoryToItems.put(factory, ciList);
}
public void removeFactoryContribution(AbstractContributionFactory factory) {
ContributionRoot items =(ContributionRoot)factoryToItems.remove(factory);
if (items != null) {
WorkbenchMenuService.this.releaseContributions(items);
}
}
/**
* Delegates back to the workbench to remove -all- the contributions
* associated with this contribution manager
*/
public void releaseContributions() {
Collection cRoots = factoryToItems.values();
for (Iterator crItem = cRoots.iterator(); crItem.hasNext();) {
ContributionRoot items = (ContributionRoot) crItem.next();
WorkbenchMenuService.this.releaseContributions(items);
}
factoryToItems.clear();
}
}
/**
*
*/
private static final String PROP_VISIBLE = "visible"; //$NON-NLS-1$
/**
* The class providing persistence for this service.
*/
private final MenuPersistence menuPersistence;
/**
* The central authority for determining which menus are visible within this
* window.
*/
private IEvaluationService evaluationService;
private IPropertyChangeListener serviceListener;
/**
* The service locator into which this service will be inserted.
*/
private IServiceLocator serviceLocator;
private IActivityManagerListener activityManagerListener;
/**
* Constructs a new instance of <code>MenuService</code> using a menu
* manager.
*/
public WorkbenchMenuService(IServiceLocator serviceLocator) {
this.menuPersistence = new MenuPersistence(this);
this.serviceLocator = serviceLocator;
evaluationService = (IEvaluationService) serviceLocator
.getService(IEvaluationService.class);
evaluationService.addServiceListener(getServiceListener());
IWorkbenchLocationService wls = (IWorkbenchLocationService) serviceLocator
.getService(IWorkbenchLocationService.class);
wls.getWorkbench()
.getActivitySupport().getActivityManager()
.addActivityManagerListener(getActivityManagerListener());
final IExtensionRegistry registry = Platform.getExtensionRegistry();
registryChangeListener = new IRegistryChangeListener() {
public void registryChanged(final IRegistryChangeEvent event) {
final Display display = PlatformUI.getWorkbench().getDisplay();
if (display.isDisposed()) {
return;
}
display.syncExec(new Runnable() {
public void run() {
handleRegistryChanges(event);
}
});
}
};
registry.addRegistryChangeListener(registryChangeListener);
}
/**
* @return
*/
private IActivityManagerListener getActivityManagerListener() {
if (activityManagerListener == null) {
activityManagerListener = new IActivityManagerListener() {
public void activityManagerChanged(
ActivityManagerEvent activityManagerEvent) {
if (activityManagerEvent.haveEnabledActivityIdsChanged()) {
updateManagers(); // called after all identifiers have
// been update - now update the
// managers
}
}
};
}
return activityManagerListener;
}
/**
* @return
*/
private IPropertyChangeListener getServiceListener() {
if (serviceListener == null) {
serviceListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(
IEvaluationService.PROP_NOTIFYING)) {
if (!((Boolean) event.getNewValue()).booleanValue()) {
// if it's false, the evaluation service has
// finished
// with its latest round of updates
updateManagers();
}
}
}
};
}
return serviceListener;
}
public void updateManagers() {
Object[] managers = managersAwaitingUpdates.toArray();
managersAwaitingUpdates.clear();
for (int i = 0; i < managers.length; i++) {
IContributionManager mgr = (IContributionManager) managers[i];
mgr.update(true);
if (mgr instanceof ToolBarManager) {
if (!updateCoolBar((ToolBarManager) mgr)) {
updateTrim((ToolBarManager) mgr);
}
} else if (mgr instanceof MenuManager) {
IContributionManager parent = ((MenuManager) mgr).getParent();
if (parent != null) {
parent.update(true);
}
}
}
}
private void updateTrim(ToolBarManager mgr) {
Control control = mgr.getControl();
if (control == null || control.isDisposed()) {
return;
}
LayoutUtil.resize(control);
}
private boolean updateCoolBar(ToolBarManager mgr) {
IWorkbenchWindow[] windows = PlatformUI.getWorkbench()
.getWorkbenchWindows();
for (int i = 0; i < windows.length; i++) {
}
return false;
}
public final void addSourceProvider(final ISourceProvider provider) {
// no-op
}
public final void dispose() {
menuPersistence.dispose();
if (registryChangeListener != null) {
final IExtensionRegistry registry = Platform.getExtensionRegistry();
registry.removeRegistryChangeListener(registryChangeListener);
registryChangeListener = null;
}
Iterator i = evaluationsByItem.values().iterator();
while (i.hasNext()) {
IEvaluationReference ref = (IEvaluationReference) i.next();
evaluationService.removeEvaluationListener(ref);
}
evaluationsByItem.clear();
managersAwaitingUpdates.clear();
if (serviceListener != null) {
evaluationService.removeServiceListener(serviceListener);
serviceListener = null;
}
if (activityManagerListener != null) {
IWorkbenchLocationService wls = (IWorkbenchLocationService) serviceLocator
.getService(IWorkbenchLocationService.class);
IWorkbench workbench = wls.getWorkbench();
if (workbench != null) {
workbench.getActivitySupport().getActivityManager()
.removeActivityManagerListener(activityManagerListener);
}
}
}
public final void readRegistry() {
menuPersistence.read();
}
public final void removeSourceProvider(final ISourceProvider provider) {
// no-op
}
//
// 3.3 common menu service information
//
private Map uriToFactories = new HashMap();
private Map evaluationsByItem = new HashMap();
private Map activityListenersByItem = new HashMap();
private Set managersAwaitingUpdates = new HashSet();
private HashMap populatedManagers = new HashMap();
private IRegistryChangeListener registryChangeListener;
/**
* Construct an 'id' string from the given URI. The resulting 'id' is the
* part of the URI not containing the query:
* <p>
* i.e. [menu | popup | toolbar]:id
* </p>
*
* @param uri
* The URI to construct the id from
* @return The id
*/
private String getIdFromURI(MenuLocationURI uri) {
return uri.getScheme() + ":" + uri.getPath(); //$NON-NLS-1$;
}
public List getAdditionsForURI(MenuLocationURI uri) {
if (uri == null)
return null;
List caches = (List) uriToFactories.get(getIdFromURI(uri));
// we always return a list
if (caches == null) {
caches = new ArrayList();
uriToFactories.put(getIdFromURI(uri), caches);
}
return caches;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#addCacheForURI(org.eclipse.ui.internal.menus.MenuCacheEntry)
*/
public void addContributionFactory(AbstractContributionFactory factory) {
if (factory == null || factory.getLocation() == null)
return;
MenuLocationURI uri = new MenuLocationURI(factory.getLocation());
String factoryId = getIdFromURI(uri);
List factories = (List) uriToFactories.get(factoryId);
// we always return a list
if (factories == null) {
factories = new ArrayList();
uriToFactories.put(factoryId, factories);
}
if (factory instanceof MenuAdditionCacheEntry && ((MenuAdditionCacheEntry)factory).hasAdditions()) {
factories.add(0, factory);
} else {
factories.add(factory);
}
// OK, now update any managers that use this uri
List factoryList = new ArrayList();
factoryList.add(factory);
List affectedManagers = getManagersFor(factoryId);
for (Iterator mgrIter = affectedManagers.iterator(); mgrIter.hasNext();) {
ContributionManager mgr = (ContributionManager) mgrIter.next();
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.get(mgr);
addContributionsToManager(mpr.serviceLocatorToUse,
mpr.restriction, mgr, mpr.uri, mpr.recurse, factoryList);
mgr.update(true);
}
}
/**
* Return a list of managers that have already been populated and
* whose URI matches the given one
* @param factoryId The factoryId to check for
* @return The list of interested managers
*/
private List getManagersFor(String factoryId) {
List mgrs = new ArrayList();
for (Iterator mgrIter = populatedManagers.keySet().iterator(); mgrIter.hasNext();) {
ContributionManager mgr = (ContributionManager) mgrIter.next();
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.get(mgr);
if (factoryId.equals(mpr.uri))
mgrs.add(mgr);
}
return mgrs;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.menus.IMenuService#removeContributionFactory(org.eclipse.ui.menus.AbstractContributionFactory)
*/
public void removeContributionFactory(AbstractContributionFactory factory) {
if (factory == null || factory.getLocation() == null)
return;
MenuLocationURI uri = new MenuLocationURI(factory.getLocation());
String factoryId = getIdFromURI(uri);
List factories = (List) uriToFactories.get(factoryId);
if (factories != null) {
// Before we remove the top-level cache we recursively
// remove any sub-caches creates by this one
if (factory instanceof MenuAdditionCacheEntry) {
List subCaches = ((MenuAdditionCacheEntry)factory).getSubCaches();
if (subCaches != null) {
for (Iterator subCacheIter = subCaches.iterator(); subCacheIter
.hasNext();) {
AbstractMenuAdditionCacheEntry mace = (AbstractMenuAdditionCacheEntry) subCacheIter.next();
removeContributionFactory(mace);
}
}
}
factories.remove(factory);
}
// OK, now update any managers that use this uri
List factoryList = new ArrayList();
factoryList.add(factory);
List affectedManagers = getManagersFor(factoryId);
for (Iterator mgrIter = affectedManagers.iterator(); mgrIter.hasNext();) {
ContributionManager mgr = (ContributionManager) mgrIter.next();
removeContributionsForFactory(mgr, factory);
mgr.update(true);
}
}
private boolean processAdditions(final IServiceLocator serviceLocatorToUse,
Set restriction, final ContributionManager mgr,
final AbstractContributionFactory cache, final Set itemsAdded) {
if (!processFactory(mgr, cache))
return true;
final int idx = getInsertionIndex(mgr, cache.getLocation());
if (idx == -1)
return false; // can't process (yet)
// Get the additions
final ContributionRoot ciList = new ContributionRoot(this, restriction,
mgr, cache);
ISafeRunnable run = new ISafeRunnable() {
public void handleException(Throwable exception) {
// TODO Auto-generated method stub
}
public void run() throws Exception {
int insertionIndex = idx;
cache.createContributionItems(serviceLocatorToUse, ciList);
// If we have any then add them at the correct location
if (ciList.getItems().size() > 0) {
// Cache the items for future cleanup
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.get(mgr);
mpr.addFactoryContribution(cache, ciList);
for (Iterator ciIter = ciList.getItems().iterator(); ciIter
.hasNext();) {
IContributionItem ici = (IContributionItem) ciIter
.next();
if ((ici instanceof ContributionManager || ici instanceof IToolBarContributionItem
|| ici instanceof AbstractGroupMarker)
&& ici.getId() != null
&& !"".equals(ici.getId())) { //$NON-NLS-1$
IContributionItem foundIci = mgr.find(ici.getId());
// really, this is a very specific scenario that
// allows merging
// but, if it is a contribution manager that also
// contains
// items, then we would be throwing stuff away.
if (foundIci instanceof ContributionManager) {
if (((ContributionManager) ici).getSize() > 0) {
IStatus status = new Status(
IStatus.WARNING,
WorkbenchPlugin.PI_WORKBENCH,
"Menu contribution id collision: " //$NON-NLS-1$
+ ici.getId());
StatusManager.getManager().handle(status);
}
continue;
} else if (foundIci instanceof IToolBarContributionItem) {
IToolBarManager toolBarManager = ((IToolBarContributionItem) ici)
.getToolBarManager();
if (toolBarManager instanceof ContributionManager
&& ((ContributionManager) toolBarManager)
.getSize() > 0) {
IStatus status = new Status(
IStatus.WARNING,
WorkbenchPlugin.PI_WORKBENCH,
"Toolbar contribution id collision: " //$NON-NLS-1$
+ ici.getId());
StatusManager.getManager().handle(status);
}
continue;
} else if (foundIci instanceof AbstractGroupMarker) {
continue;
}
}
final int oldSize = mgr.getSize();
mgr.insert(insertionIndex, ici);
if (ici.getId() != null) {
itemsAdded.add(ici.getId());
}
if (mgr.getSize() > oldSize)
insertionIndex++;
}
}
}
};
SafeRunner.run(run);
return true;
}
/**
* Determines whether the factory should be processed for this manager.
*
* @param factory
* The factory to be added
* @param mgr
* The contribution manager
* @return <code>true</code> if the factory to be processed,
* <code>false</code> otherwise
*/
private boolean processFactory(ContributionManager mgr, AbstractContributionFactory factory) {
MenuLocationURI uri = new MenuLocationURI(factory.getLocation());
if (MenuUtil.ANY_POPUP.equals(uri.getScheme() + ':' + uri.getPath())) {
// its any popup. check whether manager has additions
if (mgr.indexOf(IWorkbenchActionConstants.MB_ADDITIONS) == -1) {
// menu has no additions. Add only if allPopups = true
if (factory instanceof MenuAdditionCacheEntry) {
MenuAdditionCacheEntry menuEntry = (MenuAdditionCacheEntry) factory;
return menuEntry.contributeToAllPopups();
}
}
}
return true;
}
/**
* Removes all cached info for the given manager/factory tuple. This
* includes unregistering expressions...
*
* @param manager The contribution manager owning the contributions
* @param factory The factory responsible for the contributions
*/
protected void removeContributionsForFactory(IContributionManager manager, AbstractContributionFactory factory) {
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.get(manager);
mpr.removeFactoryContribution(factory); // automatically cleans its caches
}
/**
* @param items
*/
private void releaseCache(final ContributionRoot items) {
items.release();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#populateMenu(org.eclipse.jface.action.ContributionManager,
* org.eclipse.ui.internal.menus.MenuLocationURI)
*/
public void populateContributionManager(ContributionManager mgr, String uri) {
populateContributionManager(serviceLocator, null, mgr, uri, true);
}
public void populateContributionManager(
IServiceLocator serviceLocatorToUse, Set restriction,
ContributionManager mgr, String uri, boolean recurse) {
// Track this attempt to populate the menu, remembering all the parameters
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.get(mgr);
if (mpr == null) {
mpr = new ManagerPopulationRecord(serviceLocatorToUse,
restriction, uri, recurse);
populatedManagers.put(mgr, mpr);
}
MenuLocationURI contributionLocation = new MenuLocationURI(uri);
List factories = getAdditionsForURI(contributionLocation);
addContributionsToManager(serviceLocatorToUse, restriction, mgr, uri, recurse, factories);
}
public void addContributionsToManager(
IServiceLocator serviceLocatorToUse, Set restriction,
ContributionManager mgr, String uri, boolean recurse,
List factories) {
MenuLocationURI contributionLocation = new MenuLocationURI(uri);
List retryList = new ArrayList();
Set itemsAdded = new HashSet();
for (Iterator iterator = factories.iterator(); iterator.hasNext();) {
AbstractContributionFactory cache = (AbstractContributionFactory) iterator
.next();
if (!processAdditions(serviceLocatorToUse, restriction, mgr, cache,
itemsAdded)) {
retryList.add(cache);
}
}
// OK, iteratively loop through entries whose URI's could not
// be resolved until we either run out of entries or the list
// doesn't change size (indicating that the remaining entries
// can never be resolved).
boolean done = retryList.size() == 0;
while (!done) {
// Clone the retry list and clear it
List curRetry = new ArrayList(retryList);
int retryCount = retryList.size();
retryList.clear();
// Walk the current list seeing if any entries can now be resolved
for (Iterator iterator = curRetry.iterator(); iterator.hasNext();) {
AbstractContributionFactory cache = (AbstractContributionFactory) iterator
.next();
if (!processAdditions(serviceLocatorToUse, restriction, mgr,
cache, itemsAdded))
retryList.add(cache);
}
// We're done if the retryList is now empty (everything done) or
// if the list hasn't changed at all (no hope)
done = (retryList.size() == 0) || (retryList.size() == retryCount);
}
// Now, recurse through any sub-menus
IContributionItem[] curItems = mgr.getItems();
for (int i = 0; i < curItems.length; i++) {
if (curItems[i] instanceof ContributionManager) {
String id = curItems[i].getId();
if (id != null && id.length() > 0
&& (recurse || itemsAdded.contains(id))) {
populateContributionManager(serviceLocatorToUse,
restriction, (ContributionManager) curItems[i],
contributionLocation.getScheme() + ":" + id, true); //$NON-NLS-1$
}
} else if (curItems[i] instanceof IToolBarContributionItem) {
IToolBarContributionItem tbci = (IToolBarContributionItem) curItems[i];
if (tbci.getId() != null && tbci.getId().length() > 0
&& (recurse || itemsAdded.contains(tbci.getId()))) {
populateContributionManager(serviceLocatorToUse,
restriction, (ContributionManager) tbci
.getToolBarManager(), contributionLocation
.getScheme()
+ ":" + tbci.getId(), true); //$NON-NLS-1$
}
}
}
}
private int getInsertionIndex(ContributionManager mgr, String location) {
MenuLocationURI uri = new MenuLocationURI(location);
String query = uri.getQuery();
int additionsIndex = -1;
// No Query means 'after=additions' (if ther) or
// the end of the menu
if (query.length() == 0 || query.equals(INDEX_AFTER_ADDITIONS)) {
additionsIndex = mgr
.indexOf(IWorkbenchActionConstants.MB_ADDITIONS);
if (additionsIndex == -1)
additionsIndex = mgr.getItems().length;
else
++additionsIndex;
} else {
// Should be in the form "[before|after|endof]=id"
String[] queryParts = Util.split(query, '=');
if (queryParts.length>1 && queryParts[1].length() > 0) {
String modifier = queryParts[0];
String id = queryParts[1];
additionsIndex = mgr.indexOf(id);
if (additionsIndex != -1) {
if (MenuUtil.QUERY_BEFORE.equals(modifier)) {
// this is OK, the additionsIndex will either be correct
// or -1 (which is a no-op)
} else if (MenuUtil.QUERY_AFTER.equals(modifier)) {
additionsIndex++;
} else if (MenuUtil.QUERY_ENDOF.equals(modifier)) {
// OK, this one is exciting
IContributionItem[] items = mgr.getItems();
for (additionsIndex++; additionsIndex < items.length; additionsIndex++) {
if (items[additionsIndex].isGroupMarker()) {
break;
}
}
}
}
}
}
return additionsIndex;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#getCurrentState()
*/
public IEvaluationContext getCurrentState() {
return evaluationService.getCurrentState();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#registerVisibleWhen(org.eclipse.jface.action.IContributionItem,
* org.eclipse.core.expressions.Expression)
*/
public void registerVisibleWhen(final IContributionItem item,
final Expression visibleWhen, final Set restriction,
String identifierID) {
if (item == null) {
throw new IllegalArgumentException("item cannot be null"); //$NON-NLS-1$
}
if (visibleWhen == null) {
throw new IllegalArgumentException(
"visibleWhen expression cannot be null"); //$NON-NLS-1$
}
if (evaluationsByItem.get(item) != null) {
final String id = item.getId();
WorkbenchPlugin.log("item is already registered: " //$NON-NLS-1$
+ (id == null ? "no id" : id)); //$NON-NLS-1$
return;
}
IIdentifier identifier = null;
if (identifierID != null) {
identifier = PlatformUI.getWorkbench().getActivitySupport()
.getActivityManager().getIdentifier(identifierID);
}
ContributionItemUpdater listener = new ContributionItemUpdater(item,
identifier);
if (visibleWhen != AlwaysEnabledExpression.INSTANCE) {
IEvaluationReference ref = evaluationService.addEvaluationListener(
visibleWhen, listener, PROP_VISIBLE);
if (restriction != null) {
restriction.add(ref);
}
evaluationsByItem.put(item, ref);
}
activityListenersByItem.put(item, listener);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#unregisterVisibleWhen(org.eclipse.jface.action.IContributionItem)
*/
public void unregisterVisibleWhen(IContributionItem item, final Set restriction) {
ContributionItemUpdater identifierListener = (ContributionItemUpdater) activityListenersByItem
.remove(item);
if (identifierListener != null) {
identifierListener.dispose();
}
IEvaluationReference ref = (IEvaluationReference) evaluationsByItem
.remove(item);
if (ref == null) {
return;
}
evaluationService.removeEvaluationListener(ref);
if (restriction !=null) {
restriction.remove(ref);
}
}
/**
* @param manager
*/
protected void releaseContributions(ContributionRoot items) {
ContributionManager mgr = items.getManager();
Iterator j = items.getItems().iterator();
while (j.hasNext()) {
IContributionItem item = (IContributionItem) j.next();
releaseItem(item, items.restriction);
mgr.remove(item);
}
releaseCache(items);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.menus.IMenuService#releaseMenu(org.eclipse.jface.action.ContributionManager)
*/
public void releaseContributions(ContributionManager mgr) {
if (mgr == null)
return;
// Recursive remove any contributions from sub-menus
IContributionItem[] items = mgr.getItems();
for (int i = 0; i < items.length; i++) {
if (items[i] instanceof ContributionManager) {
releaseContributions((ContributionManager) items[i]);
} else if (items[i] instanceof IToolBarContributionItem) {
IToolBarContributionItem tbci = (IToolBarContributionItem) items[i];
releaseContributions((ContributionManager) tbci
.getToolBarManager());
}
}
// Now remove any cached information
ManagerPopulationRecord mpr = (ManagerPopulationRecord) populatedManagers.remove(mgr);
if (mpr != null)
mpr.releaseContributions();
managersAwaitingUpdates.remove(mgr);
}
/**
* @param item
*/
private void releaseItem(IContributionItem item, final Set restriction) {
unregisterVisibleWhen(item, restriction);
if (item instanceof ContributionManager) {
releaseContributions((ContributionManager) item);
} else if (item instanceof IToolBarContributionItem) {
IToolBarContributionItem tbci = (IToolBarContributionItem) item;
releaseContributions((ContributionManager) tbci.getToolBarManager());
}
}
/**
* Process additions to the menus that occur through ExtensionRegistry changes
* @param menuAdditions The list of new menu addition extensions to process
*/
public void handleDynamicAdditions(List menuAdditions) {
for (Iterator additionsIter = menuAdditions.iterator(); additionsIter.hasNext();) {
AbstractContributionFactory newFactory = null;
final IConfigurationElement menuAddition = (IConfigurationElement) additionsIter.next();
if (isProgramaticContribution(menuAddition))
newFactory = new ProxyMenuAdditionCacheEntry(
menuAddition
.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI),
menuAddition.getNamespaceIdentifier(), menuAddition);
else
newFactory = new MenuAdditionCacheEntry(
this,
menuAddition,
menuAddition
.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI),
menuAddition.getNamespaceIdentifier());
if (newFactory != null)
addContributionFactory(newFactory);
}
}
/**
* Return whether or not this contribution is programmatic (ie: has a class attribute).
*
* @param menuAddition
* @return whether or not this contribution is programamtic
* @since 3.5
*/
private boolean isProgramaticContribution(IConfigurationElement menuAddition) {
return menuAddition.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS) != null;
}
/**
* Process additions to the menus that occur through ExtensionRegistry changes
* @param menuRemovals The list of menu addition extensions to remove
*/
public void handleDynamicRemovals(List menuRemovals) {
for (Iterator additionsIter = menuRemovals.iterator(); additionsIter.hasNext();) {
IConfigurationElement ceToRemove = (IConfigurationElement) additionsIter.next();
AbstractMenuAdditionCacheEntry factoryToRemove = findFactory(ceToRemove);
removeContributionFactory(factoryToRemove);
}
}
/**
* @param ceToRemove
* @return
*/
private AbstractMenuAdditionCacheEntry findFactory(IConfigurationElement ceToRemove) {
String uriStr = ceToRemove.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI);
MenuLocationURI uri = new MenuLocationURI(uriStr);
List factories = getAdditionsForURI(uri);
for (Iterator iterator = factories.iterator(); iterator.hasNext();) {
AbstractContributionFactory factory = (AbstractContributionFactory) iterator.next();
if (factory instanceof AbstractMenuAdditionCacheEntry) {
AbstractMenuAdditionCacheEntry mace = (AbstractMenuAdditionCacheEntry) factory;
if (mace.getConfigElement().equals(ceToRemove))
return mace;
}
}
return null;
}
/**
* @param event
*/
public void handleRegistryChanges(final IRegistryChangeEvent event) {
// HACK!! determine if this is an addition or deletion from the first delta
IExtensionDelta[] deltas = event.getExtensionDeltas();
if (deltas.length == 0)
return;
}
/**
* @return Returns the menuPersistence.
*/
public MenuPersistence getMenuPersistence() {
return menuPersistence;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.menus.InternalMenuService#populateContributionManager(org.eclipse.jface.action.ContributionManager, java.lang.String, boolean)
*/
public void populateContributionManager(ContributionManager mgr,
String uri, boolean recurse) {
populateContributionManager(serviceLocator, null, mgr, uri, recurse);
}
}