| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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 |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 474273 |
| *******************************************************************************/ |
| |
| 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.Map.Entry; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import org.eclipse.core.expressions.Expression; |
| import org.eclipse.core.runtime.Assert; |
| 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.IJobFunction; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.ui.PlatformUI; |
| 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.ITriggerPointAdvisor; |
| import org.eclipse.ui.activities.IdentifierEvent; |
| import org.eclipse.ui.progress.UIJob; |
| import org.eclipse.ui.services.IEvaluationReference; |
| import org.eclipse.ui.services.IEvaluationService; |
| |
| /** |
| * An activity registry that may be altered. |
| * |
| * @since 3.0 |
| */ |
| public final class MutableActivityManager extends AbstractActivityManager |
| implements IMutableActivityManager, Cloneable { |
| |
| private Map<String, Activity> activitiesById = new HashMap<>(); |
| |
| private Map<String, Set<IActivityRequirementBinding>> activityRequirementBindingsByActivityId = new HashMap<>(); |
| |
| private Map<String, ActivityDefinition> activityDefinitionsById = new HashMap<>(); |
| |
| private Map<String, Set<IActivityPatternBinding>> activityPatternBindingsByActivityId = new HashMap<>(); |
| |
| private IActivityRegistry activityRegistry; |
| |
| private Map<String, Category> categoriesById = new HashMap<>(); |
| |
| private Map<String, Set<ICategoryActivityBinding>> categoryActivityBindingsByCategoryId = new HashMap<>(); |
| |
| private Map<String, CategoryDefinition> categoryDefinitionsById = new HashMap<>(); |
| |
| private Set<String> definedActivityIds = new HashSet<>(); |
| |
| private Set<String> definedCategoryIds = new HashSet<>(); |
| |
| private Set<String> enabledActivityIds = new HashSet<>(); |
| |
| private Map<String, Identifier> identifiersById = new HashMap<>(); |
| |
| /** |
| * Avoid endless circular referencing of re-adding activity to evaluation |
| * listener, because of adding it the first time to evaluation listener. |
| */ |
| private boolean addingEvaluationListener = false; |
| |
| /** |
| * A list of identifiers that need to have their activity sets reconciled in the |
| * background job. |
| */ |
| private List<Identifier> deferredIdentifiers = Collections.synchronizedList(new LinkedList<>()); |
| |
| /** |
| * The identifier update job. Lazily initialized. |
| */ |
| private Job deferredIdentifierJob = null; |
| |
| private final IActivityRegistryListener activityRegistryListener = activityRegistryEvent -> readRegistry(false); |
| |
| private Map<ActivityDefinition, IEvaluationReference> refsByActivityDefinition = new HashMap<>(); |
| |
| /** |
| * Create a new instance of this class using the platform extension registry. |
| * |
| * @param triggerPointAdvisor |
| */ |
| public MutableActivityManager(ITriggerPointAdvisor triggerPointAdvisor) { |
| this(triggerPointAdvisor, new ExtensionActivityRegistry(Platform.getExtensionRegistry())); |
| } |
| |
| /** |
| * Create a new instance of this class using the provided registry. |
| * |
| * @param triggerPointAdvisor |
| * |
| * @param activityRegistry the activity registry |
| */ |
| public MutableActivityManager(ITriggerPointAdvisor triggerPointAdvisor, IActivityRegistry activityRegistry) { |
| Assert.isNotNull(activityRegistry); |
| Assert.isNotNull(triggerPointAdvisor); |
| |
| this.advisor = triggerPointAdvisor; |
| this.activityRegistry = activityRegistry; |
| |
| this.activityRegistry.addActivityRegistryListener(activityRegistryListener); |
| |
| readRegistry(true); |
| } |
| |
| @Override |
| synchronized public IActivity getActivity(String activityId) { |
| if (activityId == null) { |
| throw new NullPointerException(); |
| } |
| |
| Activity activity = activitiesById.get(activityId); |
| |
| if (activity == null) { |
| activity = new Activity(activityId); |
| updateActivity(activity); |
| activitiesById.put(activityId, activity); |
| } |
| |
| return activity; |
| } |
| |
| @Override |
| synchronized public ICategory getCategory(String categoryId) { |
| if (categoryId == null) { |
| throw new NullPointerException(); |
| } |
| |
| Category category = categoriesById.get(categoryId); |
| |
| if (category == null) { |
| category = new Category(categoryId); |
| updateCategory(category); |
| categoriesById.put(categoryId, category); |
| } |
| |
| return category; |
| } |
| |
| @Override |
| synchronized public Set<String> getDefinedActivityIds() { |
| return Collections.unmodifiableSet(definedActivityIds); |
| } |
| |
| @Override |
| synchronized public Set<String> getDefinedCategoryIds() { |
| return Collections.unmodifiableSet(definedCategoryIds); |
| } |
| |
| @Override |
| synchronized public Set<String> getEnabledActivityIds() { |
| return Collections.unmodifiableSet(enabledActivityIds); |
| } |
| |
| @Override |
| synchronized public IIdentifier getIdentifier(String identifierId) { |
| if (identifierId == null) { |
| throw new NullPointerException(); |
| } |
| |
| Identifier identifier = identifiersById.get(identifierId); |
| |
| if (identifier == null) { |
| identifier = new Identifier(identifierId); |
| updateIdentifier(identifier); |
| identifiersById.put(identifierId, identifier); |
| } |
| |
| return identifier; |
| } |
| |
| private void getRequiredActivityIds(Set<String> activityIds, Set<String> requiredActivityIds) { |
| for (String activityId : activityIds) { |
| IActivity activity = getActivity(activityId); |
| Set<String> childActivityIds = new HashSet<>(); |
| Set<IActivityRequirementBinding> activityRequirementBindings = activity.getActivityRequirementBindings(); |
| for (IActivityRequirementBinding activityRequirementBinding : activityRequirementBindings) { |
| childActivityIds.add(activityRequirementBinding.getRequiredActivityId()); |
| } |
| childActivityIds.removeAll(requiredActivityIds); |
| requiredActivityIds.addAll(childActivityIds); |
| getRequiredActivityIds(childActivityIds, requiredActivityIds); |
| } |
| } |
| |
| private void notifyActivities(Map<String, ActivityEvent> activityEventsByActivityId) { |
| for (Entry<String, ActivityEvent> entry : activityEventsByActivityId.entrySet()) { |
| String activityId = entry.getKey(); |
| ActivityEvent activityEvent = entry.getValue(); |
| Activity activity = activitiesById.get(activityId); |
| |
| if (activity != null) { |
| activity.fireActivityChanged(activityEvent); |
| } |
| } |
| } |
| |
| private void notifyCategories(Map<String, CategoryEvent> categoryEventsByCategoryId) { |
| for (Entry<String, CategoryEvent> entry : categoryEventsByCategoryId.entrySet()) { |
| String categoryId = entry.getKey(); |
| CategoryEvent categoryEvent = entry.getValue(); |
| Category category = categoriesById.get(categoryId); |
| |
| if (category != null) { |
| category.fireCategoryChanged(categoryEvent); |
| } |
| } |
| } |
| |
| private void notifyIdentifiers(Map<String, IdentifierEvent> identifierEventsByIdentifierId) { |
| for (Entry<String, IdentifierEvent> entry : identifierEventsByIdentifierId.entrySet()) { |
| String identifierId = entry.getKey(); |
| IdentifierEvent identifierEvent = entry.getValue(); |
| Identifier identifier = identifiersById.get(identifierId); |
| |
| if (identifier != null) { |
| identifier.fireIdentifierChanged(identifierEvent); |
| } |
| } |
| } |
| |
| private void readRegistry(boolean setDefaults) { |
| clearExpressions(); |
| Collection<ActivityDefinition> activityDefinitions = new ArrayList<>(); |
| activityDefinitions.addAll(activityRegistry.getActivityDefinitions()); |
| Map<String, ActivityDefinition> activityDefinitionsById = new HashMap<>( |
| ActivityDefinition.activityDefinitionsById(activityDefinitions, false)); |
| |
| for (Iterator<ActivityDefinition> iterator = activityDefinitionsById.values().iterator(); iterator.hasNext();) { |
| ActivityDefinition activityDefinition = iterator.next(); |
| String name = activityDefinition.getName(); |
| |
| if (name == null || name.isEmpty()) { |
| iterator.remove(); |
| } |
| } |
| |
| Collection<CategoryDefinition> categoryDefinitions = new ArrayList<>(); |
| categoryDefinitions.addAll(activityRegistry.getCategoryDefinitions()); |
| Map<String, CategoryDefinition> categoryDefinitionsById = new HashMap<>( |
| CategoryDefinition.categoryDefinitionsById(categoryDefinitions, false)); |
| |
| for (Iterator<CategoryDefinition> iterator = categoryDefinitionsById.values().iterator(); iterator.hasNext();) { |
| CategoryDefinition categoryDefinition = iterator.next(); |
| String name = categoryDefinition.getName(); |
| |
| if (name == null || name.isEmpty()) { |
| iterator.remove(); |
| } |
| } |
| |
| Map<String, Collection<ActivityRequirementBindingDefinition>> activityRequirementBindingDefinitionsByActivityId = ActivityRequirementBindingDefinition |
| .activityRequirementBindingDefinitionsByActivityId( |
| activityRegistry.getActivityRequirementBindingDefinitions()); |
| Map<String, Set<IActivityRequirementBinding>> activityRequirementBindingsByActivityId = new HashMap<>(); |
| |
| for (Entry<String, Collection<ActivityRequirementBindingDefinition>> entry : activityRequirementBindingDefinitionsByActivityId |
| .entrySet()) { |
| String parentActivityId = entry.getKey(); |
| if (activityDefinitionsById.containsKey(parentActivityId)) { |
| Collection<ActivityRequirementBindingDefinition> activityRequirementBindingDefinitions = entry |
| .getValue(); |
| if (activityRequirementBindingDefinitions != null) { |
| for (ActivityRequirementBindingDefinition activityRequirementBindingDefinition : activityRequirementBindingDefinitions) { |
| String childActivityId = activityRequirementBindingDefinition.getRequiredActivityId(); |
| |
| if (activityDefinitionsById.containsKey(childActivityId)) { |
| IActivityRequirementBinding activityRequirementBinding = new ActivityRequirementBinding( |
| childActivityId, parentActivityId); |
| Set<IActivityRequirementBinding> activityRequirementBindings = activityRequirementBindingsByActivityId |
| .get(parentActivityId); |
| |
| if (activityRequirementBindings == null) { |
| activityRequirementBindings = new HashSet<>(); |
| activityRequirementBindingsByActivityId.put(parentActivityId, |
| activityRequirementBindings); |
| } |
| |
| activityRequirementBindings.add(activityRequirementBinding); |
| } |
| } |
| } |
| } |
| } |
| |
| Map<String, Collection<ActivityPatternBindingDefinition>> activityPatternBindingDefinitionsByActivityId = ActivityPatternBindingDefinition |
| .activityPatternBindingDefinitionsByActivityId(activityRegistry.getActivityPatternBindingDefinitions()); |
| Map<String, Set<IActivityPatternBinding>> activityPatternBindingsByActivityId = new HashMap<>(); |
| |
| for (Entry<String, Collection<ActivityPatternBindingDefinition>> entry : activityPatternBindingDefinitionsByActivityId |
| .entrySet()) { |
| String activityId = entry.getKey(); |
| if (activityDefinitionsById.containsKey(activityId)) { |
| Collection<ActivityPatternBindingDefinition> activityPatternBindingDefinitions = entry.getValue(); |
| if (activityPatternBindingDefinitions != null) { |
| for (ActivityPatternBindingDefinition activityPatternBindingDefinition : activityPatternBindingDefinitions) { |
| String pattern = activityPatternBindingDefinition.getPattern(); |
| |
| if (pattern != null && pattern.length() != 0) { |
| IActivityPatternBinding activityPatternBinding = new ActivityPatternBinding(activityId, |
| pattern, activityPatternBindingDefinition.isEqualityPattern()); |
| Set<IActivityPatternBinding> activityPatternBindings = activityPatternBindingsByActivityId |
| .get(activityId); |
| |
| if (activityPatternBindings == null) { |
| activityPatternBindings = new HashSet<>(); |
| activityPatternBindingsByActivityId.put(activityId, activityPatternBindings); |
| } |
| |
| activityPatternBindings.add(activityPatternBinding); |
| } |
| } |
| } |
| } |
| } |
| |
| Map<String, Collection<CategoryActivityBindingDefinition>> categoryActivityBindingDefinitionsByCategoryId = CategoryActivityBindingDefinition |
| .categoryActivityBindingDefinitionsByCategoryId( |
| activityRegistry.getCategoryActivityBindingDefinitions()); |
| Map<String, Set<ICategoryActivityBinding>> categoryActivityBindingsByCategoryId = new HashMap<>(); |
| |
| for (Entry<String, Collection<CategoryActivityBindingDefinition>> entry : categoryActivityBindingDefinitionsByCategoryId |
| .entrySet()) { |
| String categoryId = entry.getKey(); |
| if (categoryDefinitionsById.containsKey(categoryId)) { |
| Collection<CategoryActivityBindingDefinition> categoryActivityBindingDefinitions = entry.getValue(); |
| if (categoryActivityBindingDefinitions != null) { |
| for (CategoryActivityBindingDefinition categoryActivityBindingDefinition : categoryActivityBindingDefinitions) { |
| String activityId = categoryActivityBindingDefinition.getActivityId(); |
| |
| if (activityDefinitionsById.containsKey(activityId)) { |
| ICategoryActivityBinding categoryActivityBinding = new CategoryActivityBinding(activityId, |
| categoryId); |
| Set<ICategoryActivityBinding> categoryActivityBindings = 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<String> definedActivityIds = new HashSet<>(activityDefinitionsById.keySet()); |
| |
| Set<String> previouslyDefinedActivityIds = null; |
| if (!definedActivityIds.equals(this.definedActivityIds)) { |
| previouslyDefinedActivityIds = this.definedActivityIds; |
| this.definedActivityIds = definedActivityIds; |
| definedActivityIdsChanged = true; |
| } |
| |
| boolean definedCategoryIdsChanged = false; |
| Set<String> definedCategoryIds = new HashSet<>(categoryDefinitionsById.keySet()); |
| |
| Set<String> previouslyDefinedCategoryIds = null; |
| if (!definedCategoryIds.equals(this.definedCategoryIds)) { |
| previouslyDefinedCategoryIds = this.definedCategoryIds; |
| this.definedCategoryIds = definedCategoryIds; |
| definedCategoryIdsChanged = true; |
| } |
| |
| Set<String> enabledActivityIds = new HashSet<>(this.enabledActivityIds); |
| getRequiredActivityIds(this.enabledActivityIds, enabledActivityIds); |
| boolean enabledActivityIdsChanged = false; |
| |
| Set<String> previouslyEnabledActivityIds = null; |
| if (!this.enabledActivityIds.equals(enabledActivityIds)) { |
| previouslyEnabledActivityIds = this.enabledActivityIds; |
| this.enabledActivityIds = enabledActivityIds; |
| enabledActivityIdsChanged = true; |
| } |
| |
| Map<String, ActivityEvent> activityEventsByActivityId = updateActivities(activitiesById.keySet()); |
| |
| Map<String, CategoryEvent> categoryEventsByCategoryId = updateCategories(categoriesById.keySet()); |
| |
| Map<String, IdentifierEvent> 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())); |
| } |
| } |
| |
| private void clearExpressions() { |
| IEvaluationService evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class); |
| Iterator<IEvaluationReference> i = refsByActivityDefinition.values().iterator(); |
| while (i.hasNext()) { |
| IEvaluationReference ref = i.next(); |
| evaluationService.removeEvaluationListener(ref); |
| } |
| refsByActivityDefinition.clear(); |
| } |
| |
| @Override |
| synchronized public void setEnabledActivityIds(Set<String> enabledActivityIds) { |
| enabledActivityIds = new HashSet<>(enabledActivityIds); |
| Set<String> requiredActivityIds = new HashSet<>(enabledActivityIds); |
| getRequiredActivityIds(enabledActivityIds, requiredActivityIds); |
| enabledActivityIds = requiredActivityIds; |
| Set<String> deltaActivityIds = null; |
| boolean activityManagerChanged = false; |
| Map<String, ActivityEvent> activityEventsByActivityId = null; |
| |
| Set<String> previouslyEnabledActivityIds = null; |
| // the sets are different so there may be work to do. |
| if (!this.enabledActivityIds.equals(enabledActivityIds)) { |
| previouslyEnabledActivityIds = this.enabledActivityIds; |
| activityManagerChanged = true; |
| |
| // break out the additions to the current set |
| Set<String> additions = new HashSet<>(enabledActivityIds); |
| additions.removeAll(previouslyEnabledActivityIds); |
| |
| // and the removals |
| Set<String> removals = new HashSet<>(previouslyEnabledActivityIds); |
| removals.removeAll(enabledActivityIds); |
| |
| // remove from each set the expression-activities |
| removeExpressionControlledActivities(additions); |
| removeExpressionControlledActivities(removals); |
| |
| // merge the two sets into one delta - these are the changes that |
| // need to be made after taking expressions into account |
| deltaActivityIds = new HashSet<>(additions); |
| deltaActivityIds.addAll(removals); |
| |
| if (deltaActivityIds.size() > 0) { |
| // instead of blowing away the old set with the new we will |
| // instead modify it based on the deltas |
| // add in all the new activities to the current set |
| enabledActivityIds.addAll(additions); |
| // and remove the stale ones |
| enabledActivityIds.removeAll(removals); |
| // finally set the internal set of activities |
| this.enabledActivityIds = enabledActivityIds; |
| activityEventsByActivityId = updateActivities(deltaActivityIds); |
| } else { |
| return; |
| } |
| } |
| |
| updateListeners(activityManagerChanged, activityEventsByActivityId, deltaActivityIds, |
| previouslyEnabledActivityIds); |
| } |
| |
| /** |
| * Updates all the listeners to changes in the state. |
| * |
| * @param activityManagerChanged |
| * @param activityEventsByActivityId |
| * @param deltaActivityIds |
| * @param previouslyEnabledActivityIds |
| */ |
| private void updateListeners(boolean activityManagerChanged, Map<String, ActivityEvent> activityEventsByActivityId, |
| Set<String> deltaActivityIds, Set<String> previouslyEnabledActivityIds) { |
| // don't update identifiers if the enabled activity set has not changed |
| if (activityManagerChanged) { |
| Map<String, IdentifierEvent> identifierEventsByIdentifierId = updateIdentifiers(identifiersById.keySet(), |
| deltaActivityIds); |
| if (identifierEventsByIdentifierId != null) { |
| notifyIdentifiers(identifierEventsByIdentifierId); |
| } |
| } |
| if (activityEventsByActivityId != null) { |
| notifyActivities(activityEventsByActivityId); |
| } |
| |
| if (activityManagerChanged) { |
| fireActivityManagerChanged( |
| new ActivityManagerEvent(this, false, false, true, null, null, previouslyEnabledActivityIds)); |
| } |
| } |
| |
| private void addExpressionEnabledActivity(String id) { |
| Set<String> previouslyEnabledActivityIds = new HashSet<>(this.enabledActivityIds); |
| this.enabledActivityIds.add(id); |
| |
| updateExpressionEnabledActivities(id, previouslyEnabledActivityIds); |
| } |
| |
| private void removeExpressionEnabledActivity(String id) { |
| Set<String> previouslyEnabledActivityIds = new HashSet<>(this.enabledActivityIds); |
| this.enabledActivityIds.remove(id); |
| |
| updateExpressionEnabledActivities(id, previouslyEnabledActivityIds); |
| } |
| |
| /** |
| * @param id |
| * @param previouslyEnabledActivityIds |
| */ |
| private void updateExpressionEnabledActivities(String id, Set<String> previouslyEnabledActivityIds) { |
| Set<String> deltaActivityIds = new HashSet<>(); |
| deltaActivityIds.add(id); |
| Map<String, ActivityEvent> activityEventsByActivityId = updateActivities(deltaActivityIds); |
| |
| updateListeners(true, activityEventsByActivityId, deltaActivityIds, previouslyEnabledActivityIds); |
| } |
| |
| /** |
| * Removes from a list of activity changes all those that are based on |
| * expressions |
| * |
| * @param delta the set to modify |
| */ |
| private void removeExpressionControlledActivities(Set<String> delta) { |
| |
| for (Iterator<String> i = delta.iterator(); i.hasNext();) { |
| String id = i.next(); |
| IActivity activity = activitiesById.get(id); |
| Expression expression = activity.getExpression(); |
| |
| if (expression != null) { |
| i.remove(); |
| } |
| } |
| } |
| |
| private Map<String, ActivityEvent> updateActivities(Collection<String> activityIds) { |
| Map<String, ActivityEvent> activityEventsByActivityId = new TreeMap<>(); |
| |
| for (String activityId : activityIds) { |
| Activity activity = activitiesById.get(activityId); |
| |
| if (activity != null) { |
| ActivityEvent activityEvent = updateActivity(activity); |
| |
| if (activityEvent != null) { |
| activityEventsByActivityId.put(activityId, activityEvent); |
| } |
| } |
| } |
| |
| return activityEventsByActivityId; |
| } |
| |
| private IPropertyChangeListener enabledWhenListener = event -> { |
| if (addingEvaluationListener) { |
| return; |
| } |
| |
| Object nv = event.getNewValue(); |
| boolean enabledWhen = nv == null ? false : ((Boolean) nv).booleanValue(); |
| String id = event.getProperty(); |
| IActivity activity = activitiesById.get(id); |
| if (activity.isEnabled() != enabledWhen) { |
| if (enabledWhen) { |
| addExpressionEnabledActivity(id); |
| } else { |
| removeExpressionEnabledActivity(id); |
| } |
| } |
| }; |
| |
| private ITriggerPointAdvisor advisor; |
| |
| private ActivityEvent updateActivity(Activity activity) { |
| Set<IActivityRequirementBinding> activityRequirementBindings = activityRequirementBindingsByActivityId |
| .get(activity.getId()); |
| boolean activityRequirementBindingsChanged = activity.setActivityRequirementBindings( |
| activityRequirementBindings != null ? activityRequirementBindings : Collections.emptySet()); |
| Set<IActivityPatternBinding> activityPatternBindings = activityPatternBindingsByActivityId |
| .get(activity.getId()); |
| boolean activityPatternBindingsChanged = activity.setActivityPatternBindings( |
| activityPatternBindings != null ? activityPatternBindings : Collections.emptySet()); |
| ActivityDefinition activityDefinition = activityDefinitionsById.get(activity.getId()); |
| boolean definedChanged = activity.setDefined(activityDefinition != null); |
| |
| // enabledWhen comes into play |
| IEvaluationReference ref = refsByActivityDefinition.get(activityDefinition); |
| IEvaluationService evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class); |
| boolean newRef = false; |
| if (activityDefinition != null && evaluationService != null) { |
| activity.setExpression(activityDefinition.getEnabledWhen()); |
| if (ref == null && activityDefinition.getEnabledWhen() != null) { |
| addingEvaluationListener = true; |
| try { |
| ref = evaluationService.addEvaluationListener(activityDefinition.getEnabledWhen(), |
| enabledWhenListener, activityDefinition.getId()); |
| newRef = true; |
| } finally { |
| addingEvaluationListener = false; |
| } |
| if (ref != null) { |
| refsByActivityDefinition.put(activityDefinition, ref); |
| } |
| } |
| } |
| final boolean enabledChanged; |
| if (ref != null && evaluationService != null) { |
| enabledChanged = activity.setEnabled(ref.evaluate(evaluationService.getCurrentState())); |
| if (newRef && activity.isEnabled()) { |
| // make sure this activity is in the enabled set for this |
| // manager - event firing will be handled by the caller to this |
| // method. |
| this.enabledActivityIds.add(activity.getId()); |
| } |
| } else { |
| 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<String, CategoryEvent> updateCategories(Collection<String> categoryIds) { |
| Map<String, CategoryEvent> categoryEventsByCategoryId = new TreeMap<>(); |
| |
| for (String categoryId : categoryIds) { |
| 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<ICategoryActivityBinding> categoryActivityBindings = categoryActivityBindingsByCategoryId |
| .get(category.getId()); |
| boolean categoryActivityBindingsChanged = category.setCategoryActivityBindings( |
| categoryActivityBindings != null ? categoryActivityBindings : Collections.emptySet()); |
| 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) { |
| return updateIdentifier(identifier, definedActivityIds); |
| } |
| |
| private IdentifierEvent updateIdentifier(Identifier identifier, Set<String> changedActivityIds) { |
| String id = identifier.getId(); |
| Set<String> 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 { |
| Set<String> activityIdsToUpdate = new HashSet<>(changedActivityIds); |
| if (identifier.getActivityIds() != null) { |
| activityIdsToUpdate.addAll(identifier.getActivityIds()); |
| } |
| for (String activityId : activityIdsToUpdate) { |
| Activity activity = (Activity) getActivity(activityId); |
| |
| if (activity.isMatch(id)) { |
| activityIds.add(activityId); |
| } |
| } |
| |
| activityIdsChanged = identifier.setActivityIds(activityIds); |
| |
| if (advisor != null) { |
| enabled = advisor.computeEnablement(this, identifier); |
| } |
| enabledChanged = identifier.setEnabled(enabled); |
| |
| if (activityIdsChanged || enabledChanged) { |
| return new IdentifierEvent(identifier, activityIdsChanged, enabledChanged); |
| } |
| } |
| return null; |
| } |
| |
| private Map<String, IdentifierEvent> updateIdentifiers(Collection<String> identifierIds) { |
| return updateIdentifiers(identifierIds, definedActivityIds); |
| } |
| |
| private Map<String, IdentifierEvent> updateIdentifiers(Collection<String> identifierIds, |
| Set<String> changedActivityIds) { |
| Map<String, IdentifierEvent> identifierEventsByIdentifierId = new TreeMap<>(); |
| |
| for (String identifierId : identifierIds) { |
| Identifier identifier = identifiersById.get(identifierId); |
| |
| if (identifier != null) { |
| IdentifierEvent identifierEvent = updateIdentifier(identifier, changedActivityIds); |
| |
| if (identifierEvent != null) { |
| identifierEventsByIdentifierId.put(identifierId, identifierEvent); |
| } |
| } |
| } |
| |
| return identifierEventsByIdentifierId; |
| } |
| |
| /** |
| * Unhook this manager from its registry. |
| * |
| * @since 3.1 |
| */ |
| public void unhookRegistryListeners() { |
| activityRegistry.removeActivityRegistryListener(activityRegistryListener); |
| } |
| |
| @Override |
| synchronized public Object clone() { |
| MutableActivityManager clone = new MutableActivityManager(advisor, activityRegistry); |
| clone.setEnabledActivityIds(getEnabledActivityIds()); |
| return clone; |
| } |
| |
| /** |
| * Return the identifier update job. |
| * |
| * @return the job |
| * @since 3.1 |
| */ |
| private Job getUpdateJob() { |
| if (deferredIdentifierJob == null) { |
| deferredIdentifierJob = Job.create("Activity Identifier Update", (IJobFunction) monitor -> { //$NON-NLS-1$ |
| final Map<String, IdentifierEvent> identifierEventsByIdentifierId = new HashMap<>(); |
| |
| while (!deferredIdentifiers.isEmpty()) { |
| Identifier identifier = deferredIdentifiers.remove(0); |
| Set<String> activityIds = new HashSet<>(); |
| for (String activityId : definedActivityIds) { |
| 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); |
| identifierEventsByIdentifierId.put(identifier.getId(), identifierEvent); |
| } |
| } |
| if (!identifierEventsByIdentifierId.isEmpty()) { |
| UIJob notifyJob = new UIJob("Activity Identifier Update UI") { //$NON-NLS-1$ |
| @Override |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| notifyIdentifiers(identifierEventsByIdentifierId); |
| return Status.OK_STATUS; |
| } |
| }; |
| notifyJob.setSystem(true); |
| notifyJob.schedule(); |
| } |
| return Status.OK_STATUS; |
| }); |
| deferredIdentifierJob.setSystem(true); |
| } |
| return deferredIdentifierJob; |
| } |
| |
| } |