blob: 07be5a000b9fb324ef0b7e38edd70718cfc41fa7 [file] [log] [blame]
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.ui.internal.activities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.WeakHashMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.activities.ActivityEvent;
import org.eclipse.ui.activities.ActivityManagerEvent;
import org.eclipse.ui.activities.CategoryEvent;
import org.eclipse.ui.activities.IActivity;
import org.eclipse.ui.activities.IActivityPatternBinding;
import org.eclipse.ui.activities.IActivityRequirementBinding;
import org.eclipse.ui.activities.ICategory;
import org.eclipse.ui.activities.ICategoryActivityBinding;
import org.eclipse.ui.activities.IIdentifier;
import org.eclipse.ui.activities.IMutableActivityManager;
import org.eclipse.ui.activities.IdentifierEvent;
import org.eclipse.ui.internal.util.Util;
/**
* An activity registry that may be altered.
*
* @since 3.0
*/
public final class MutableActivityManager extends AbstractActivityManager
implements IMutableActivityManager, Cloneable {
private Map activitiesById = new WeakHashMap();
private Map activityRequirementBindingsByActivityId = new HashMap();
private Map activityDefinitionsById = new HashMap();
private Map activityPatternBindingsByActivityId = new HashMap();
private IActivityRegistry activityRegistry;
private Map categoriesById = new WeakHashMap();
private Map categoryActivityBindingsByCategoryId = new HashMap();
private Map categoryDefinitionsById = new HashMap();
private Set definedActivityIds = new HashSet();
private Set definedCategoryIds = new HashSet();
private Set enabledActivityIds = new HashSet();
private Map identifiersById = new WeakHashMap();
/**
* A list of identifiers that need to have their activity sets reconciled in the background job.
*/
private List deferredIdentifiers = Collections.synchronizedList(new LinkedList());
/**
* The identifier update job. Lazily initialized.
*/
private Job deferredIdentifierJob = null;
private final IActivityRegistryListener activityRegistryListener = new IActivityRegistryListener() {
public void activityRegistryChanged(
ActivityRegistryEvent activityRegistryEvent) {
readRegistry(false);
}
};
/**
* Create a new instance of this class using the platform extension registry.
*/
public MutableActivityManager() {
this(new ExtensionActivityRegistry(Platform.getExtensionRegistry()));
}
/**
* Create a new instance of this class using the provided registry.
*
* @param activityRegistry the activity registry
*/
public MutableActivityManager(IActivityRegistry activityRegistry) {
if (activityRegistry == null) {
throw new NullPointerException();
}
this.activityRegistry = activityRegistry;
this.activityRegistry
.addActivityRegistryListener(activityRegistryListener);
readRegistry(true);
}
public IActivity getActivity(String activityId) {
if (activityId == null) {
throw new NullPointerException();
}
Activity activity = (Activity) activitiesById.get(activityId);
if (activity == null) {
activity = new Activity(activityId);
updateActivity(activity);
activitiesById.put(activityId, activity);
}
return activity;
}
public ICategory getCategory(String categoryId) {
if (categoryId == null) {
throw new NullPointerException();
}
Category category = (Category) categoriesById.get(categoryId);
if (category == null) {
category = new Category(categoryId);
updateCategory(category);
categoriesById.put(categoryId, category);
}
return category;
}
public Set getDefinedActivityIds() {
return Collections.unmodifiableSet(definedActivityIds);
}
public Set getDefinedCategoryIds() {
return Collections.unmodifiableSet(definedCategoryIds);
}
public Set getEnabledActivityIds() {
return Collections.unmodifiableSet(enabledActivityIds);
}
public IIdentifier getIdentifier(String identifierId) {
if (identifierId == null) {
throw new NullPointerException();
}
Identifier identifier = (Identifier) identifiersById.get(identifierId);
if (identifier == null) {
identifier = new Identifier(identifierId);
updateIdentifier(identifier);
identifiersById.put(identifierId, identifier);
}
return identifier;
}
private void getRequiredActivityIds(Set activityIds, Set requiredActivityIds) {
for (Iterator iterator = activityIds.iterator(); iterator.hasNext();) {
String activityId = (String) iterator.next();
IActivity activity = getActivity(activityId);
Set childActivityIds = new HashSet();
Set activityRequirementBindings = activity
.getActivityRequirementBindings();
for (Iterator iterator2 = activityRequirementBindings.iterator(); iterator2
.hasNext();) {
IActivityRequirementBinding activityRequirementBinding = (IActivityRequirementBinding) iterator2
.next();
childActivityIds.add(activityRequirementBinding
.getRequiredActivityId());
}
childActivityIds.removeAll(requiredActivityIds);
requiredActivityIds.addAll(childActivityIds);
getRequiredActivityIds(childActivityIds, requiredActivityIds);
}
}
private void notifyActivities(Map activityEventsByActivityId) {
for (Iterator iterator = activityEventsByActivityId.entrySet()
.iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String activityId = (String) entry.getKey();
ActivityEvent activityEvent = (ActivityEvent) entry.getValue();
Activity activity = (Activity) activitiesById.get(activityId);
if (activity != null) {
activity.fireActivityChanged(activityEvent);
}
}
}
private void notifyCategories(Map categoryEventsByCategoryId) {
for (Iterator iterator = categoryEventsByCategoryId.entrySet()
.iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String categoryId = (String) entry.getKey();
CategoryEvent categoryEvent = (CategoryEvent) entry.getValue();
Category category = (Category) categoriesById.get(categoryId);
if (category != null) {
category.fireCategoryChanged(categoryEvent);
}
}
}
private void notifyIdentifiers(Map identifierEventsByIdentifierId) {
for (Iterator iterator = identifierEventsByIdentifierId.entrySet()
.iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String identifierId = (String) entry.getKey();
IdentifierEvent identifierEvent = (IdentifierEvent) entry
.getValue();
Identifier identifier = (Identifier) identifiersById
.get(identifierId);
if (identifier != null) {
identifier.fireIdentifierChanged(identifierEvent);
}
}
}
private void readRegistry(boolean setDefaults) {
if (!isRegexpSupported()) {
return;
}
Collection activityDefinitions = new ArrayList();
activityDefinitions.addAll(activityRegistry.getActivityDefinitions());
Map activityDefinitionsById = new HashMap(ActivityDefinition
.activityDefinitionsById(activityDefinitions, false));
for (Iterator iterator = activityDefinitionsById.values().iterator(); iterator
.hasNext();) {
ActivityDefinition activityDefinition = (ActivityDefinition) iterator
.next();
String name = activityDefinition.getName();
if (name == null || name.length() == 0) {
iterator.remove();
}
}
Collection categoryDefinitions = new ArrayList();
categoryDefinitions.addAll(activityRegistry.getCategoryDefinitions());
Map categoryDefinitionsById = new HashMap(CategoryDefinition
.categoryDefinitionsById(categoryDefinitions, false));
for (Iterator iterator = categoryDefinitionsById.values().iterator(); iterator
.hasNext();) {
CategoryDefinition categoryDefinition = (CategoryDefinition) iterator
.next();
String name = categoryDefinition.getName();
if (name == null || name.length() == 0) {
iterator.remove();
}
}
Map activityRequirementBindingDefinitionsByActivityId = ActivityRequirementBindingDefinition
.activityRequirementBindingDefinitionsByActivityId(activityRegistry
.getActivityRequirementBindingDefinitions());
Map activityRequirementBindingsByActivityId = new HashMap();
for (Iterator iterator = activityRequirementBindingDefinitionsByActivityId
.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String parentActivityId = (String) entry.getKey();
if (activityDefinitionsById.containsKey(parentActivityId)) {
Collection activityRequirementBindingDefinitions = (Collection) entry
.getValue();
if (activityRequirementBindingDefinitions != null) {
for (Iterator iterator2 = activityRequirementBindingDefinitions
.iterator(); iterator2.hasNext();) {
ActivityRequirementBindingDefinition activityRequirementBindingDefinition = (ActivityRequirementBindingDefinition) iterator2
.next();
String childActivityId = activityRequirementBindingDefinition
.getRequiredActivityId();
if (activityDefinitionsById
.containsKey(childActivityId)) {
IActivityRequirementBinding activityRequirementBinding = new ActivityRequirementBinding(
childActivityId, parentActivityId);
Set activityRequirementBindings = (Set) activityRequirementBindingsByActivityId
.get(parentActivityId);
if (activityRequirementBindings == null) {
activityRequirementBindings = new HashSet();
activityRequirementBindingsByActivityId.put(
parentActivityId,
activityRequirementBindings);
}
activityRequirementBindings
.add(activityRequirementBinding);
}
}
}
}
}
Map activityPatternBindingDefinitionsByActivityId = ActivityPatternBindingDefinition
.activityPatternBindingDefinitionsByActivityId(activityRegistry
.getActivityPatternBindingDefinitions());
Map activityPatternBindingsByActivityId = new HashMap();
for (Iterator iterator = activityPatternBindingDefinitionsByActivityId
.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String activityId = (String) entry.getKey();
if (activityDefinitionsById.containsKey(activityId)) {
Collection activityPatternBindingDefinitions = (Collection) entry
.getValue();
if (activityPatternBindingDefinitions != null) {
for (Iterator iterator2 = activityPatternBindingDefinitions
.iterator(); iterator2.hasNext();) {
ActivityPatternBindingDefinition activityPatternBindingDefinition = (ActivityPatternBindingDefinition) iterator2
.next();
String pattern = activityPatternBindingDefinition
.getPattern();
if (pattern != null && pattern.length() != 0) {
IActivityPatternBinding activityPatternBinding = new ActivityPatternBinding(
activityId, pattern);
Set activityPatternBindings = (Set) activityPatternBindingsByActivityId
.get(activityId);
if (activityPatternBindings == null) {
activityPatternBindings = new HashSet();
activityPatternBindingsByActivityId.put(
activityId, activityPatternBindings);
}
activityPatternBindings.add(activityPatternBinding);
}
}
}
}
}
Map categoryActivityBindingDefinitionsByCategoryId = CategoryActivityBindingDefinition
.categoryActivityBindingDefinitionsByCategoryId(activityRegistry
.getCategoryActivityBindingDefinitions());
Map categoryActivityBindingsByCategoryId = new HashMap();
for (Iterator iterator = categoryActivityBindingDefinitionsByCategoryId
.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
String categoryId = (String) entry.getKey();
if (categoryDefinitionsById.containsKey(categoryId)) {
Collection categoryActivityBindingDefinitions = (Collection) entry
.getValue();
if (categoryActivityBindingDefinitions != null) {
for (Iterator iterator2 = categoryActivityBindingDefinitions
.iterator(); iterator2.hasNext();) {
CategoryActivityBindingDefinition categoryActivityBindingDefinition = (CategoryActivityBindingDefinition) iterator2
.next();
String activityId = categoryActivityBindingDefinition
.getActivityId();
if (activityDefinitionsById.containsKey(activityId)) {
ICategoryActivityBinding categoryActivityBinding = new CategoryActivityBinding(
activityId, categoryId);
Set categoryActivityBindings = (Set) categoryActivityBindingsByCategoryId
.get(categoryId);
if (categoryActivityBindings == null) {
categoryActivityBindings = new HashSet();
categoryActivityBindingsByCategoryId.put(
categoryId, categoryActivityBindings);
}
categoryActivityBindings
.add(categoryActivityBinding);
}
}
}
}
}
this.activityRequirementBindingsByActivityId = activityRequirementBindingsByActivityId;
this.activityDefinitionsById = activityDefinitionsById;
this.activityPatternBindingsByActivityId = activityPatternBindingsByActivityId;
this.categoryActivityBindingsByCategoryId = categoryActivityBindingsByCategoryId;
this.categoryDefinitionsById = categoryDefinitionsById;
boolean definedActivityIdsChanged = false;
Set definedActivityIds = new HashSet(activityDefinitionsById.keySet());
Set previouslyDefinedActivityIds = null;
if (!definedActivityIds.equals(this.definedActivityIds)) {
previouslyDefinedActivityIds = this.definedActivityIds;
this.definedActivityIds = definedActivityIds;
definedActivityIdsChanged = true;
}
boolean definedCategoryIdsChanged = false;
Set definedCategoryIds = new HashSet(categoryDefinitionsById.keySet());
Set previouslyDefinedCategoryIds = null;
if (!definedCategoryIds.equals(this.definedCategoryIds)) {
previouslyDefinedCategoryIds = this.definedCategoryIds;
this.definedCategoryIds = definedCategoryIds;
definedCategoryIdsChanged = true;
}
Set enabledActivityIds = new HashSet(this.enabledActivityIds);
getRequiredActivityIds(this.enabledActivityIds, enabledActivityIds);
boolean enabledActivityIdsChanged = false;
Set previouslyEnabledActivityIds = null;
if (!this.enabledActivityIds.equals(enabledActivityIds)) {
previouslyEnabledActivityIds = this.enabledActivityIds;
this.enabledActivityIds = enabledActivityIds;
enabledActivityIdsChanged = true;
}
Map activityEventsByActivityId = updateActivities(activitiesById
.keySet());
Map categoryEventsByCategoryId = updateCategories(categoriesById
.keySet());
Map identifierEventsByIdentifierId = updateIdentifiers(identifiersById
.keySet());
if (definedActivityIdsChanged || definedCategoryIdsChanged
|| enabledActivityIdsChanged) {
fireActivityManagerChanged(new ActivityManagerEvent(this,
definedActivityIdsChanged, definedCategoryIdsChanged,
enabledActivityIdsChanged, previouslyDefinedActivityIds,
previouslyDefinedCategoryIds, previouslyEnabledActivityIds));
}
if (activityEventsByActivityId != null) {
notifyActivities(activityEventsByActivityId);
}
if (categoryEventsByCategoryId != null) {
notifyCategories(categoryEventsByCategoryId);
}
if (identifierEventsByIdentifierId != null) {
notifyIdentifiers(identifierEventsByIdentifierId);
}
if (setDefaults) {
setEnabledActivityIds(new HashSet(activityRegistry
.getDefaultEnabledActivities()));
}
}
/**
* Returns whether the Java 1.4 regular expression support is available.
* Regexp support will not be available when running against JCL Foundation (see bug 80053).
*
* @return <code>true</code> if regexps are supported, <code>false</code> otherwise.
*
* @since 3.1
*/
private boolean isRegexpSupported() {
try {
Class.forName("java.util.regex.Pattern"); //$NON-NLS-1$
return true;
}
catch (Exception e) {
return false;
}
}
public void setEnabledActivityIds(Set enabledActivityIds) {
enabledActivityIds = Util.safeCopy(enabledActivityIds, String.class);
Set requiredActivityIds = new HashSet(enabledActivityIds);
getRequiredActivityIds(enabledActivityIds, requiredActivityIds);
enabledActivityIds = requiredActivityIds;
boolean activityManagerChanged = false;
Map activityEventsByActivityId = null;
Set previouslyEnabledActivityIds = null;
if (!this.enabledActivityIds.equals(enabledActivityIds)) {
previouslyEnabledActivityIds = this.enabledActivityIds;
this.enabledActivityIds = enabledActivityIds;
activityManagerChanged = true;
activityEventsByActivityId = updateActivities(activitiesById
.keySet());
}
//don't update identifiers if the enabled activity set has not changed
if (activityManagerChanged) {
Map identifierEventsByIdentifierId = updateIdentifiers(identifiersById
.keySet());
if (identifierEventsByIdentifierId != null) {
notifyIdentifiers(identifierEventsByIdentifierId);
}
}
if (activityEventsByActivityId != null) {
notifyActivities(activityEventsByActivityId);
}
if (activityManagerChanged) {
fireActivityManagerChanged(new ActivityManagerEvent(this, false,
false, true, null, null, previouslyEnabledActivityIds));
}
}
private Map updateActivities(Collection activityIds) {
Map activityEventsByActivityId = new TreeMap();
for (Iterator iterator = activityIds.iterator(); iterator.hasNext();) {
String activityId = (String) iterator.next();
Activity activity = (Activity) activitiesById.get(activityId);
if (activity != null) {
ActivityEvent activityEvent = updateActivity(activity);
if (activityEvent != null) {
activityEventsByActivityId.put(activityId, activityEvent);
}
}
}
return activityEventsByActivityId;
}
private ActivityEvent updateActivity(Activity activity) {
Set activityRequirementBindings = (Set) activityRequirementBindingsByActivityId
.get(activity.getId());
boolean activityRequirementBindingsChanged = activity
.setActivityRequirementBindings(activityRequirementBindings != null ? activityRequirementBindings
: Collections.EMPTY_SET);
Set activityPatternBindings = (Set) activityPatternBindingsByActivityId
.get(activity.getId());
boolean activityPatternBindingsChanged = activity
.setActivityPatternBindings(activityPatternBindings != null ? activityPatternBindings
: Collections.EMPTY_SET);
ActivityDefinition activityDefinition = (ActivityDefinition) activityDefinitionsById
.get(activity.getId());
boolean definedChanged = activity
.setDefined(activityDefinition != null);
boolean enabledChanged = activity.setEnabled(enabledActivityIds
.contains(activity.getId()));
boolean nameChanged = activity
.setName(activityDefinition != null ? activityDefinition
.getName() : null);
boolean descriptionChanged = activity
.setDescription(activityDefinition != null ? activityDefinition
.getDescription() : null);
boolean defaultEnabledChanged = activity.setDefaultEnabled(activityRegistry
.getDefaultEnabledActivities().contains(activity.getId()));
if (activityRequirementBindingsChanged
|| activityPatternBindingsChanged || definedChanged
|| enabledChanged || nameChanged || descriptionChanged
|| defaultEnabledChanged) {
return new ActivityEvent(activity,
activityRequirementBindingsChanged,
activityPatternBindingsChanged, definedChanged,
descriptionChanged, enabledChanged, nameChanged, defaultEnabledChanged);
}
return null;
}
private Map updateCategories(Collection categoryIds) {
Map categoryEventsByCategoryId = new TreeMap();
for (Iterator iterator = categoryIds.iterator(); iterator.hasNext();) {
String categoryId = (String) iterator.next();
Category category = (Category) categoriesById.get(categoryId);
if (category != null) {
CategoryEvent categoryEvent = updateCategory(category);
if (categoryEvent != null) {
categoryEventsByCategoryId.put(categoryId, categoryEvent);
}
}
}
return categoryEventsByCategoryId;
}
private CategoryEvent updateCategory(Category category) {
Set categoryActivityBindings = (Set) categoryActivityBindingsByCategoryId
.get(category.getId());
boolean categoryActivityBindingsChanged = category
.setCategoryActivityBindings(categoryActivityBindings != null ? categoryActivityBindings
: Collections.EMPTY_SET);
CategoryDefinition categoryDefinition = (CategoryDefinition) categoryDefinitionsById
.get(category.getId());
boolean definedChanged = category
.setDefined(categoryDefinition != null);
boolean nameChanged = category
.setName(categoryDefinition != null ? categoryDefinition
.getName() : null);
boolean descriptionChanged = category
.setDescription(categoryDefinition != null ? categoryDefinition
.getDescription() : null);
if (categoryActivityBindingsChanged || definedChanged || nameChanged
|| descriptionChanged) {
return new CategoryEvent(category, categoryActivityBindingsChanged,
definedChanged, descriptionChanged, nameChanged);
}
return null;
}
private IdentifierEvent updateIdentifier(Identifier identifier) {
String id = identifier.getId();
Set activityIds = new HashSet();
boolean enabled = false;
boolean activityIdsChanged = false;
boolean enabledChanged = false;
// short-circut logic. If all activities are enabled, then the
// identifier must be as well. Return true and schedule the remainder of
// the work to run in a background job.
if (enabledActivityIds.size() == definedActivityIds.size()) {
enabled = true;
enabledChanged = identifier.setEnabled(enabled);
identifier.setActivityIds(Collections.EMPTY_SET);
deferredIdentifiers.add(identifier);
getUpdateJob().schedule();
if (enabledChanged) {
return new IdentifierEvent(identifier, activityIdsChanged,
enabledChanged);
}
}
else {
boolean matchesAtLeastOneEnabled = false;
boolean matchesAtLeastOneDisabled = false;
for (Iterator iterator = definedActivityIds.iterator(); iterator
.hasNext();) {
String activityId = (String) iterator.next();
Activity activity = (Activity) getActivity(activityId);
if (activity.isMatch(id)) {
activityIds.add(activityId);
if (activity.isEnabled()) {
matchesAtLeastOneEnabled = true;
} else {
matchesAtLeastOneDisabled = true;
}
}
}
enabled = matchesAtLeastOneEnabled ? true : !matchesAtLeastOneDisabled;
activityIdsChanged = identifier.setActivityIds(activityIds);
enabledChanged = identifier.setEnabled(enabled);
if (activityIdsChanged || enabledChanged) {
return new IdentifierEvent(identifier, activityIdsChanged,
enabledChanged);
}
}
return null;
}
private Map updateIdentifiers(Collection identifierIds) {
Map identifierEventsByIdentifierId = new TreeMap();
for (Iterator iterator = identifierIds.iterator(); iterator.hasNext();) {
String identifierId = (String) iterator.next();
Identifier identifier = (Identifier) identifiersById
.get(identifierId);
if (identifier != null) {
IdentifierEvent identifierEvent = updateIdentifier(identifier);
if (identifierEvent != null) {
identifierEventsByIdentifierId.put(identifierId,
identifierEvent);
}
}
}
return identifierEventsByIdentifierId;
}
/**
* Unhook this manager from its registry.
*
* @since 3.1
*/
public void unhookRegistryListeners() {
activityRegistry.removeActivityRegistryListener(activityRegistryListener);
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone() {
MutableActivityManager clone = new MutableActivityManager(activityRegistry);
clone.setEnabledActivityIds(getEnabledActivityIds());
return clone;
}
/**
* Return the identifier update job.
*
* @return the job
* @since 3.1
*/
private Job getUpdateJob() {
if (deferredIdentifierJob == null) {
deferredIdentifierJob = new Job("Identifier Update Job") { //$NON-NLS-1$
/* (non-Javadoc)
* @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
*/
protected IStatus run(IProgressMonitor monitor) {
while (!deferredIdentifiers.isEmpty()) {
Identifier identifier = (Identifier) deferredIdentifiers.remove(0);
Set activityIds = new HashSet();
for (Iterator iterator = definedActivityIds.iterator(); iterator
.hasNext();) {
String activityId = (String) iterator.next();
Activity activity = (Activity) getActivity(activityId);
if (activity.isMatch(identifier.getId())) {
activityIds.add(activityId);
}
}
boolean activityIdsChanged = identifier.setActivityIds(activityIds);
if (activityIdsChanged) {
IdentifierEvent identifierEvent = new IdentifierEvent(identifier, activityIdsChanged,
false);
Map identifierEventsByIdentifierId = new HashMap(1);
identifierEventsByIdentifierId.put(identifier.getId(),
identifierEvent);
notifyIdentifiers(identifierEventsByIdentifierId);
}
}
return Status.OK_STATUS;
}
};
deferredIdentifierJob.setSystem(true);
}
return deferredIdentifierJob;
}
}