diff options
author | Michael Valenta | 2006-02-03 19:45:28 +0000 |
---|---|---|
committer | Michael Valenta | 2006-02-03 19:45:28 +0000 |
commit | fbcec19eae86e0404938bdf8f030711aedd45e7c (patch) | |
tree | 6b966fa99072de3e955aead841c1e6536d2a4347 | |
parent | fab31f63f009dbf7f2ee619b9c13c27924727f5c (diff) | |
download | eclipse.platform.team-fbcec19eae86e0404938bdf8f030711aedd45e7c.tar.gz eclipse.platform.team-fbcec19eae86e0404938bdf8f030711aedd45e7c.tar.xz eclipse.platform.team-fbcec19eae86e0404938bdf8f030711aedd45e7c.zip |
Refactored Merge operation to better support concurrency
44 files changed, 1230 insertions, 877 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeManager.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeManager.java index 757da230d..9914e35c3 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeManager.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeManager.java @@ -12,6 +12,8 @@ package org.eclipse.team.core.mapping; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.mapping.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.core.mapping.provider.IResourceMappingScopeParticipant; import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; @@ -49,6 +51,11 @@ public interface IResourceMappingScopeManager { /** * Return the projects that apply to this manager. + * The projects returned will depend on the type of context used + * to generate this scope. If the context is a local context, + * all workspace projects are returned. If it is a remote context, + * the projects are the same as those returned from + * {@link RemoteResourceMappingContext#getProjects()} * @return the projects that apply to this manager */ IProject[] getProjects(); @@ -64,28 +71,44 @@ public interface IResourceMappingScopeManager { * uses to obtain traversals from resource mappings */ ResourceMappingContext getContext(); + + /** + * Return whether the scope has been initialized. + * @return whether the scope has been initialized. + */ + boolean isInitialized(); /** - * Add a listener to this scope. Listeners will be notified whenever the - * list of projects that apply to this scope change. Events will also be - * issued if the resource mapping context of this manager is a - * {@link RemoteResourceMappingContext} and the remote state of a resource - * that is a child of the projects. + * Build the scope that is used to determine the complete set of resource + * mappings, and hence resources, that an operation should be performed on. * <p> - * Participants that wich toknow if the contents of the scope chaneg can add - * a property change listener to the scope using - * {@link ISynchronizationScope#addPropertyChangeListener(IPropertyChangeListener)}. + * This method obtaines a lock on the workspace root to avoid workspace + * changes while calculating the scope. + * @param monitor a progress monitor + * when building the scope * - * @param listener - * a change listener + * @throws CoreException */ - void addListener(IScopeContextChangeListener listener); + void initialize(IProgressMonitor monitor) throws CoreException; /** - * Remov the listener from the manager. Removing a listener that - * is not present has no effect. - * @param listener the listener + * Refresh the scope of this manager for the given mappings. + * Changes in the scope will be reported as a property change + * event fired from the scope. Clients should call this method + * when a change in the workspace or a change issued from this + * manager have resulted in a change in the resources that + * should be included in the scope. + * @param mappings the mappings to be refreshed + * @param monitor a progress monitor + * @return a set of traversals that cover the given mappings + * @throws CoreException + */ + ResourceTraversal[] refresh(ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException; + + /** + * Method to be invoked when the scope of this + * manager is no longer needed. */ - void removeListener(IScopeContextChangeListener listener); + void dispose(); } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeParticipantFactory.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeParticipantFactory.java new file mode 100644 index 000000000..a21b1c60a --- /dev/null +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IResourceMappingScopeParticipantFactory.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 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.team.core.mapping; + +import org.eclipse.core.resources.mapping.ModelProvider; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.team.core.mapping.provider.IResourceMappingScopeParticipant; +import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; + +/** + * Factory interface for creating a participant for use with an + * {@link IResourceMappingScopeManager}. This factory should be + * assocated with a {@link ModelProvider} using the {@link IAdaptable} + * mechanism. + * <p> + * This interface may be implemented by clients. + * + * @see ModelProvider + * @see IAdaptable + * @see IAdapterManager + * @see IResourceMappingScopeManager + * @see IResourceMappingScopeParticipant + * @see ResourceMappingScopeParticipant + * <p> + * <strong>EXPERIMENTAL</strong>. This class or interface has been added as + * part of a work in progress. There is a guarantee neither that this API will + * work nor that it will remain the same. Please do not use this API without + * consulting with the Platform/Team team. + * </p> + * @since 3.2 + */ +public interface IResourceMappingScopeParticipantFactory { + + /** + * Create a participant in the scope management process for the given model provider. + * @param provider the model provider + * @param manager the scope manager + * @return a participant in the scope management process + */ + IResourceMappingScopeParticipant createParticipant(ModelProvider provider, ResourceMappingScopeManager manager); + +} diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IScopeContextChangeListener.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/ResourceMappingScopeParticipant.java index d88930b1b..a276797d1 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/IScopeContextChangeListener.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/ResourceMappingScopeParticipant.java @@ -10,29 +10,28 @@ *******************************************************************************/ package org.eclipse.team.core.mapping; -import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; - +import org.eclipse.team.core.mapping.provider.IResourceMappingScopeParticipant; /** - * A litener that will be notified whenever the list of projects that apply to - * this scope change. Events will also be issued if the resource mapping context - * of this manager is a {@link RemoteResourceMappingContext} and the remot state - * of a resource that is a child of the projects. - * <p> - * This interface may be implemented by clients. + * Implementation of the {@link IResourceMappingScopeParticipant} class. + * + * @see IResourceMappingScopeParticipantFactory * <p> * <strong>EXPERIMENTAL</strong>. This class or interface has been added as * part of a work in progress. There is a guarantee neither that this API will * work nor that it will remain the same. Please do not use this API without * consulting with the Platform/Team team. * </p> - * - * @see IResourceMappingScopeManager#addListener(IScopeContextChangeListener) - * * @since 3.2 */ -public interface IScopeContextChangeListener { - - +public abstract class ResourceMappingScopeParticipant implements + IResourceMappingScopeParticipant { + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.provider.IResourceMappingScopeParticipant#dispose() + */ + public void dispose() { + // Do nothing, by default + } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/IResourceMappingScopeParticipant.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/IResourceMappingScopeParticipant.java index 296e39a4e..a2597ba6e 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/IResourceMappingScopeParticipant.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/IResourceMappingScopeParticipant.java @@ -10,19 +10,20 @@ *******************************************************************************/ package org.eclipse.team.core.mapping.provider; +import org.eclipse.core.resources.*; +import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.team.core.mapping.IResourceMappingScope; -import org.eclipse.team.core.mapping.IResourceMappingScopeManager; +import org.eclipse.team.core.mapping.*; /** - * A scope participant is responsible for ensuring that the resources - * contained within an {@link IResourceMappingScope} that overlap with the - * participant's model provider stay up-to-date - * with the model elements (represented as {@link ResourceMapping} instances) - * contained in the scope. + * A scope participant is responsible for ensuring that the resources contained + * within an {@link IResourceMappingScope} that overlap with the participant's + * model provider stay up-to-date with the model elements (represented as + * {@link ResourceMapping} instances) contained in the scope. * * <p> - * This interface is not intended to be implemented by clients. + * This interface is not intended to be implemented by clients. CLients should instead subclass + * {@link ResourceMappingScopeParticipant}. * <p> * <strong>EXPERIMENTAL</strong>. This class or interface has been added as * part of a work in progress. There is a guarantee neither that this API will @@ -37,4 +38,32 @@ import org.eclipse.team.core.mapping.IResourceMappingScopeManager; */ public interface IResourceMappingScopeParticipant { + /** + * Callback that the manager makes to participants when the state of + * resources that are contained in the resource mapping context of the + * manager change. This method will only be invoked when the context of the + * manager is a {@link RemoteResourceMappingContext} and the state of one or + * more resources changes w.r.t. the context. It is the responsibility of the + * participant to react to local changes that affect the resources in the + * scope by calling + * {@link IResourceMappingScopeManager#refresh(ResourceMapping[], org.eclipse.core.runtime.IProgressMonitor)}. + * + * @param manager + * the scope manager + * @param resources + * the changed resources + * @param projects + * projects that were either added or removed + * @return the resource mappings that need to be refreshed. + */ + ResourceMapping[] handleContextChange( + IResourceMappingScopeManager manager, IResource[] resources, IProject[] projects); + + /** + * Callback from the scope manager when the scope is no longer needed. + * This si done to give participants a chance to remove a + * registered {@link IResourceChangeListener} or any other listeners. + */ + void dispose(); + } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/ResourceMappingScopeManager.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/ResourceMappingScopeManager.java index d38651bcb..75b2fb30b 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/ResourceMappingScopeManager.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/ResourceMappingScopeManager.java @@ -14,9 +14,10 @@ import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.*; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.team.core.mapping.*; +import org.eclipse.team.core.subscribers.SubscriberScopeManager; import org.eclipse.team.internal.core.Policy; import org.eclipse.team.internal.core.mapping.*; @@ -28,20 +29,24 @@ import org.eclipse.team.internal.core.mapping.*; * Here's a summary of the scope generation algorithm: * <ol> * <li>Obtain selected mappings - * <li>Project mappings onto resources using the appropriate - * context(s) in order to obtain a set of ResourceTraverals + * <li>Project mappings onto resources using the appropriate context(s) in + * order to obtain a set of ResourceTraverals * <li>Determine what model providers are interested in the targeted resources * <li>From those model providers, obtain the set of affected resource mappings * <li>If the original set is the same as the new set, we are done. - * <li>if the set differs from the original selection, rerun the mapping process - * for any new mappings - * <ul> - * <li>Only need to query model providers for mappings for new resources - * <li>If new mappings are obtained, - * ask model provider to compress the mappings? - * <li>keep repeating until no new mappings or resources are added - * </ul> - * </ol> + * <li>if the set differs from the original selection, rerun the mapping + * process for any new mappings + * <ul> + * <li>Only need to query model providers for mappings for new resources + * <li>keep repeating until no new mappings or resources are added + * </ul> + * </ol> + * <p> + * This implementation does not involve participants in the scope management + * process. It is up to subclasses that wish to support a longer life cycle for + * scopes to provide for participation. For example, the + * {@link SubscriberScopeManager} class includes participates in the scope + * management process. * <p> * This class is can be subclasses by clients. * @@ -53,6 +58,7 @@ import org.eclipse.team.internal.core.mapping.*; * </p> * * @see org.eclipse.core.resources.mapping.ResourceMapping + * @see SubscriberScopeManager * * @since 3.2 */ @@ -62,6 +68,7 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager private final ResourceMappingContext context; private final boolean consultModels; private IResourceMappingScope scope; + private boolean initialized; /** * Convenience method for obtaining the set of resource @@ -104,48 +111,73 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager * If <code>consultModels</code> is <code>true</code> then * the moel providers will be queried in order to determine if * additional mappings should be included in the scope + * @param inputMappings the input mappings * @param resourceMappingContext a resource mapping context * @param consultModels whether modle providers should be consulted */ - public ResourceMappingScopeManager(ResourceMappingContext resourceMappingContext, boolean consultModels) { + public ResourceMappingScopeManager(ResourceMapping[] inputMappings, ResourceMappingContext resourceMappingContext, boolean consultModels) { this.context = resourceMappingContext; this.consultModels = consultModels; + scope = createScope(inputMappings); } + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#isInitialized() + */ + public boolean isInitialized() { + return initialized; + } + /** - * Build the scope that is used to determine the complete set of resource - * mappings, and hence resources, that an operation should be performed on. - * If <code>useLocalContext</code> is <code>true</code> then the - * {@link ResourceMappingContext#LOCAL_CONTEXT} is used to prepare the scope instead - * of the context associatd with the manager. Clients may wish to do this - * when long running operations should not occur. - * - * @param selectedMappings the selected set of resource mappings - * @param useLocalContext indicates that the localcontext should be used - * when building the scope - * @param monitor a progress monitor - * @return a scope that defines the complete set of resources to be operated - * on - * @throws CoreException + * Return the scheduling rule that is used when initializing + * and refreshing the scope. By default, it is the + * workspace root. + * @return the scheduling rule that is used when initializing + * and refreshing the scope + */ + public ISchedulingRule getSchedulingRule() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#initialize(org.eclipse.core.runtime.IProgressMonitor) */ - public IResourceMappingScope prepareScope( - ResourceMapping[] selectedMappings, - boolean useLocalContext, + public void initialize( IProgressMonitor monitor) throws CoreException { + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + internalPrepareContext(monitor); + } + }, getSchedulingRule(), IResource.NONE, monitor); + } + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#refresh(org.eclipse.core.resources.mapping.ResourceMapping[], org.eclipse.core.runtime.IProgressMonitor) + */ + public ResourceTraversal[] refresh(final ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException { + // We need to lock the workspace when building the scope + final ResourceTraversal[][] traversals = new ResourceTraversal[][] { new ResourceTraversal[0] }; + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + workspace.run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + traversals[0] = internalRefreshScope(mappings, monitor); + } + }, getSchedulingRule(), IResource.NONE, monitor); + return traversals[0]; + } + + private void internalPrepareContext(IProgressMonitor monitor) throws CoreException { + if (initialized) + return; monitor.beginTask(null, IProgressMonitor.UNKNOWN); - - // Create the scope - scope = createScope(selectedMappings); - // Accumulate the initial set of mappings we need traversals for - ResourceMapping[] targetMappings = selectedMappings; + ResourceMapping[] targetMappings = scope.getInputMappings(); ResourceTraversal[] newTraversals; boolean firstTime = true; boolean hasAdditionalResources = false; int count = 0; do { - newTraversals = addMappingsToScope(targetMappings, useLocalContext, + newTraversals = addMappingsToScope(targetMappings, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN)); if (newTraversals.length > 0 && consultModels) { ResourceTraversal[] adjusted = adjustInputTraversals(newTraversals); @@ -161,26 +193,8 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager } while (consultModels & newTraversals.length != 0 && count++ < MAX_ITERATION); setHasAdditionalMappings(scope, consultModels && internalHasAdditionalMappings()); setHasAdditionalResources(consultModels && hasAdditionalResources); - return scope; - } - - /** - * Refresh the scope of this manager for the given mappings. - * @param mappings the mappings to be refreshed - * @param monitor a progress monitor - * @return a set of traversals that cover the given mappings - * @throws CoreException - */ - public ResourceTraversal[] refreshScope(final ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException { - // We need to lock the workspace when building the scope - final ResourceTraversal[][] traversals = new ResourceTraversal[][] { new ResourceTraversal[0] }; - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - workspace.run(new IWorkspaceRunnable() { - public void run(IProgressMonitor monitor) throws CoreException { - traversals[0] = internalRefreshScope(mappings, monitor); - } - }, workspace.getRoot(), IResource.NONE, monitor); - return traversals[0]; + monitor.done(); + initialized = true; } private ResourceTraversal[] internalRefreshScope(ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException { @@ -254,7 +268,7 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager ResourceTraversal[] adjusted = adjustInputTraversals(newTraversals); targetMappings = getMappingsFromProviders(adjusted, context, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN)); - newTraversals = addMappingsToScope(targetMappings, false, + newTraversals = addMappingsToScope(targetMappings, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN)); } while (newTraversals.length != 0 && count++ < MAX_ITERATION); if (!scope.hasAdditionalMappings()) { @@ -315,7 +329,7 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager */ protected final IResourceMappingScope createScope( ResourceMapping[] inputMappings) { - return new ResourceMappingScope(this, inputMappings); + return new ResourceMappingScope(inputMappings); } /** @@ -338,11 +352,9 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager private ResourceTraversal[] addMappingsToScope( ResourceMapping[] targetMappings, - boolean useLocalContext, IProgressMonitor monitor) throws CoreException { + IProgressMonitor monitor) throws CoreException { CompoundResourceTraversal result = new CompoundResourceTraversal(); ResourceMappingContext context = this.context; - if (useLocalContext) - context = ResourceMappingContext.LOCAL_CONTEXT; for (int i = 0; i < targetMappings.length; i++) { ResourceMapping mapping = targetMappings[i]; if (scope.getTraversals(mapping) == null) { @@ -389,21 +401,8 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager return true; } - /** - * Return whether the model providers should be consulted in - * order to see if the scope needs to be expanded. - * @return whether the model providers should be consulted - */ - public boolean isConsultModels() { - return consultModels; - } - - /** - * Return the resource mapping context used during the scope - * generation process in order to determine what resources - * are to be included in the scope. - * @return the resource mapping context used during the scope - * generation process + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#getContext() */ public ResourceMappingContext getContext() { return context; @@ -415,16 +414,6 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager public IResourceMappingScope getScope() { return scope; } - - public void addListener(IScopeContextChangeListener listener) { - // TODO Auto-generated method stub - - } - - public void removeListener(IScopeContextChangeListener listener) { - // TODO Auto-generated method stub - - } /* (non-Javadoc) * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#getProjects() @@ -436,4 +425,11 @@ public class ResourceMappingScopeManager implements IResourceMappingScopeManager } return ResourcesPlugin.getWorkspace().getRoot().getProjects(); } + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#dispose() + */ + public void dispose() { + // Do nothing, by default + } } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/SynchronizationContext.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/SynchronizationContext.java index 5356572e2..ae500a434 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/SynchronizationContext.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/mapping/provider/SynchronizationContext.java @@ -18,7 +18,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.core.mapping.*; import org.eclipse.team.internal.core.Policy; import org.eclipse.team.internal.core.mapping.DiffCache; -import org.eclipse.team.internal.core.mapping.ResourceMappingScope; /** * Abstract implementation of the {@link ISynchronizationContext} interface. @@ -98,24 +97,16 @@ public abstract class SynchronizationContext implements ISynchronizationContext */ public void refresh(ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException { monitor.beginTask(null, 100); - ResourceMappingScopeManager manager = getScopeManager(); + ResourceMappingScopeManager manager = null; //getScopeManager(); if (manager == null) { // The scope manager is missing so just refresh everything refresh(scope.getTraversals(), IResource.NONE, Policy.subMonitorFor(monitor, 50)); } else { - ResourceTraversal[] traversals = manager.refreshScope(mappings, Policy.subMonitorFor(monitor, 50)); + ResourceTraversal[] traversals = manager.refresh(mappings, Policy.subMonitorFor(monitor, 50)); if (traversals.length > 0) refresh(traversals, IResource.NONE, Policy.subMonitorFor(monitor, 50)); } monitor.done(); } - private ResourceMappingScopeManager getScopeManager() { - if (scope instanceof ResourceMappingScope) { - ResourceMappingScope rms = (ResourceMappingScope) scope; - rms.getManager(); - } - return null; - } - } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberMergeContext.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberMergeContext.java index 4397be33b..77c363f30 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberMergeContext.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberMergeContext.java @@ -14,7 +14,7 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; import org.eclipse.team.core.mapping.provider.MergeContext; import org.eclipse.team.core.mapping.provider.ResourceDiffTree; import org.eclipse.team.core.synchronize.SyncInfo; @@ -39,10 +39,12 @@ public abstract class SubscriberMergeContext extends MergeContext { private Subscriber subscriber; private SubscriberDiffTreeEventHandler handler; + private final IResourceMappingScopeManager manager; - protected SubscriberMergeContext(Subscriber subscriber, IResourceMappingScope scope) { - super(scope, getType(subscriber), new ResourceDiffTree()); + protected SubscriberMergeContext(Subscriber subscriber, IResourceMappingScopeManager manager) { + super(manager.getScope(), getType(subscriber), new ResourceDiffTree()); this.subscriber = subscriber; + this.manager = manager; } private static int getType(Subscriber subscriber) { @@ -53,17 +55,12 @@ public abstract class SubscriberMergeContext extends MergeContext { /** * Initialize the diff tree of this context. This method must * be called before the context is given to clients. - * @param monitor a progress monitor - * @param refresh indicate whether the subscriber should be refreshed * @throws CoreException */ - protected void initialize(IProgressMonitor monitor, boolean refresh) throws CoreException { - handler = new SubscriberDiffTreeEventHandler(subscriber, getScope(), (ResourceDiffTree)getDiffTree()); + protected void initialize() { + handler = new SubscriberDiffTreeEventHandler(subscriber, manager, (ResourceDiffTree)getDiffTree()); handler.setJobFamily(this); handler.start(); - if (refresh) { - refresh(getScope().getTraversals(), IResource.NONE, monitor); - } } /* (non-Javadoc) @@ -72,7 +69,6 @@ public abstract class SubscriberMergeContext extends MergeContext { public void refresh(ResourceTraversal[] traversals, int flags, IProgressMonitor monitor) throws CoreException { subscriber.refresh(traversals, monitor); - handler.waitUntilIdle(monitor); } /* (non-Javadoc) diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberResourceMappingContext.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberResourceMappingContext.java index 7116811ff..2a11803a6 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberResourceMappingContext.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberResourceMappingContext.java @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.team.core.subscribers; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberScopeManager.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberScopeManager.java new file mode 100644 index 000000000..3aa46e75d --- /dev/null +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/subscribers/SubscriberScopeManager.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 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.team.core.subscribers; + +import java.util.*; + +import org.eclipse.core.resources.*; +import org.eclipse.core.resources.mapping.*; +import org.eclipse.core.runtime.*; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; +import org.eclipse.team.core.mapping.IResourceMappingScopeParticipantFactory; +import org.eclipse.team.core.mapping.provider.IResourceMappingScopeParticipant; +import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; + +/** + * A {@link IResourceMappingScopeManager} that uses a {@link Subscriber} to provide + * a {@link RemoteResourceMappingContext} and to notify participants when the + * remote state of resources change. + * <p> + * <strong>EXPERIMENTAL</strong>. This class or interface has been added as + * part of a work in progress. There is a guarantee neither that this API will + * work nor that it will remain the same. Please do not use this API without + * consulting with the Platform/Team team. + * </p> + * @since 3.2 + */ +public class SubscriberScopeManager extends ResourceMappingScopeManager implements ISubscriberChangeListener { + + private final Subscriber subscriber; + private Map participants = new HashMap(); + + /** + * Create a manager for the given subscriber and input. + * @param inputMappings the input mappings + * @param subscriber the subscriber + * @param consultModels whether models should be consulted when calculating the scope + */ + public SubscriberScopeManager(ResourceMapping[] inputMappings, Subscriber subscriber, boolean consultModels) { + this(inputMappings, subscriber, SubscriberResourceMappingContext.createContext(subscriber), consultModels); + } + + /** + * Create a manager for the given subscriber and input. + * @param inputMappings the input mappings + * @param subscriber the subscriber + * @param context a remote resource mapping conext for the subscriber + * @param consultModels whether models should be consulted when calculating the scope + */ + public SubscriberScopeManager(ResourceMapping[] inputMappings, Subscriber subscriber, RemoteResourceMappingContext context, boolean consultModels) { + super(inputMappings, context, consultModels); + this.subscriber = subscriber; + } + + /** + * Return the subscriber for this manager. + * @return the subscriber for this manager + */ + protected Subscriber getSubscriber() { + return subscriber; + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.IResourceMappingScopeManager#dispose() + */ + public void dispose() { + for (Iterator iter = participants.values().iterator(); iter.hasNext();) { + IResourceMappingScopeParticipant p = (IResourceMappingScopeParticipant) iter.next(); + p.dispose(); + } + super.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager#initialize(org.eclipse.core.runtime.IProgressMonitor) + */ + public void initialize(IProgressMonitor monitor) throws CoreException { + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + SubscriberScopeManager.super.initialize(monitor); + hookupParticipants(); + getSubscriber().addListener(SubscriberScopeManager.this); + } + }, getSchedulingRule(), IResource.NONE, monitor); + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager#refresh(org.eclipse.core.resources.mapping.ResourceMapping[], org.eclipse.core.runtime.IProgressMonitor) + */ + public ResourceTraversal[] refresh(final ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException { + final List result = new ArrayList(1); + ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + result.add(SubscriberScopeManager.super.refresh(mappings, monitor)); + hookupParticipants(); + } + }, getSchedulingRule(), IResource.NONE, monitor); + if (result.isEmpty()) + return new ResourceTraversal[0]; + return (ResourceTraversal[])result.get(0); + } + + /* + * Hookup the participants for the participating models. + * This is done to ensure that future local and remote changes to + * resources will update the resources contained in the scope + * appropriately + */ + /* private */ void hookupParticipants() { + ModelProvider[] providers = getScope().getModelProviders(); + for (int i = 0; i < providers.length; i++) { + ModelProvider provider = providers[i]; + if (!participants.containsKey(provider)) { + IResourceMappingScopeParticipant p = createParticipant(provider); + if (p != null) { + participants.put(provider, p); + } + } + } + } + + /* + * Obtain a participant through the factory which is obtained using IAdaptable + */ + private IResourceMappingScopeParticipant createParticipant(ModelProvider provider) { + Object factoryObject = provider.getAdapter(IResourceMappingScopeParticipantFactory.class); + if (factoryObject instanceof IResourceMappingScopeParticipantFactory) { + IResourceMappingScopeParticipantFactory factory = (IResourceMappingScopeParticipantFactory) factoryObject; + return factory.createParticipant(provider, this); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.ISubscriberChangeListener#subscriberResourceChanged(org.eclipse.team.core.subscribers.ISubscriberChangeEvent[]) + */ + public void subscriberResourceChanged(ISubscriberChangeEvent[] deltas) { + List changedResources = new ArrayList(); + List changedProjects = new ArrayList(); + for (int i = 0; i < deltas.length; i++) { + ISubscriberChangeEvent event = deltas[i]; + if ((event.getFlags() & (ISubscriberChangeEvent.ROOT_ADDED | ISubscriberChangeEvent.ROOT_REMOVED)) != 0) { + changedProjects.add(event.getResource().getProject()); + } + if ((event.getFlags() & ISubscriberChangeEvent.SYNC_CHANGED) != 0) { + changedResources.add(event.getResource()); + } + } + fireChange((IResource[]) changedResources.toArray(new IResource[changedResources.size()]), (IProject[]) changedProjects.toArray(new IProject[changedProjects.size()])); + } + + private void fireChange(final IResource[] resources, final IProject[] projects) { + IResourceMappingScopeParticipant[] handlers = (IResourceMappingScopeParticipant[]) participants.values().toArray(new IResourceMappingScopeParticipant[participants.size()]); + for (int i = 0; i < handlers.length; i++) { + final IResourceMappingScopeParticipant participant = handlers[i]; + Platform.run(new ISafeRunnable() { + public void run() throws Exception { + participant.handleContextChange(SubscriberScopeManager.this, resources, projects); + } + public void handleException(Throwable exception) { + // Handled by platform + } + }); + } + } + +} diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/mapping/ResourceMappingScope.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/mapping/ResourceMappingScope.java index c20f21d85..7d4e46ee2 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/mapping/ResourceMappingScope.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/mapping/ResourceMappingScope.java @@ -17,7 +17,6 @@ import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.team.core.mapping.IResourceMappingScope; import org.eclipse.team.core.mapping.PropertyChangeEvent; -import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; /** * Concrete implementation of the {@link IResourceMappingScope} @@ -42,7 +41,6 @@ public class ResourceMappingScope extends AbstractResourceMappingScope { private final Map mappingsToTraversals = new HashMap(); private boolean hasAdditionalMappings; private boolean hasAdditionalResources; - private final ResourceMappingScopeManager manager; private final CompoundResourceTraversal compoundTraversal = new CompoundResourceTraversal(); public static ResourceTraversal[] combineTraversals(ResourceTraversal[] allTraversals) { @@ -76,8 +74,7 @@ public class ResourceMappingScope extends AbstractResourceMappingScope { return (ResourceTraversal[]) result.toArray(new ResourceTraversal[result.size()]); } - public ResourceMappingScope(ResourceMappingScopeManager manager, ResourceMapping[] selectedMappings) { - this.manager = manager; + public ResourceMappingScope(ResourceMapping[] selectedMappings) { inputMappings = selectedMappings; } @@ -105,6 +102,8 @@ public class ResourceMappingScope extends AbstractResourceMappingScope { * @see org.eclipse.team.ui.mapping.IResourceMappingOperationScope#getMappings() */ public ResourceMapping[] getMappings() { + if (mappingsToTraversals.isEmpty()) + return inputMappings; return (ResourceMapping[]) mappingsToTraversals.keySet().toArray(new ResourceMapping[mappingsToTraversals.size()]); } @@ -153,10 +152,6 @@ public class ResourceMappingScope extends AbstractResourceMappingScope { public boolean hasAdditonalResources() { return hasAdditionalResources; } - - public ResourceMappingScopeManager getManager() { - return manager; - } public void fireTraversalsChangedEvent(ResourceTraversal[] oldTraversals) { firePropertyChangedEvent(new PropertyChangeEvent(this, IResourceMappingScope.TRAVERSALS, oldTraversals, getTraversals())); diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberDiffTreeEventHandler.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberDiffTreeEventHandler.java index 983926c30..a8449e11c 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberDiffTreeEventHandler.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberDiffTreeEventHandler.java @@ -11,18 +11,16 @@ package org.eclipse.team.internal.core.subscribers; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.team.core.ITeamStatus; import org.eclipse.team.core.diff.IDiff; import org.eclipse.team.core.diff.IDiffVisitor; -import org.eclipse.team.core.mapping.IResourceDiffTree; -import org.eclipse.team.core.mapping.ISynchronizationScope; -import org.eclipse.team.core.mapping.provider.ResourceDiffTree; +import org.eclipse.team.core.mapping.*; +import org.eclipse.team.core.mapping.provider.*; import org.eclipse.team.core.subscribers.Subscriber; -import org.eclipse.team.internal.core.Policy; /** * A subscriber event handler whose output is a diff tree @@ -31,6 +29,7 @@ public class SubscriberDiffTreeEventHandler extends SubscriberEventHandler { private ResourceDiffTree tree; private SubscriberDiffCollector collector; + private IResourceMappingScopeManager manager; private Object family; /* @@ -85,12 +84,37 @@ public class SubscriberDiffTreeEventHandler extends SubscriberEventHandler { * @param scope the scope of the handler * @param tree the tree to be populated by this handler */ - public SubscriberDiffTreeEventHandler(Subscriber subscriber, ISynchronizationScope scope, ResourceDiffTree tree) { - super(subscriber, scope); + public SubscriberDiffTreeEventHandler(Subscriber subscriber, IResourceMappingScopeManager manager, ResourceDiffTree tree) { + super(subscriber, manager.getScope()); + this.manager = manager; this.tree = tree; this.collector = new SubscriberDiffCollector(subscriber); } + protected void reset(ResourceTraversal[] traversals, int type) { + if (type == SubscriberEvent.INITIALIZE && traversals.length == 0) { + // This means the scope has not been initialized + queueEvent(new RunnableEvent(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + prepareScope(monitor); + } + }, true), true); + } else { + super.reset(traversals, type); + } + } + + protected void prepareScope(IProgressMonitor monitor) { + try { + manager.initialize(monitor); + } catch (CoreException e) { + handleException(e); + } + ResourceTraversal[] traversals = manager.getScope().getTraversals(); + if (traversals.length > 0) + reset(traversals, SubscriberEvent.INITIALIZE); + } + /* (non-Javadoc) * @see org.eclipse.team.internal.core.subscribers.SubscriberEventHandler#handleChange(org.eclipse.core.resources.IResource) */ @@ -172,20 +196,6 @@ public class SubscriberDiffTreeEventHandler extends SubscriberEventHandler { return tree; } - public void waitUntilIdle(IProgressMonitor monitor) { - monitor.worked(1); - // wait for the event handler to process changes. - while(getEventHandlerJob().getState() != Job.NONE) { - monitor.worked(1); - try { - Thread.sleep(10); - } catch (InterruptedException e) { - } - Policy.checkCanceled(monitor); - } - monitor.worked(1); - } - /* (non-Javadoc) * @see org.eclipse.team.internal.core.subscribers.SubscriberEventHandler#getSubscriber() */ @@ -201,9 +211,17 @@ public class SubscriberDiffTreeEventHandler extends SubscriberEventHandler { super.shutdown(); } + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.BackgroundEventHandler#getJobFamiliy() + */ protected Object getJobFamiliy() { return family; } + + /** + * Set the family of this handler to the given object + * @param family the family of the handler's job + */ public void setJobFamily(Object family) { this.family = family; } diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberEventHandler.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberEventHandler.java index 4d6f73333..dc69b0e0b 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberEventHandler.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/SubscriberEventHandler.java @@ -130,7 +130,7 @@ public abstract class SubscriberEventHandler extends BackgroundEventHandler { * @param newTraversals the new traversals */ protected synchronized void reset(ResourceTraversal[] oldTraversals, ResourceTraversal[] newTraversals) { - reset(scope.getRoots(), SubscriberEvent.CHANGE); + reset(newTraversals, SubscriberEvent.CHANGE); } /** @@ -141,8 +141,8 @@ public abstract class SubscriberEventHandler extends BackgroundEventHandler { // Set the started flag to enable event queuing. // We are guaranteed to be the first since this method is synchronized. started = true; - IResource[] resources = scope.getRoots(); - reset(resources, SubscriberEvent.INITIALIZE); + ResourceTraversal[] traversals = scope.getTraversals(); + reset(traversals, SubscriberEvent.INITIALIZE); initializing = false; } @@ -302,10 +302,13 @@ public abstract class SubscriberEventHandler extends BackgroundEventHandler { * @param type can be Event.CHANGE to recalculate all states or Event.INITIALIZE to perform the * optimized recalculation if supported by the subscriber. */ - protected void reset(IResource[] roots, int type) { - IResource[] resources = roots; - for (int i = 0; i < resources.length; i++) { - queueEvent(new SubscriberEvent(resources[i], type, IResource.DEPTH_INFINITE), false); + protected void reset(ResourceTraversal[] traversals, int type) { + for (int i = 0; i < traversals.length; i++) { + ResourceTraversal traversal = traversals[i]; + IResource[] resources = traversal.getResources(); + for (int j = 0; j < resources.length; j++) { + queueEvent(new SubscriberEvent(resources[j], type, traversal.getDepth()), false); + } } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/OutgoingChangesDialog.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/OutgoingChangesDialog.java index 4e34262e6..cc77d73ae 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/OutgoingChangesDialog.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/OutgoingChangesDialog.java @@ -12,17 +12,15 @@ package org.eclipse.team.internal.ccvs.ui.actions; import java.lang.reflect.InvocationTargetException; -import org.eclipse.core.runtime.*; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; -import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; import org.eclipse.team.core.mapping.ISynchronizationContext; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.mappings.WorkspaceSubscriberContext; @@ -31,20 +29,19 @@ import org.eclipse.team.internal.ui.dialogs.DetailsDialog; import org.eclipse.team.ui.operations.ModelSynchronizeParticipant; import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; import org.eclipse.team.ui.synchronize.ParticipantPagePane; -import org.eclipse.ui.PlatformUI; public class OutgoingChangesDialog extends DetailsDialog { private final String message; private ParticipantPagePane pane; - private final IResourceMappingScope scope; private ModelSynchronizeParticipant participant; private final String title; private final String detailsMessage; + private final IResourceMappingScopeManager manager; - public OutgoingChangesDialog(Shell parentShell, IResourceMappingScope scope, String title, String message, String detailsMessage) { + public OutgoingChangesDialog(Shell parentShell, IResourceMappingScopeManager manager, String title, String message, String detailsMessage) { super(parentShell, title); - this.scope = scope; + this.manager = manager; this.title = title; this.message = message; this.detailsMessage = detailsMessage; @@ -109,23 +106,15 @@ public class OutgoingChangesDialog extends DetailsDialog { } private ModelSynchronizeParticipant createParticipant() throws InvocationTargetException, InterruptedException { - ISynchronizationContext context = createSynchronizationContext(scope); - ModelSynchronizeParticipant participant = ModelSynchronizeParticipant.createParticipant(context, title); + ISynchronizationContext context = createSynchronizationContext(manager); + ModelSynchronizeParticipant participant = ModelSynchronizeParticipant.createParticipant(manager, context, title); participant.setMergingEnabled(false); return participant; } - private ISynchronizationContext createSynchronizationContext(final IResourceMappingScope scope) throws InvocationTargetException, InterruptedException { + private ISynchronizationContext createSynchronizationContext(final IResourceMappingScopeManager manager) throws InvocationTargetException, InterruptedException { final ISynchronizationContext[] context = new ISynchronizationContext[] { null }; - PlatformUI.getWorkbench().getProgressService().run(true, true, new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - context[0] = WorkspaceSubscriberContext.createContext(scope, false, ISynchronizationContext.THREE_WAY, monitor); - } catch (CoreException e) { - throw new InvocationTargetException(e); - } - } - }); + context[0] = WorkspaceSubscriberContext.createContext(manager, ISynchronizationContext.THREE_WAY); return context[0]; } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithRemoteAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithRemoteAction.java index 3c953f0d7..9a88deec2 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithRemoteAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithRemoteAction.java @@ -13,18 +13,37 @@ package org.eclipse.team.internal.ccvs.ui.actions; import java.lang.reflect.InvocationTargetException; import org.eclipse.jface.action.IAction; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.team.internal.ccvs.core.*; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Display; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.ICVSResource; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.ui.CVSUIMessages; -import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; -import org.eclipse.team.internal.ccvs.ui.mappings.ModelReplaceOperation; +import org.eclipse.team.internal.ccvs.ui.operations.ReplaceOperation; public class ReplaceWithRemoteAction extends WorkspaceTraversalAction { public void execute(IAction action) throws InvocationTargetException, InterruptedException { - IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore(); - new ModelReplaceOperation(getTargetPart(), getSelectedResourceMappings(CVSProviderPlugin.getTypeId()), getResourceMappingContext()).run(); + + final ReplaceOperation replaceOperation = new ReplaceOperation(getTargetPart(), getCVSResourceMappings(), null); + if (hasOutgoingChanges(replaceOperation)) { + final boolean[] keepGoing = new boolean[] { true }; + Display.getDefault().syncExec(new Runnable() { + public void run() { + OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), replaceOperation.getScopeManager(), + CVSUIMessages.ReplaceWithTagAction_2, + CVSUIMessages.ReplaceWithTagAction_0, + CVSUIMessages.ReplaceWithTagAction_1); + int result = dialog.open(); + keepGoing[0] = result == Window.OK; + } + }); + if (!keepGoing[0]) + return; + } + replaceOperation.run(); + // TODO: Involve models in the replace + //new ModelReplaceOperation(getTargetPart(), getSelectedResourceMappings(CVSProviderPlugin.getTypeId()), getResourceMappingContext()).run(); } /** diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithTagAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithTagAction.java index 24682b1b1..db9933ca2 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithTagAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/ReplaceWithTagAction.java @@ -42,7 +42,7 @@ public class ReplaceWithTagAction extends WorkspaceTraversalAction { final boolean[] keepGoing = new boolean[] { true }; Display.getDefault().syncExec(new Runnable() { public void run() { - OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), replaceOperation.getScope(), + OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), replaceOperation.getScopeManager(), CVSUIMessages.ReplaceWithTagAction_2, CVSUIMessages.ReplaceWithTagAction_0, CVSUIMessages.ReplaceWithTagAction_1); @@ -101,7 +101,7 @@ public class ReplaceWithTagAction extends WorkspaceTraversalAction { final boolean[] keepGoing = new boolean[] { true }; Display.getDefault().syncExec(new Runnable() { public void run() { - OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), tagOperation.getScope(), + OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), tagOperation.getScopeManager(), CVSUIMessages.TagLocalAction_2, CVSUIMessages.TagLocalAction_0, CVSUIMessages.TagLocalAction_1); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SyncAction.java index 1596ceeee..0da85305a 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SyncAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SyncAction.java @@ -47,7 +47,7 @@ public class SyncAction extends WorkspaceTraversalAction { showSingleFileComparison(getShell(), CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), resources[0], getTargetPage()); }else if (isShowModelSync()) { try { - new ModelUpdateOperation(getTargetPart(), getCVSResourceMappings(), getResourceMappingContext()) { + new ModelUpdateOperation(getTargetPart(), getCVSResourceMappings()) { protected boolean isAttemptHeadlessMerge() { return false; } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/TagLocalAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/TagLocalAction.java index bd5746115..c38ca2d8b 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/TagLocalAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/TagLocalAction.java @@ -35,7 +35,7 @@ public class TagLocalAction extends TagAction { final boolean[] keepGoing = new boolean[] { true }; Display.getDefault().syncExec(new Runnable() { public void run() { - OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), tagOperation.getScope(), + OutgoingChangesDialog dialog = new OutgoingChangesDialog(getShell(), tagOperation.getScopeManager(), CVSUIMessages.TagLocalAction_2, CVSUIMessages.TagLocalAction_0, CVSUIMessages.TagLocalAction_1); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/UpdateSilentAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/UpdateSilentAction.java index c7a477777..58a27b78b 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/UpdateSilentAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/UpdateSilentAction.java @@ -48,7 +48,7 @@ public class UpdateSilentAction extends WorkspaceTraversalAction { if (CVSUIPlugin.getPlugin().getPreferenceStore().getString(ICVSUIConstants.PREF_UPDATE_HANDLING).equals(ICVSUIConstants.PREF_UPDATE_HANDLING_TRADITIONAL)) { new UpdateOperation(getTargetPart(), getCVSResourceMappings(), Command.NO_LOCAL_OPTIONS, null /* no tag */).run(); } else { - new ModelUpdateOperation(getTargetPart(), getSelectedResourceMappings(CVSProviderPlugin.getTypeId()), getResourceMappingContext()).run(); + new ModelUpdateOperation(getTargetPart(), getSelectedResourceMappings(CVSProviderPlugin.getTypeId())).run(); } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/AbstractModelMergeOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/AbstractModelMergeOperation.java index 839adfac7..1fbc4fa0c 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/AbstractModelMergeOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/AbstractModelMergeOperation.java @@ -10,27 +10,21 @@ *******************************************************************************/ package org.eclipse.team.internal.ccvs.ui.mappings; -import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants; -import org.eclipse.team.ui.operations.ModelMergeOperation; +import org.eclipse.team.ui.operations.ModelParticipantMergeOperation; +import org.eclipse.team.ui.operations.ModelSynchronizeParticipant; import org.eclipse.ui.IWorkbenchPart; -public abstract class AbstractModelMergeOperation extends ModelMergeOperation { - - private ResourceMappingContext context; +public abstract class AbstractModelMergeOperation extends ModelParticipantMergeOperation { - public AbstractModelMergeOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings, ResourceMappingContext resourceMappingContext) { - super(part, selectedMappings); - this.context = resourceMappingContext; - } - - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getResourceMappingContext() - */ - protected ResourceMappingContext getResourceMappingContext() {; - return context; + private boolean ownsManager = false; + + public AbstractModelMergeOperation(IWorkbenchPart part, IResourceMappingScopeManager manager, boolean ownsManager) { + super(part, manager); + this.ownsManager = ownsManager; } /* (non-Javadoc) @@ -46,5 +40,20 @@ public abstract class AbstractModelMergeOperation extends ModelMergeOperation { protected boolean isPreviewInDialog() { return CVSUIPlugin.getPlugin().getPreferenceStore().getString(ICVSUIConstants.PREF_UPDATE_PREVIEW).equals(ICVSUIConstants.PREF_UPDATE_PREVIEW_IN_DIALOG); } + + protected void endOperation(IProgressMonitor monitor) { + if (ownsManager) { + IResourceMappingScopeManager manager = getScopeManager(); + manager.dispose(); + } + super.endOperation(monitor); + } + + protected ModelSynchronizeParticipant createParticipant() { + ModelSynchronizeParticipant participant = super.createParticipant(); + // Transfer ownership of the manager to the participant + ownsManager = false; + return participant; + } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/CVSSubscriberMergeContext.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/CVSSubscriberMergeContext.java index 6bdf963e5..65e04afdf 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/CVSSubscriberMergeContext.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/CVSSubscriberMergeContext.java @@ -15,7 +15,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.team.core.diff.IDiff; -import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; import org.eclipse.team.core.subscribers.Subscriber; import org.eclipse.team.core.subscribers.SubscriberMergeContext; import org.eclipse.team.internal.ccvs.core.CVSException; @@ -24,8 +24,8 @@ import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer; public abstract class CVSSubscriberMergeContext extends SubscriberMergeContext { - protected CVSSubscriberMergeContext(Subscriber subscriber, IResourceMappingScope scope) { - super(subscriber, scope); + protected CVSSubscriberMergeContext(Subscriber subscriber, IResourceMappingScopeManager manager) { + super(subscriber, manager); } /* (non-Javadoc) diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/MergeSubscriberContext.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/MergeSubscriberContext.java index d2cd52e9a..82cbf93d1 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/MergeSubscriberContext.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/MergeSubscriberContext.java @@ -24,14 +24,14 @@ import org.eclipse.team.internal.ccvs.core.CVSMergeSubscriber; public class MergeSubscriberContext extends CVSSubscriberMergeContext { - public static IMergeContext createContext(IResourceMappingScope scope, Subscriber subscriber, IProgressMonitor monitor) throws CoreException { - MergeSubscriberContext mergeContext = new MergeSubscriberContext(subscriber, scope); - mergeContext.initialize(monitor, true); + public static IMergeContext createContext(IResourceMappingScopeManager manager, Subscriber subscriber) { + MergeSubscriberContext mergeContext = new MergeSubscriberContext(subscriber, manager); + mergeContext.initialize(); return mergeContext; } - public MergeSubscriberContext(Subscriber subscriber, IResourceMappingScope scope) { - super(subscriber, scope); + public MergeSubscriberContext(Subscriber subscriber, IResourceMappingScopeManager manager) { + super(subscriber, manager); } /* (non-Javadoc) diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelMergeOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelMergeOperation.java index 67386692d..8f473c674 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelMergeOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelMergeOperation.java @@ -11,30 +11,39 @@ package org.eclipse.team.internal.ccvs.ui.mappings; import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.team.core.mapping.IMergeContext; +import org.eclipse.team.core.mapping.ISynchronizationContext; import org.eclipse.team.core.subscribers.Subscriber; -import org.eclipse.team.core.subscribers.SubscriberResourceMappingContext; +import org.eclipse.team.core.subscribers.SubscriberScopeManager; +import org.eclipse.team.internal.ccvs.core.CVSMergeSubscriber; import org.eclipse.team.internal.ccvs.ui.CVSUIMessages; -import org.eclipse.team.internal.ccvs.ui.Policy; import org.eclipse.ui.IWorkbenchPart; public class ModelMergeOperation extends AbstractModelMergeOperation { private final Subscriber subscriber; - - public ModelMergeOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings, Subscriber subscriber) { - super(part, selectedMappings, SubscriberResourceMappingContext.createContext(subscriber)); + + /** + * Create a merge operation for the given subscriber. The merge operation will cancel the subscriber + * when it is no longer needed. + * @param part the part + * @param mappings the mappings + * @param subscriber the subscriber + */ + public ModelMergeOperation(IWorkbenchPart part, ResourceMapping[] mappings, final CVSMergeSubscriber subscriber) { + super(part, new SubscriberScopeManager(mappings, subscriber, true){ + public void dispose() { + subscriber.cancel(); + super.dispose(); + } + }, true); this.subscriber = subscriber; } - protected IMergeContext buildMergeContext(IProgressMonitor monitor) - throws CoreException { - monitor.beginTask(null, 100); - IMergeContext context = MergeSubscriberContext.createContext(getScope(), subscriber, Policy.subMonitorFor(monitor, 50)); - monitor.done(); - return context; + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ModelParticipantMergeOperation#createMergeContext() + */ + protected ISynchronizationContext createMergeContext() { + return MergeSubscriberContext.createContext(getScopeManager(), subscriber); } /* (non-Javadoc) diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelReplaceOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelReplaceOperation.java index f2c5e7ed2..f73dc04de 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelReplaceOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelReplaceOperation.java @@ -11,7 +11,6 @@ package org.eclipse.team.internal.ccvs.ui.mappings; import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceMappingContext; import org.eclipse.core.runtime.*; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; @@ -27,8 +26,8 @@ public class ModelReplaceOperation extends ModelUpdateOperation { boolean hasPrompted = false; - public ModelReplaceOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings, ResourceMappingContext context) { - super(part, selectedMappings, context); + public ModelReplaceOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings, boolean consultModels) { + super(part, selectedMappings, consultModels); } /* (non-Javadoc) @@ -64,7 +63,6 @@ public class ModelReplaceOperation extends ModelUpdateOperation { * @see org.eclipse.team.ui.operations.ResourceMappingMergeOperation#performMerge(org.eclipse.core.runtime.IProgressMonitor) */ protected IStatus performMerge(IProgressMonitor monitor) throws CoreException { - // TODO: cancel must free context to avoid leaking if (!hasLocalChanges() || promptForOverwrite()) { return super.performMerge(monitor); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelUpdateOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelUpdateOperation.java index 8a558614f..f552b6b02 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelUpdateOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/ModelUpdateOperation.java @@ -11,21 +11,23 @@ package org.eclipse.team.internal.ccvs.ui.mappings; import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceMappingContext; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.team.core.mapping.IMergeContext; import org.eclipse.team.core.mapping.ISynchronizationContext; +import org.eclipse.team.core.subscribers.SubscriberScopeManager; +import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.ui.*; import org.eclipse.team.ui.operations.ModelSynchronizeParticipant; import org.eclipse.ui.IWorkbenchPart; public class ModelUpdateOperation extends AbstractModelMergeOperation { - public ModelUpdateOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings, ResourceMappingContext context) { - super(part, selectedMappings, context); + public ModelUpdateOperation(IWorkbenchPart targetPart, ResourceMapping[] selectedResourceMappings, boolean consultModels) { + super(targetPart, new SubscriberScopeManager(selectedResourceMappings, CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), consultModels), true); } + public ModelUpdateOperation(IWorkbenchPart targetPart, ResourceMapping[] resourceMappings) { + this(targetPart, resourceMappings, true); + } + /* (non-Javadoc) * @see org.eclipse.team.ui.TeamOperation#getJobName() */ @@ -43,16 +45,6 @@ public class ModelUpdateOperation extends AbstractModelMergeOperation { protected boolean isAttemptHeadlessMerge() { return CVSUIPlugin.getPlugin().getPreferenceStore().getString(ICVSUIConstants.PREF_UPDATE_HANDLING).equals(ICVSUIConstants.PREF_UPDATE_HANDLING_PERFORM); } - - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingMergeOperation#buildMergeContext(org.eclipse.core.runtime.IProgressMonitor) - */ - protected IMergeContext buildMergeContext(IProgressMonitor monitor) throws CoreException { - monitor.beginTask(null, 100); - IMergeContext context = WorkspaceSubscriberContext.createContext(getScope(), true /* refresh */, getMergeType(), Policy.subMonitorFor(monitor, 50)); - monitor.done(); - return context; - } /** * Return the merge type associated with this operation. @@ -66,6 +58,13 @@ public class ModelUpdateOperation extends AbstractModelMergeOperation { * @see org.eclipse.team.ui.operations.ResourceMappingMergeOperation#createParticipant() */ protected ModelSynchronizeParticipant createParticipant() { - return new WorkspaceModelParticipant(getContext(), getJobName()); + return new WorkspaceModelParticipant(getScopeManager(), createMergeContext(), getJobName()); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ModelParticipantMergeOperation#createMergeContext() + */ + protected ISynchronizationContext createMergeContext() { + return WorkspaceSubscriberContext.createContext(getScopeManager(), getMergeType()); } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceModelParticipant.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceModelParticipant.java index 776171e39..87d77e4d4 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceModelParticipant.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceModelParticipant.java @@ -10,12 +10,11 @@ *******************************************************************************/ package org.eclipse.team.internal.ccvs.ui.mappings; +import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.*; import org.eclipse.team.core.mapping.*; -import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; -import org.eclipse.team.core.subscribers.SubscriberResourceMappingContext; +import org.eclipse.team.core.subscribers.SubscriberScopeManager; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.ui.Policy; import org.eclipse.team.internal.ccvs.ui.actions.*; @@ -28,6 +27,14 @@ import org.eclipse.team.ui.operations.MergeActionGroup; import org.eclipse.team.ui.operations.ModelSynchronizeParticipant; import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; +/** + * @author MValenta + * + */ +/** + * @author MValenta + * + */ public class WorkspaceModelParticipant extends ModelSynchronizeParticipant { @@ -137,8 +144,8 @@ public class WorkspaceModelParticipant extends public WorkspaceModelParticipant() { } - public WorkspaceModelParticipant(ISynchronizationContext context, String name) { - super(context); + public WorkspaceModelParticipant(IResourceMappingScopeManager manager, ISynchronizationContext context, String name) { + super(manager, context); try { setInitializationData(TeamUI.getSynchronizeManager().getParticipantDescriptor("org.eclipse.team.cvs.ui.workspace-participant")); //$NON-NLS-1$ } catch (CoreException e) { @@ -165,15 +172,15 @@ public class WorkspaceModelParticipant extends /* (non-Javadoc) * @see org.eclipse.team.ui.operations.ModelSynchronizeParticipant#restoreContext(org.eclipse.team.core.mapping.IResourceMappingScope, org.eclipse.core.runtime.IProgressMonitor) */ - protected IMergeContext restoreContext(IResourceMappingScope scope, IProgressMonitor monitor) throws CoreException { - return WorkspaceSubscriberContext.createContext(scope, false /* refresh */, ISynchronizationContext.THREE_WAY, monitor); + protected IMergeContext restoreContext(IResourceMappingScopeManager manager) { + return WorkspaceSubscriberContext.createContext(manager, ISynchronizationContext.THREE_WAY); } /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ModelSynchronizeParticipant#createScopeGenerator() + * @see org.eclipse.team.ui.operations.ModelSynchronizeParticipant#createScopeManager(org.eclipse.core.resources.mapping.ResourceMapping[]) */ - protected ResourceMappingScopeManager createScopeManager() { - return new ResourceMappingScopeManager(new SubscriberResourceMappingContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), true), true); + protected IResourceMappingScopeManager createScopeManager(ResourceMapping[] mappings) { + return new SubscriberScopeManager(mappings, CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(), true); } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java index 506dd6e9e..394768e1b 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java @@ -38,15 +38,15 @@ public class WorkspaceSubscriberContext extends CVSSubscriberMergeContext { private final int type; - public static IMergeContext createContext(IResourceMappingScope scope, boolean refresh, int type, IProgressMonitor monitor) throws CoreException { + public static IMergeContext createContext(IResourceMappingScopeManager manager, int type) { Subscriber subscriber = CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber(); - WorkspaceSubscriberContext mergeContext = new WorkspaceSubscriberContext(subscriber, scope, type); - mergeContext.initialize(monitor, refresh); + WorkspaceSubscriberContext mergeContext = new WorkspaceSubscriberContext(subscriber, manager, type); + mergeContext.initialize(); return mergeContext; } - protected WorkspaceSubscriberContext(Subscriber subscriber, IResourceMappingScope scope, int type) { - super(subscriber, scope); + protected WorkspaceSubscriberContext(Subscriber subscriber, IResourceMappingScopeManager manager, int type) { + super(subscriber, manager); this.type = type; } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java index f87da3d7d..804d950e9 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.team.internal.ccvs.ui.operations; -import java.lang.reflect.InvocationTargetException; import java.util.*; import org.eclipse.core.resources.IProject; @@ -22,6 +21,8 @@ import org.eclipse.jface.action.IAction; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; +import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; import org.eclipse.team.internal.ccvs.core.*; import org.eclipse.team.internal.ccvs.core.client.Command; import org.eclipse.team.internal.ccvs.core.client.Session; @@ -29,7 +30,6 @@ import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.Policy; -import org.eclipse.team.ui.operations.ModelOperation; import org.eclipse.ui.IWorkbenchPart; /** @@ -44,7 +44,7 @@ public abstract class RepositoryProviderOperation extends CVSOperation { */ public static boolean consultModelsWhenBuildingScope = true; - private IResourceMappingScope scope; + private IResourceMappingScopeManager manager; private final ResourceMapping[] selectedMappings; /** @@ -203,41 +203,24 @@ public abstract class RepositoryProviderOperation extends CVSOperation { } catch (CoreException e) { throw CVSException.wrapException(e); } finally { + if (manager != null) { + manager.dispose(); + manager = null; + } monitor.done(); } } public IResourceMappingScope buildScope(IProgressMonitor monitor) throws InterruptedException, CVSException { - if (scope == null) { - ModelOperation op = new ModelOperation(getPart(), selectedMappings) { - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#execute(org.eclipse.core.runtime.IProgressMonitor) - */ - protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - // No need to do anything. We just wanted to build the scope - } - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#consultModelsWhenGeneratingScope() - */ - protected boolean consultModelsWhenGeneratingScope() { - if (!consultModelsWhenBuildingScope) - return false; - return RepositoryProviderOperation.this.consultModelsForMappings(); - } - - protected ResourceMappingContext getResourceMappingContext() { - return RepositoryProviderOperation.this.getResourceMappingContext(); - } - }; - // Run the operation to build the scope + if (manager == null) { + manager = new ResourceMappingScopeManager(selectedMappings, getResourceMappingContext(), consultModelsWhenBuildingScope && consultModelsForMappings()); try { - op.run(monitor); - } catch (InvocationTargetException e) { + manager.initialize(monitor); + } catch (CoreException e) { throw CVSException.wrapException(e); } - scope = op.getScope(); } - return scope; + return manager.getScope(); } private void execute(Map providerTraversal, IProgressMonitor monitor) throws CVSException, InterruptedException { @@ -317,11 +300,11 @@ public abstract class RepositoryProviderOperation extends CVSOperation { */ private Map getProviderTraversalMapping(IProgressMonitor monitor) throws CoreException { Map result = new HashMap(); - ResourceMapping[] mappings = scope.getMappings(); + ResourceMapping[] mappings = getScope().getMappings(); for (int j = 0; j < mappings.length; j++) { ResourceMapping mapping = mappings[j]; IProject[] projects = mapping.getProjects(); - ResourceTraversal[] traversals = scope.getTraversals(mapping); + ResourceTraversal[] traversals = getScope().getTraversals(mapping); for (int k = 0; k < projects.length; k++) { IProject project = projects[k]; RepositoryProvider provider = RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()); @@ -473,7 +456,7 @@ public abstract class RepositoryProviderOperation extends CVSOperation { * @throws CoreException */ public ResourceTraversal[] getTraversals() { - return scope.getTraversals(); + return getScope().getTraversals(); } public boolean consultModelsForMappings() { @@ -485,6 +468,10 @@ public abstract class RepositoryProviderOperation extends CVSOperation { } public IResourceMappingScope getScope() { - return scope; + return manager.getScope(); + } + + public IResourceMappingScopeManager getScopeManager() { + return manager; } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CommitWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CommitWizard.java index 8e17514c5..4d04e85a5 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CommitWizard.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CommitWizard.java @@ -17,9 +17,7 @@ import java.util.*; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceMappingContext; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.jface.dialogs.MessageDialog; @@ -29,6 +27,8 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.team.core.IFileContentManager; import org.eclipse.team.core.Team; import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; +import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; import org.eclipse.team.core.subscribers.SubscriberResourceMappingContext; import org.eclipse.team.core.synchronize.*; import org.eclipse.team.internal.ccvs.core.*; @@ -37,7 +37,6 @@ import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.ui.*; import org.eclipse.team.internal.ccvs.ui.operations.*; import org.eclipse.team.internal.core.subscribers.SubscriberSyncInfoCollector; -import org.eclipse.team.ui.operations.ModelOperation; import org.eclipse.team.ui.synchronize.ResourceScope; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; @@ -333,26 +332,18 @@ public class CommitWizard extends ResizableWizard { } public static IResourceMappingScope buildScope(IWorkbenchPart part, ResourceMapping[] mappings, IProgressMonitor monitor) throws InterruptedException, CVSException { - ModelOperation op = new ModelOperation(part, mappings) { - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#execute(org.eclipse.core.runtime.IProgressMonitor) - */ - protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - // No need to do anything. We just wanted to build the scope - } - - protected ResourceMappingContext getResourceMappingContext() { - // TODO: Could use a context built using the source sync-context - return SubscriberResourceMappingContext.createContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber()); - } - }; - // Run the operation to build the scope + IResourceMappingScopeManager manager = new ResourceMappingScopeManager(mappings, + SubscriberResourceMappingContext.createContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber()), + true); try { - op.run(monitor); - } catch (InvocationTargetException e) { + manager.initialize(monitor); + return manager.getScope(); + } catch (CoreException e) { throw CVSException.wrapException(e); + } finally { + if (manager != null) + manager.dispose(); } - return op.getScope(); } private IWorkbenchPart getPart() { diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/CommonViewerAdvisor.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/CommonViewerAdvisor.java index 7ed90c9e3..68990d583 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/CommonViewerAdvisor.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/CommonViewerAdvisor.java @@ -114,7 +114,7 @@ public class CommonViewerAdvisor extends AbstractTreeViewerAdvisor implements IN * @return a newly created common viewer */ private static CommonViewer createViewer(Composite parent, ISynchronizePageConfiguration configuration, IEmptyTreeListener listener) { - CommonViewer v = new NavigableCommonViewer(configuration.getViewerId(), parent, SWT.NONE, listener); + CommonViewer v = new NavigableCommonViewer(configuration.getViewerId(), parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, listener); v.getNavigatorContentService().bindExtensions(TeamContentProviderManager.getInstance().getContentProviderIds(), true); v.getNavigatorContentService().activateExtensions(TeamContentProviderManager.getInstance().getContentProviderIds(), true); configuration.getSite().setSelectionProvider(v); @@ -204,19 +204,6 @@ public class CommonViewerAdvisor extends AbstractTreeViewerAdvisor implements IN private ModelSynchronizeParticipant getParticipant() { return (ModelSynchronizeParticipant)getConfiguration().getParticipant(); } - - /** - * Set the given property for all active extensions. - * @param property the property - * @param value the value - */ - public void setExtentionProperty(String property, int value) { - properties.put(property, new Integer(value)); - for (Iterator iter = extensions.iterator(); iter.hasNext();) { - INavigatorContentExtension extension = (INavigatorContentExtension) iter.next(); - extension.getStateModel().setIntProperty(property, value); - } - } /* (non-Javadoc) * @see org.eclipse.team.internal.ui.synchronize.StructuredViewerAdvisor#getContextMenuId(org.eclipse.jface.viewers.StructuredViewer) diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/MergeIncomingChangesAction.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/MergeIncomingChangesAction.java index ecf3f681c..72147bef9 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/MergeIncomingChangesAction.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/MergeIncomingChangesAction.java @@ -18,6 +18,7 @@ import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.team.core.diff.*; import org.eclipse.team.core.mapping.IMergeContext; +import org.eclipse.team.core.mapping.ISynchronizationContext; import org.eclipse.team.internal.ui.Utils; import org.eclipse.team.ui.mapping.ISaveableCompareModel; import org.eclipse.team.ui.mapping.SynchronizationOperation; @@ -53,18 +54,21 @@ public class MergeIncomingChangesAction extends ModelProviderAction { new SynchronizationOperation(getConfiguration(), getContext().getScope().getMappings()) { public void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - new ModelMergeOperation(getPart(), context) { - protected IMergeContext buildMergeContext(IProgressMonitor monitor) throws CoreException { - return context; - } + new ModelMergeOperation(getPart(), ((ModelSynchronizeParticipant)getConfiguration().getParticipant()).getScopeManager()) { public boolean isPreviewRequested() { return false; } - protected void showPreview(IProgressMonitor monitor) { - // Do nothing since this action was launched from a preview + protected void initializeContext(IProgressMonitor monitor) throws CoreException { + // Context is already initialized + } + protected ISynchronizationContext getContext() { + return context; } }.run(monitor); } + protected boolean canRunAsJob() { + return true; + } }.run(); } catch (InvocationTargetException e) { Utils.handle(e); diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelParticipantPageDialog.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelParticipantPageDialog.java new file mode 100644 index 000000000..5bfca0cca --- /dev/null +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelParticipantPageDialog.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 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.team.internal.ui.mapping; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.widgets.*; +import org.eclipse.team.core.mapping.IMergeContext; +import org.eclipse.team.core.mapping.ISynchronizationContext; +import org.eclipse.team.internal.ui.TeamUIMessages; +import org.eclipse.team.ui.SaveablePartAdapter; +import org.eclipse.team.ui.operations.ModelSynchronizeParticipant; +import org.eclipse.team.ui.synchronize.*; + +public final class ModelParticipantPageDialog extends ParticipantPageDialog { + + /* + * Ids for custom buttons when previewing a merge/replace + */ + private static final int DONE_ID = IDialogConstants.CLIENT_ID + 1; + private static final int REPLACE_ID = IDialogConstants.CLIENT_ID + 2; + + private final ModelSynchronizeParticipant participant; + private Button doneButton; + private Button replaceButton; + + public ModelParticipantPageDialog(Shell shell, ModelSynchronizeParticipant participant, CompareConfiguration cc, ISynchronizePageConfiguration pc) { + super(shell, createInput(shell, participant, cc, pc), participant); + this.participant = participant; + } + + private static SaveablePartAdapter createInput(Shell shell, ModelSynchronizeParticipant participant, CompareConfiguration cc, ISynchronizePageConfiguration pc) { + ParticipantPageSaveablePart input = new ParticipantPageSaveablePart(shell, cc, pc, participant); + return input; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.SaveablePartDialog#close() + */ + public boolean close() { + boolean close = super.close(); + if (super.close()) { + getInput().dispose(); + } + return close; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.synchronize.ParticipantPageDialog#isOfferToRememberParticipant() + */ + protected boolean isOfferToRememberParticipant() { + boolean isReplace = ((IMergeContext)participant.getContext()).getMergeType() == ISynchronizationContext.TWO_WAY; + if (isReplace) + return false; + return super.isOfferToRememberParticipant(); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.SaveablePartDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + protected void createButtonsForButtonBar(Composite parent) { + boolean isReplace = ((IMergeContext)participant.getContext()).getMergeType() == ISynchronizationContext.TWO_WAY; + isReplace = false; // TODO: Disbled for now + if (isReplace) { + replaceButton = createButton(parent, REPLACE_ID, "&Replace", true); + replaceButton.setEnabled(true); + } + doneButton = createButton(parent, DONE_ID, TeamUIMessages.ResourceMappingMergeOperation_2, !isReplace); + doneButton.setEnabled(true); + // Don't call super because we don't want the OK button to appear + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.synchronize.ParticipantPageDialog#buttonPressed(int) + */ + protected void buttonPressed(int buttonId) { + if (buttonId == DONE_ID) { + super.buttonPressed(IDialogConstants.OK_ID); + } else if (buttonId == REPLACE_ID) { + // TODO: Disabled for now +// try { +// // Do this inline so we don't have to manage disposing of the context +// PlatformUI.getWorkbench().getProgressService().run(true, true, new IRunnableWithProgress() { +// public void run(IProgressMonitor monitor) throws InvocationTargetException, +// InterruptedException { +// try { +// +// ModelParticipantPageDialog.this.operation.performMerge(monitor); +// } catch (CoreException e) { +// throw new InvocationTargetException(e); +// } +// } +// }); +// } catch (InvocationTargetException e) { +// Throwable t = e.getTargetException(); +// IStatus status; +// if (t instanceof CoreException) { +// CoreException ce = (CoreException) t; +// status = ce.getStatus(); +// } else { +// status = new Status(IStatus.ERROR, TeamUIPlugin.ID, 0, TeamUIMessages.internal, t); +// TeamUIPlugin.log(status); +// } +// ErrorDialog.openError(getShell(), null, null, status); +// return; +// } catch (InterruptedException e) { +// // Operation was cancelled. Leave the dialog open +// return; +// } + super.buttonPressed(IDialogConstants.OK_ID); + } else { + super.buttonPressed(buttonId); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelSynchronizePage.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelSynchronizePage.java index 1c6c3abb3..3740b9957 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelSynchronizePage.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ModelSynchronizePage.java @@ -61,11 +61,7 @@ public class ModelSynchronizePage extends AbstractSynchronizePage { * @see org.eclipse.team.internal.ui.synchronize.AbstractSynchronizePage#updateMode(int) */ protected void updateMode(int mode) { - if (isThreeWay()) { - CommonViewerAdvisor advisor = (CommonViewerAdvisor)getConfiguration().getProperty(SynchronizePageConfiguration.P_ADVISOR); - if (advisor != null) - advisor.setExtentionProperty(ISynchronizePageConfiguration.P_MODE, mode); - } + // Nothing to do } /** diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ResourceTeamAwareContentProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ResourceTeamAwareContentProvider.java index 5d70fda9a..283bf98c2 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ResourceTeamAwareContentProvider.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/mapping/ResourceTeamAwareContentProvider.java @@ -101,13 +101,12 @@ public class ResourceTeamAwareContentProvider extends SynchronizationContentProv * @see org.eclipse.team.ui.mapping.SynchronizationContentProvider#getChildrenInContext(org.eclipse.team.core.mapping.ISynchronizationContext, java.lang.Object, java.lang.Object[]) */ protected Object[] getChildrenInContext(ISynchronizationContext context, Object parent, Object[] children) { - Object[] objects = super.getChildrenInContext(context, parent, children); if (parent instanceof IResource) { IResource resource = (IResource) parent; Set result = new HashSet(); - for (int i = 0; i < objects.length; i++) { - Object object = objects[i]; + for (int i = 0; i < children.length; i++) { + Object object = children[i]; result.add(object); } IPath[] childPaths = context.getDiffTree().getChildren(resource.getFullPath()); @@ -129,9 +128,9 @@ public class ResourceTeamAwareContentProvider extends SynchronizationContentProv result.add(child); } } - return result.toArray(new Object[result.size()]); + return super.getChildrenInContext(context, parent, result.toArray(new Object[result.size()])); } - return children; + return super.getChildrenInContext(context, parent, children); } protected ResourceTraversal[] getTraversals(ISynchronizationContext context, Object object) { diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/SaveablePartDialog.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/SaveablePartDialog.java index 1b62ac634..ba184c932 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/SaveablePartDialog.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/SaveablePartDialog.java @@ -88,4 +88,12 @@ public class SaveablePartDialog extends ResizableDialog { }); } } + + /** + * Return the input to the dialog. + * @return the input to the dialog + */ + protected ISaveableWorkbenchPart getInput() { + return input; + } } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationContentProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationContentProvider.java index 700ff9deb..af60a0311 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationContentProvider.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationContentProvider.java @@ -126,7 +126,7 @@ public abstract class SynchronizationContentProvider implements ICommonContentPr return new Object[0]; } if (parent == getModelProvider()) { - if (!isInitialized(context)) { + if (context != null && !isInitialized(context)) { return new Object[0]; } parent = getModelRoot(); @@ -266,6 +266,9 @@ public abstract class SynchronizationContentProvider implements ICommonContentPr stateModel.removePropertyChangeListener(this); if (context != null) context.getDiffTree().removeDiffChangeListener(this); + ISynchronizePageConfiguration configuration = getConfiguration(); + if (configuration != null) + configuration.removePropertyChangeListener(this); } /* (non-Javadoc) @@ -282,6 +285,9 @@ public abstract class SynchronizationContentProvider implements ICommonContentPr public void init(IExtensionStateModel aStateModel, IMemento aMemento) { stateModel = aStateModel; stateModel.addPropertyChangeListener(this); + ISynchronizePageConfiguration configuration = getConfiguration(); + if (configuration != null) + configuration.addPropertyChangeListener(this); scope = (IResourceMappingScope)aStateModel.getProperty(ISynchronizationConstants.P_RESOURCE_MAPPING_SCOPE); context = (ISynchronizationContext)aStateModel.getProperty(ISynchronizationConstants.P_SYNCHRONIZATION_CONTEXT); ITreeContentProvider provider = getDelegateContentProvider(); @@ -317,7 +323,7 @@ public abstract class SynchronizationContentProvider implements ICommonContentPr * included in the contents */ protected boolean includeDirection(int direction) { - int mode = stateModel.getIntProperty(ISynchronizePageConfiguration.P_MODE); + int mode = getConfiguration().getMode(); switch (mode) { case ISynchronizePageConfiguration.BOTH_MODE: return true; diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationLabelProvider.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationLabelProvider.java index b60b46400..3cbfad8d3 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationLabelProvider.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationLabelProvider.java @@ -150,7 +150,8 @@ public abstract class SynchronizationLabelProvider extends AbstractSynchronizeLa String text = super.getText(element); if (contentProvider instanceof SynchronizationContentProvider) { SynchronizationContentProvider scp = (SynchronizationContentProvider) contentProvider; - if (!scp.isInitialized(getContext())) { + ISynchronizationContext context = getContext(); + if (context != null && !scp.isInitialized(context)) { return NLS.bind("{0} Initializing", text); } } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationOperation.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationOperation.java index 20c7aa354..3931cbde3 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationOperation.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/mapping/SynchronizationOperation.java @@ -105,12 +105,6 @@ public abstract class SynchronizationOperation extends TeamOperation { public boolean shouldRun() { return super.shouldRun(); } - - public boolean belongsTo(Object family) { - if (family == getContext()) - return true; - return super.belongsTo(family); - } /** * Return the buffer that this operation will write its results diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/MergeActionGroup.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/MergeActionGroup.java index 38d82adf6..6dca754a8 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/MergeActionGroup.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/MergeActionGroup.java @@ -191,7 +191,8 @@ public class MergeActionGroup extends SynchronizePageActionGroup { } public void dispose() { - modelPicker.dispose(); + if (modelPicker != null) + modelPicker.dispose(); super.dispose(); } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelMergeOperation.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelMergeOperation.java index d10a99a62..244944efd 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelMergeOperation.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelMergeOperation.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2000, 2005 IBM Corporation and others. + * Copyright (c) 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 + * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.team.ui.operations; @@ -14,85 +14,21 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -import org.eclipse.compare.CompareConfiguration; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.ModelProvider; -import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.runtime.*; -import org.eclipse.jface.dialogs.*; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.swt.widgets.*; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.diff.*; import org.eclipse.team.core.mapping.*; import org.eclipse.team.internal.ui.*; -import org.eclipse.team.internal.ui.mapping.DefaultResourceMappingMerger; -import org.eclipse.team.ui.TeamUI; -import org.eclipse.team.ui.mapping.ICompareAdapter; -import org.eclipse.team.ui.synchronize.*; import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.PlatformUI; /** - * The steps of an optimistic merge operation are: - * <ol> - * <li>Obtain the selection to be operated on. - * <li>Determine the projection of the selection onto resources - * using resource mappings and traversals. - * <ul> - * <li>this will require traversals using both the ancestor and remote - * for three-way merges. - * <li>for model providers with registered merger, mapping set need - * not be expanded (this is tricky if one of the model providers doesn't - * have a merge but all others do). - * <li>if the model does not have a custom merger, ensure that additional - * mappings are included (i.e. for many model elements to one resource case) - * </ul> - * <li>Create a MergeContext for the merge - * <ul> - * <li>Determine the synchronization state of all resources - * covered by the input. - * <li>Pre-fetch the required contents. - * </ul> - * <li>Obtain and invoke the merger for each provider - * <ul> - * <li>This will auto-merge as much as possible - * <li>If everything was merged, cleanup and stop - * <li>Otherwise, a set of un-merged resource mappings is returned - * </ul> - * <li>Delegate manual merge to the model provider - * <ul> - * <li>This hands off the context to the manual merge - * <li>Once completed, the manual merge must clean up - * </ul> - * </ol> - * - * <p> - * Handle multiple model providers where one extends all others by using - * the top-most model provider. The assumption is that the model provider - * will delegate to lower level model providers when appropriate. - * <p> - * Special case to support sub-file merges. - * <ul> - * <li>Restrict when sub-file merging is supported - * <ul> - * <li>Only one provider involved (i.e. consulting participants results - * in participants that are from the model provider or below). - * <li>The provider has a custom auto and manual merger. - * </ul> - * <li>Prompt to warn when sub-file merging is not possible. - * <li>Need to display the additional elements that will be affected. - * This could be done in a diff tree or some other view. It needs to - * consider incoming changes including additions. - * </ul> - * <p> - * Special case to handle conflicting model providers. - * <ul> - * <li>Prompt user to indicate the conflict - * <li>Allow user to exclude one of the models? - * <li>Allow use to choose order of evaluation? - * <li>Support tabbed sync view - * </ul> + * A model operation that executes a merge according to the merge lifecycle + * associated with an {@link IMergeContext} and {@link IResourceMappingMerger} + * instances obtained from the model providers involved. * * <p> * <strong>EXPERIMENTAL</strong>. This class or interface has been added as @@ -104,22 +40,6 @@ import org.eclipse.ui.PlatformUI; * @since 3.2 */ public abstract class ModelMergeOperation extends ModelOperation { - - /** - * Status code that can be returned from the {@link #performMerge(IProgressMonitor)} - * method to indicate that a subclass would liek to force a preview of the merge. - * The message of such a status should be ignored. - */ - public static final int REQUEST_PREVIEW = 1024; - - /* - * Ids for custom buttons when previewing a merge/replace - */ - private static final int DONE_ID = IDialogConstants.CLIENT_ID + 1; - private static final int REPLACE_ID = IDialogConstants.CLIENT_ID + 2; - - private IMergeContext context; - private boolean ownsContext = true; /** * Validate the merge context with the model providers that have mappings in @@ -161,10 +81,12 @@ public abstract class ModelMergeOperation extends ModelOperation { */ private static IStatus validateMerge(ModelProvider provider, IMergeContext context, IProgressMonitor monitor) { IResourceMappingMerger merger = getMerger(provider); + if (merger == null) + return Status.OK_STATUS; return merger.validateMerge(context, monitor); } - /** + /* * Return the auto-merger associated with the given model provider using the * adaptable mechanism. If the model provider does not have a merger * associated with it, a default merger that performs the merge at the file @@ -175,251 +97,109 @@ public abstract class ModelMergeOperation extends ModelOperation { * <code>null</code>) * @return a merger */ - public static IResourceMappingMerger getMerger(ModelProvider provider) { + private static IResourceMappingMerger getMerger(ModelProvider provider) { Assert.isNotNull(provider); - IResourceMappingMerger merger = (IResourceMappingMerger)Utils.getAdapter(provider, IResourceMappingMerger.class); - if (merger != null) - return merger; - return new DefaultResourceMappingMerger(provider); + return (IResourceMappingMerger)Utils.getAdapter(provider, IResourceMappingMerger.class); } /** - * Create a merge operation - * @param part the workbench part from which the merge was launched or <code>null</code> - * @param selectedMappings the selected mappings - */ - protected ModelMergeOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings) { - super(part, selectedMappings); - } - - /** - * Create the model merge operation for the given context. - * The merge will be performed for the given context but - * the context will not be disposed by this operation - * (i.e. it is considered to be owned by the client). - * @param part the workbench part from which the merge was launched or <code>null</code> - * @param context the merge context to be merged + * Create a model merge operation. + * @param part the workbench part from which the operation was requested or <code>null</code> + * @param manager the scope manager */ - public ModelMergeOperation(IWorkbenchPart part, IMergeContext context) { - super(part, context.getScope()); - this.context = context; - ownsContext = false; + protected ModelMergeOperation(IWorkbenchPart part, IResourceMappingScopeManager manager) { + super(part, manager); } - - /* (non-Javadoc) - * @see org.eclipse.team.ui.mapping.ResourceMappingOperation#execute(org.eclipse.core.runtime.IProgressMonitor) - */ - protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + + protected void execute(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { try { monitor.beginTask(null, 100); - if (context == null) - context = buildMergeContext(Policy.subMonitorFor(monitor, 75)); + initializeContext(Policy.subMonitorFor(monitor, 75)); if (!hasChangesOfInterest()) { - promptForNoChanges(); - return; - } - if (!isPreviewRequested()) { - IStatus status = validateMerge(context, Policy.subMonitorFor(monitor, 5)); - if (status.isOK()) { - status = performMerge(Policy.subMonitorFor(monitor, 20)); - if (status.isOK()) { - // The merge was sucessful so we can just return - return; - } else { - if (status.getCode() == IMergeStatus.CONFLICTS) { - promptForMergeFailure(status); - } - } - } else { - // TODO prompt with validation message + handleNoChanges(); + } else if (isPreviewRequested()) { + handlePreviewRequest(); + } else { + IStatus status = ModelMergeOperation.validateMerge(getMergeContext(), Policy.subMonitorFor(monitor, 5)); + if (!status.isOK()) { + handleValidationFailure(status); + } + status = performMerge(Policy.subMonitorFor(monitor, 20)); + if (!status.isOK()) { + handleMergeFailure(status); } } - // Either auto-merging was not attemped or it was not 100% sucessful - showPreview(Policy.subMonitorFor(monitor, 25)); } catch (CoreException e) { throw new InvocationTargetException(e); } finally { - if (ownsContext && context != null) - context.dispose(); monitor.done(); } } - - /** - * Prompt for a failure to auto-merge - * @param status the status returned from the merger that reported the conflict - */ - protected void promptForMergeFailure(IStatus status) { - Display.getDefault().syncExec(new Runnable() { - public void run() { - MessageDialog.openInformation(getShell(), TeamUIMessages.MergeIncomingChangesAction_0, TeamUIMessages.MergeIncomingChangesAction_1); - }; - }); - } /** - * Return whether the context of this operation has changes that are - * of interest to the operation. Sublcasses may override. - * @return whether the context of this operation has changes that are - * of interest to the operation + * A preview of the merge has been requested. By default, this method does + * nothing. Subclasses that wish to support previewing must override this + * method to preview the merge and the {@link #getPreviewRequestMessage()} + * to have the option presented to the user if the scope changes. */ - protected boolean hasChangesOfInterest() { - return !context.getDiffTree().isEmpty() && hasIncomingChanges(context.getDiffTree()); + protected void handlePreviewRequest() { + // Do nothing } - private boolean hasIncomingChanges(IDiffTree tree) { - return hasChangesMatching(tree, new FastDiffFilter() { - public boolean select(IDiff node) { - if (node instanceof IThreeWayDiff) { - IThreeWayDiff twd = (IThreeWayDiff) node; - int direction = twd.getDirection(); - if (direction == IThreeWayDiff.INCOMING || direction == IThreeWayDiff.CONFLICTING) { - return true; - } - } else { - // Return true for any two-way change - return true; - } - return false; - } - }); - } + /** + * Initialize the merge context for this merge operation. + * After this method is invoked, the {@link #getContext()} + * method must return an instance of {@link IMergeContext} + * that is fully initialized. + * @param monitor a progress monitor + * @throws CoreException + */ + protected abstract void initializeContext(IProgressMonitor monitor) throws CoreException; /** - * Method invoked when the context contains no changes so that the user - * can be informed. + * Method invoked when the context contains changes that failed validation + * by at least one {@link IResourceMappingMerger}. + * By default, the user is prompted to inform them that unmergeable changes were found + * and the {@link #handlePreviewRequest()} method is invoked. + * Subclasses may override. + * @param status the status returned from the mergers that reported the validation failures */ - protected void promptForNoChanges() { + protected void handleValidationFailure(IStatus status) { Display.getDefault().syncExec(new Runnable() { public void run() { - MessageDialog.openInformation(getShell(), TeamUIMessages.ResourceMappingMergeOperation_0, TeamUIMessages.ResourceMappingMergeOperation_1); + MessageDialog.openInformation(getShell(), "Validation Failure", "Better message to come."); }; }); + handlePreviewRequest(); } /** - * Preview the merge so the user can perform the merge manually. - * @param monitor a progress monitor + * Method invoked when the context contains unmergable changes. + * By default, the user is promted to inform them that unmergeable changes were found. + * Subclasses may override. + * @param status the status returned from the merger that reported the conflict */ - protected void showPreview(IProgressMonitor monitor) { - calculateStates(context, Policy.subMonitorFor(monitor, 5)); - // TODO Ownership of the context is being transferred to the participant - final ModelSynchronizeParticipant participant = createParticipant(); - ownsContext = false; - Display.getDefault().asyncExec(new Runnable() { + protected void handleMergeFailure(IStatus status) { + Display.getDefault().syncExec(new Runnable() { public void run() { - if (isPreviewInDialog()) { - CompareConfiguration cc = new CompareConfiguration(); - ISynchronizePageConfiguration pageConfiguration = participant.createPageConfiguration(); - // Restrict preview page to only support incomign and conflict modes - if (pageConfiguration.getComparisonType() == ISynchronizePageConfiguration.THREE_WAY) { - pageConfiguration.setSupportedModes(ISynchronizePageConfiguration.INCOMING_MODE | ISynchronizePageConfiguration.CONFLICTING_MODE); - pageConfiguration.setMode(ISynchronizePageConfiguration.INCOMING_MODE); - } - ParticipantPageSaveablePart input = new ParticipantPageSaveablePart(getShell(), cc, pageConfiguration, participant); - ParticipantPageDialog dialog = new ParticipantPageDialog(getShell(), input, participant) { - private Button doneButton; - private Button replaceButton; - - protected boolean isOfferToRememberParticipant() { - boolean isReplace = context.getMergeType() == ISynchronizationContext.TWO_WAY; - if (isReplace) - return false; - return super.isOfferToRememberParticipant(); - } - - protected void createButtonsForButtonBar(Composite parent) { - boolean isReplace = context.getMergeType() == ISynchronizationContext.TWO_WAY; - if (isReplace) { - replaceButton = createButton(parent, REPLACE_ID, "&Replace", true); - replaceButton.setEnabled(true); - } - doneButton = createButton(parent, DONE_ID, TeamUIMessages.ResourceMappingMergeOperation_2, !isReplace); - doneButton.setEnabled(true); - // Don't call super because we don't want the OK button to appear - } - protected void buttonPressed(int buttonId) { - if (buttonId == DONE_ID) { - super.buttonPressed(IDialogConstants.OK_ID); - } else if (buttonId == REPLACE_ID) { - try { - // Do this inline so we don't have to manage disposing of the context - PlatformUI.getWorkbench().getProgressService().run(true, true, new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InvocationTargetException, - InterruptedException { - try { - performMerge(monitor); - } catch (CoreException e) { - throw new InvocationTargetException(e); - } - } - - }); - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - IStatus status; - if (t instanceof CoreException) { - CoreException ce = (CoreException) t; - status = ce.getStatus(); - } else { - status = new Status(IStatus.ERROR, TeamUIPlugin.ID, 0, TeamUIMessages.internal, t); - TeamUIPlugin.log(status); - } - ErrorDialog.openError(getShell(), null, null, status); - return; - } catch (InterruptedException e) { - // Operation was cancelled. Leave the dialog open - return; - } - super.buttonPressed(IDialogConstants.OK_ID); - } else { - super.buttonPressed(buttonId); - } - } - }; - int result = dialog.open(); - input.dispose(); - if (TeamUI.getSynchronizeManager().get(participant.getId(), participant.getSecondaryId()) == null) - participant.dispose(); - } else { - ISynchronizeManager mgr = TeamUI.getSynchronizeManager(); - ISynchronizeView view = mgr.showSynchronizeViewInActivePage(); - mgr.addSynchronizeParticipants(new ISynchronizeParticipant[] {participant}); - view.display(participant); - } - } + MessageDialog.openInformation(getShell(), TeamUIMessages.MergeIncomingChangesAction_0, TeamUIMessages.MergeIncomingChangesAction_1); + }; }); + handlePreviewRequest(); } /** - * Return whether previews should occur in a dialog or in the synchronize view. - * @return whether previews should occur in a dialog or in the synchronize view + * Method invoked when the context contains no changes. + * By default, the user is promted to inform them that no changes were found. + * Subclasses may override. */ - protected boolean isPreviewInDialog() { - return true; - } - - private void calculateStates(ISynchronizationContext context, IProgressMonitor monitor) { - monitor.beginTask(null, IProgressMonitor.UNKNOWN); - ModelProvider[] providers = getScope().getModelProviders(); - for (int i = 0; i < providers.length; i++) { - ModelProvider provider = providers[i]; - calculateStates(context, provider, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN)); - } - monitor.done(); - } - - private void calculateStates(ISynchronizationContext context, ModelProvider provider, IProgressMonitor monitor) { - Object o = provider.getAdapter(ICompareAdapter.class); - if (o instanceof ICompareAdapter) { - ICompareAdapter calculator = (ICompareAdapter) o; - try { - calculator.prepareContext(context, monitor); - } catch (CoreException e) { - TeamUIPlugin.log(e); - } - } - monitor.done(); + protected void handleNoChanges() { + Display.getDefault().syncExec(new Runnable() { + public void run() { + MessageDialog.openInformation(getShell(), TeamUIMessages.ResourceMappingMergeOperation_0, TeamUIMessages.ResourceMappingMergeOperation_1); + }; + }); } /** @@ -497,43 +277,32 @@ public abstract class ModelMergeOperation extends ModelOperation { if (sc instanceof IMergeContext) { IMergeContext context = (IMergeContext) sc; IResourceMappingMerger merger = getMerger(provider); - IStatus status = merger.merge(context, monitor); - if (status.isOK() || status.getCode() == IMergeStatus.CONFLICTS) { - return status; + if (merger != null) { + IStatus status = merger.merge(context, monitor); + if (status.isOK() || status.getCode() == IMergeStatus.CONFLICTS) { + return status; + } + throw new TeamException(status); } - throw new TeamException(status); + return Status.OK_STATUS; } return noMergeContextAvailable(); } - + private IStatus noMergeContextAvailable() { throw new IllegalStateException("Merges should only be attemped for operations that have a merge context"); } /** - * Build and initialize a merge context for the input of this operation. - * @param monitor a progress monitor - * @return a merge context for merging the mappings of the input - */ - protected abstract IMergeContext buildMergeContext(IProgressMonitor monitor) throws CoreException; - - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getContext() - */ - protected ISynchronizationContext getContext() { - return context; - } - - /* (non-Javadoc) - * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getPreviewRequestMessage() + * Return whether the context of this operation has changes that are + * of interest to the operation. Sublcasses may override. + * @return whether the context of this operation has changes that are + * of interest to the operation */ - protected String getPreviewRequestMessage() { - if (!isPreviewRequested()) { - return TeamUIMessages.ResourceMappingMergeOperation_4; - } - return super.getPreviewRequestMessage(); + protected boolean hasChangesOfInterest() { + return !getContext().getDiffTree().isEmpty() && hasIncomingChanges(getContext().getDiffTree()); } - + /** * Return whether the given diff tree contains any deltas that match the given filter. * @param tree the diff tree @@ -559,19 +328,26 @@ public abstract class ModelMergeOperation extends ModelOperation { } return false; } - - /** - * Create the synchronize pariticipant to be used by this operation - * to preview changes. By default, a {@link ModelSynchronizeParticipant} - * is created using he context ({@link #getContext()}) and job name ({@link #getJobName()}) - * of this operation. Subclasses may override this method. - * <p> - * Once created, it is the responsibility of the participant to dispose of the - * synchronization context when it is no longer needed. - * @return a newly created synchronize pariticipant to be used by this operation - */ - protected ModelSynchronizeParticipant createParticipant() { - return ModelSynchronizeParticipant.createParticipant(getContext(), getJobName()); + + private boolean hasIncomingChanges(IDiffTree tree) { + return hasChangesMatching(tree, new FastDiffFilter() { + public boolean select(IDiff node) { + if (node instanceof IThreeWayDiff) { + IThreeWayDiff twd = (IThreeWayDiff) node; + int direction = twd.getDirection(); + if (direction == IThreeWayDiff.INCOMING || direction == IThreeWayDiff.CONFLICTING) { + return true; + } + } else { + // Return true for any two-way change + return true; + } + return false; + } + }); + } + + private IMergeContext getMergeContext() { + return (IMergeContext)getContext(); } - } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelOperation.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelOperation.java index 668d4f38b..8ef1959c7 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelOperation.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelOperation.java @@ -18,9 +18,7 @@ import org.eclipse.core.resources.mapping.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; -import org.eclipse.team.core.mapping.IResourceMappingScope; -import org.eclipse.team.core.mapping.ISynchronizationContext; -import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; +import org.eclipse.team.core.mapping.*; import org.eclipse.team.internal.core.mapping.ResourceMappingScope; import org.eclipse.team.internal.ui.TeamUIMessages; import org.eclipse.team.internal.ui.dialogs.AdditionalMappingsDialog; @@ -45,9 +43,8 @@ import org.eclipse.ui.IWorkbenchPart; */ public abstract class ModelOperation extends TeamOperation { - private final ResourceMapping[] selectedMappings; - private IResourceMappingScope scope; private boolean previewRequested; + private IResourceMappingScopeManager manager; /** * Return the list of provides sorted by their extends relationship. @@ -87,37 +84,38 @@ public abstract class ModelOperation extends TeamOperation { } /** - * Create a model operation for the given selected mappings. - * The scope will be generated when the operation is executed. - * @param part the workbench part from which the merge was launched or <code>null</code> - * @param selectedMappings the selected mappings - */ - protected ModelOperation(IWorkbenchPart part, ResourceMapping[] selectedMappings) { - super(part); - this.selectedMappings = selectedMappings; - } - - /** * Create a model operation that operates on the given scope. * @param part the workbench part from which the merge was launched or <code>null</code> - * @param scope the scope of this operation + * @param manager the scope manager for this operation */ - protected ModelOperation(IWorkbenchPart part, IResourceMappingScope scope) { - this(part, scope.getInputMappings()); - this.scope = scope; + protected ModelOperation(IWorkbenchPart part, IResourceMappingScopeManager manager) { + super(part); + this.manager = manager; } /** * Run the operation. This method first ensures that the scope is built - * by calling {@link #prepareScope(IProgressMonitor)} and then invokes the + * by calling {@link #initializeScope(IProgressMonitor)} and then invokes the * {@link #execute(IProgressMonitor)} method. * @param monitor a progress monitor * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor) */ - public void run(IProgressMonitor monitor) throws InvocationTargetException, + public final void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - prepareScope(monitor); - execute(monitor); + try { + beginOperation(monitor); + execute(monitor); + } finally { + endOperation(monitor); + } + } + + protected void beginOperation(IProgressMonitor monitor) throws InvocationTargetException { + initializeScope(monitor); + } + + protected void endOperation(IProgressMonitor monitor) { + // Do nothing by deafult } /** @@ -139,35 +137,34 @@ public abstract class ModelOperation extends TeamOperation { * the {@link #getScopeManager()} to return a custom scope manager. * @param monitor a progress monitor */ - protected final void prepareScope(IProgressMonitor monitor) throws InvocationTargetException { - if (scope == null) { - try { - ResourceMappingScopeManager manager = getScopeManager(); - scope = manager.prepareScope(selectedMappings, isUseLocalContext(), monitor); + protected final void initializeScope(IProgressMonitor monitor) throws InvocationTargetException { + try { + if (!manager.isInitialized()) { + manager.initialize(monitor); promptIfInputChange(monitor); - } catch (CoreException e) { - throw new InvocationTargetException(e); } + } catch (CoreException e) { + throw new InvocationTargetException(e); } } /** * Prompt the user by calling {@link #promptForInputChange(String, IProgressMonitor)} * if the scope of the operation was expanded (as described in - * {@link #prepareScope(IProgressMonitor)}). + * {@link #initializeScope(IProgressMonitor)}). * @param monitor a progress monitor */ protected void promptIfInputChange(IProgressMonitor monitor) { IResourceMappingScope inputScope = getScope().asInputScope(); - if (scope.hasAdditionalMappings()) { + if (getScope().hasAdditionalMappings()) { boolean prompt = false; // There are additional mappings so we may need to prompt ModelProvider[] inputModelProviders = inputScope.getModelProviders(); - if (hasAdditionalMappingsFromIndependantModel(inputModelProviders, scope.getModelProviders())) { + if (hasAdditionalMappingsFromIndependantModel(inputModelProviders, getScope().getModelProviders())) { // Prompt if the is a new model provider in the scope that is independant // of any of the input mappings prompt = true; - } else if (scope.hasAdditonalResources()) { + } else if (getScope().hasAdditonalResources()) { // We definitely need to prompt to indicate that additional resources prompt = true; } else if (inputModelProviders.length == 1) { @@ -175,7 +172,7 @@ public abstract class ModelOperation extends TeamOperation { // We need to prompt if the additional mappings are from the same model as // the input or if they are from a model that has no relationship to the input model String modelProviderId = inputModelProviders[0].getDescriptor().getId(); - ResourceMapping[] mappings = scope.getMappings(); + ResourceMapping[] mappings = getScope().getMappings(); for (int i = 0; i < mappings.length; i++) { ResourceMapping mapping = mappings[i]; if (inputScope.getTraversals(mapping) == null) { @@ -197,7 +194,7 @@ public abstract class ModelOperation extends TeamOperation { ModelProvider provider = inputModelProviders[i]; String id = provider.getDescriptor().getId(); ResourceMapping[] inputMappings = inputScope.getMappings(id); - ResourceMapping[] scopeMappings = scope.getMappings(id); + ResourceMapping[] scopeMappings = getScope().getMappings(id); if (inputMappings.length != scopeMappings.length) { // There are more mappings for this provider. // We need to see if any of the new ones overlap the old ones. @@ -209,7 +206,7 @@ public abstract class ModelOperation extends TeamOperation { // We need to prompt if the traversal for this mapping overlaps with // the input mappings for the model provider // TODO could check for project overlap first - ResourceTraversal[] scopeTraversals = scope.getTraversals(mapping); + ResourceTraversal[] scopeTraversals = getScope().getTraversals(mapping); ResourceTraversal[] inputModelTraversals = getTraversals(inputScope, inputMappings); if (overlaps(scopeTraversals, inputModelTraversals)) { prompt = true; @@ -228,17 +225,6 @@ public abstract class ModelOperation extends TeamOperation { } /** - * Indicate whether the local context should be used when preparing the scope. - * Subclasses may wish to do this when initial creation of the - * scope cannot be log running but they will perform future refreshes on the - * scope that can be. - * @return whether the local context should be used when preparing the scope - */ - protected boolean isUseLocalContext() { - return false; - } - - /** * Return a string to be used in the preview request on the scope prompt * or <code>null</code> if a preview of the operation results is not possible. * By default, <code>null</code> is returned but subclasses may override. @@ -364,23 +350,6 @@ public abstract class ModelOperation extends TeamOperation { } /** - * Return the scope manager used to build the scope of this - * operation from the input mappings. By default, this method passes - * the resource mapping context and the result of {@link #consultModelsWhenGeneratingScope()} - * to the scope builder constructor. - * <p> - * This method can be overridden by subclasses. - * - * @return the scope builder used to build the scope of this - * operation from the input mappings. - */ - protected ResourceMappingScopeManager getScopeManager() { - if (scope != null) - return ((ResourceMappingScope)scope).getManager(); - return new ResourceMappingScopeManager(getResourceMappingContext(), consultModelsWhenGeneratingScope()); - } - - /** * Prompt the user to inform them that additional resource mappings * have been included in the operations. * @param requestPreviewMessage message to be displayed for the option to force a preview @@ -439,7 +408,7 @@ public abstract class ModelOperation extends TeamOperation { * @return the scope of this operation */ public IResourceMappingScope getScope() { - return scope; + return manager.getScope(); } /** @@ -451,32 +420,13 @@ public abstract class ModelOperation extends TeamOperation { public boolean isPreviewRequested() { return previewRequested; } - - /** - * Return whether the model providers should be consulted - * when generating the scope. When <code>true</code>, the scope - * generation process will consult any model providers to determine - * if additional mappings, and hence additional resources, need to - * be included in the operation. If <code>false</code>, the models - * are not consulted and only the input mappings are included in the - * scope. a value of <code>true</code> is returned by default. - * @return whether the model providers should be consulted - * when generating the scope - */ - protected boolean consultModelsWhenGeneratingScope() { - return true; - } - + /** - * Return the resource mapping context used during the - * scope generation and refresh process to determine - * what resources are to be included in the resulting - * synchronization context. - * Subclasses may override. - * @return the resource mapping context + * Return the scope manager for this operation. + * @return the scope manager for this operation. */ - protected ResourceMappingContext getResourceMappingContext() { - return ResourceMappingContext.LOCAL_CONTEXT; + public IResourceMappingScopeManager getScopeManager() { + return manager; } } diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelParticipantMergeOperation.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelParticipantMergeOperation.java new file mode 100644 index 000000000..86aa17c72 --- /dev/null +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelParticipantMergeOperation.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.team.ui.operations; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.*; +import org.eclipse.team.core.mapping.*; +import org.eclipse.team.internal.ui.TeamUIMessages; +import org.eclipse.team.internal.ui.mapping.ModelParticipantPageDialog; +import org.eclipse.team.ui.TeamUI; +import org.eclipse.team.ui.synchronize.*; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.progress.WorkbenchJob; + +/** + * The steps of an optimistic merge operation are: + * <ol> + * <li>Obtain the selection to be operated on. + * <li>Determine the projection of the selection onto resources + * using resource mappings and traversals. + * <ul> + * <li>this will require traversals using both the ancestor and remote + * for three-way merges. + * <li>for model providers with registered merger, mapping set need + * not be expanded (this is tricky if one of the model providers doesn't + * have a merge but all others do). + * <li>if the model does not have a custom merger, ensure that additional + * mappings are included (i.e. for many model elements to one resource case) + * </ul> + * <li>Create a MergeContext for the merge + * <ul> + * <li>Determine the synchronization state of all resources + * covered by the input. + * <li>Pre-fetch the required contents. + * </ul> + * <li>Obtain and invoke the merger for each provider + * <ul> + * <li>This will auto-merge as much as possible + * <li>If everything was merged, cleanup and stop + * <li>Otherwise, a set of un-merged resource mappings is returned + * </ul> + * <li>Delegate manual merge to the model provider + * <ul> + * <li>This hands off the context to the manual merge + * <li>Once completed, the manual merge must clean up + * </ul> + * </ol> + * + * <p> + * Handle multiple model providers where one extends all others by using + * the top-most model provider. The assumption is that the model provider + * will delegate to lower level model providers when appropriate. + * <p> + * Special case to support sub-file merges. + * <ul> + * <li>Restrict when sub-file merging is supported + * <ul> + * <li>Only one provider involved (i.e. consulting participants results + * in participants that are from the model provider or below). + * <li>The provider has a custom auto and manual merger. + * </ul> + * <li>Prompt to warn when sub-file merging is not possible. + * <li>Need to display the additional elements that will be affected. + * This could be done in a diff tree or some other view. It needs to + * consider incoming changes including additions. + * </ul> + * <p> + * Special case to handle conflicting model providers. + * <ul> + * <li>Prompt user to indicate the conflict + * <li>Allow user to exclude one of the models? + * <li>Allow use to choose order of evaluation? + * <li>Support tabbed sync view + * </ul> + * + * <p> + * <strong>EXPERIMENTAL</strong>. This class or interface has been added as + * part of a work in progress. There is a guarantee neither that this API will + * work nor that it will remain the same. Please do not use this API without + * consulting with the Platform/Team team. + * </p> + * + * @since 3.2 + */ +public abstract class ModelParticipantMergeOperation extends ModelMergeOperation { + + /** + * Status code that can be returned from the {@link #performMerge(IProgressMonitor)} + * method to indicate that a subclass would like to force a preview of the merge. + * The message of such a status should be ignored. + */ + public static final int REQUEST_PREVIEW = 1024; + + private ModelSynchronizeParticipant participant; + private boolean ownsParticipant = true; + + /** + * Create a merge participant operation for the scope of the given manager. + * @param part the workbench part from which the merge was launched or <code>null</code> + * @param manager the scope manager + */ + protected ModelParticipantMergeOperation(IWorkbenchPart part, IResourceMappingScopeManager manager) { + super(part, manager); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ModelMergeOperation#initializeContext(org.eclipse.core.runtime.IProgressMonitor) + */ + protected void initializeContext(IProgressMonitor monitor) throws CoreException { + if (participant == null) { + participant = createParticipant(); + participant.getContext().refresh(getScope().getTraversals(), + RemoteResourceMappingContext.FILE_CONTENTS_REQUIRED, monitor); + try { + Platform.getJobManager().join(participant.getContext(), monitor); + } catch (InterruptedException e) { + throw new OperationCanceledException(); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ModelMergeOperation#execute(org.eclipse.core.runtime.IProgressMonitor) + */ + protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + super.execute(monitor); + } finally { + if (ownsParticipant && participant != null) + participant.dispose(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ModelMergeOperation#handlePreviewRequest() + */ + protected void handlePreviewRequest() { + Job job = new WorkbenchJob(getJobName()) { + public IStatus runInUIThread(IProgressMonitor monitor) { + if (isPreviewInDialog()) { + CompareConfiguration cc = new CompareConfiguration(); + ISynchronizePageConfiguration pageConfiguration = participant.createPageConfiguration(); + // Restrict preview page to only support incomign and conflict modes + if (pageConfiguration.getComparisonType() == ISynchronizePageConfiguration.THREE_WAY) { + pageConfiguration.setSupportedModes(ISynchronizePageConfiguration.INCOMING_MODE | ISynchronizePageConfiguration.CONFLICTING_MODE); + pageConfiguration.setMode(ISynchronizePageConfiguration.INCOMING_MODE); + } + ParticipantPageDialog dialog = new ModelParticipantPageDialog(getShell(), participant, cc, pageConfiguration); + dialog.open(); + } else { + ISynchronizeManager mgr = TeamUI.getSynchronizeManager(); + ISynchronizeView view = mgr.showSynchronizeViewInActivePage(); + mgr.addSynchronizeParticipants(new ISynchronizeParticipant[] {participant}); + view.display(participant); + } + return Status.OK_STATUS; + } + }; + job.addJobChangeListener(new JobChangeAdapter() { + public void done(IJobChangeEvent event) { + // Ensure that the participant is disposed it it didn't go to the sync view + if (TeamUI.getSynchronizeManager().get(participant.getId(), participant.getSecondaryId()) == null) + participant.dispose(); + } + + }); + ownsParticipant = false; + job.schedule(); + } + + /** + * Return whether previews should occur in a dialog or in the synchronize view. + * @return whether previews should occur in a dialog or in the synchronize view + */ + protected boolean isPreviewInDialog() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getContext() + */ + protected ISynchronizationContext getContext() { + if (participant != null) + return participant.getContext(); + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.operations.ResourceMappingOperation#getPreviewRequestMessage() + */ + protected String getPreviewRequestMessage() { + if (!isPreviewRequested()) { + return TeamUIMessages.ResourceMappingMergeOperation_4; + } + return super.getPreviewRequestMessage(); + } + + /** + * Create the synchronize pariticipant to be used by this operation + * to preview changes. By default, a {@link ModelSynchronizeParticipant} + * is created using the scope manager ({@link #getScopeManager()}) context + * from ({@link #createMergeContext()}) and job name ({@link #getJobName()}) + * of this operation. Subclasses may override this method. + * <p> + * Once created, it is the responsibility of the participant to dispose of the + * synchronization context when it is no longer needed. + * @return a newly created synchronize pariticipant to be used by this operation + */ + protected ModelSynchronizeParticipant createParticipant() { + return ModelSynchronizeParticipant.createParticipant(getScopeManager(), createMergeContext(), getJobName()); + } + + /** + * Create a merge context for use by this operation. This method + * is not long running so the operation should not refresh the + * context or perform other long running operations in this thread. + * However the context may start initializing in another thread as long + * as the job used to perform the initialization belongs to the + * family that matches the context. + * @return a merge context for use by this operation + */ + protected abstract ISynchronizationContext createMergeContext(); + +} diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelSynchronizeParticipant.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelSynchronizeParticipant.java index 3f81e313d..cb7e2986d 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelSynchronizeParticipant.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/operations/ModelSynchronizeParticipant.java @@ -83,6 +83,7 @@ public class ModelSynchronizeParticipant extends private final static String CTX_RESOURCE_PATH = "resource_path"; //$NON-NLS-1$ private ISynchronizationContext context; + private IResourceMappingScopeManager manager; private boolean mergingEnabled = true; protected SubscriberRefreshSchedule refreshSchedule; private String description; @@ -100,11 +101,12 @@ public class ModelSynchronizeParticipant extends /** * Create a participant for the given context + * @param manager the scope manager * @param context the synchronization context * @param name the name of the participant */ - public static ModelSynchronizeParticipant createParticipant(ISynchronizationContext context, String name) { - return new ModelSynchronizeParticipant(context, name); + public static ModelSynchronizeParticipant createParticipant(IResourceMappingScopeManager manager, ISynchronizationContext context, String name) { + return new ModelSynchronizeParticipant(manager, context, name); } /* @@ -112,7 +114,8 @@ public class ModelSynchronizeParticipant extends * @param context the synchronization context * @param name the name of the participant */ - private ModelSynchronizeParticipant(ISynchronizationContext context, String name) { + private ModelSynchronizeParticipant(IResourceMappingScopeManager manager, ISynchronizationContext context, String name) { + this.manager = manager; initializeContext(context); try { setInitializationData(TeamUI.getSynchronizeManager().getParticipantDescriptor("org.eclipse.team.ui.synchronization_context_synchronize_participant")); //$NON-NLS-1$ @@ -128,7 +131,8 @@ public class ModelSynchronizeParticipant extends * Create a participant for the given context * @param context the synchronization context */ - public ModelSynchronizeParticipant(ISynchronizationContext context) { + public ModelSynchronizeParticipant(IResourceMappingScopeManager manager, ISynchronizationContext context) { + this.manager = manager; initializeContext(context); refreshSchedule = new SubscriberRefreshSchedule(createRefreshable()); } @@ -221,6 +225,7 @@ public class ModelSynchronizeParticipant extends * @see org.eclipse.team.ui.synchronize.ISynchronizeParticipant#dispose() */ public void dispose() { + manager.dispose(); context.dispose(); Platform.getJobManager().cancel(this); refreshSchedule.dispose(); @@ -475,11 +480,10 @@ public class ModelSynchronizeParticipant extends CompoundResourceTraversal traversal = new CompoundResourceTraversal(); traversal.addTraversals(traversals); try { - // When restoring, we can't do anything long running so we'll need to use the local content for everything - NullProgressMonitor monitor = new NullProgressMonitor(); - ResourceMapping[] mappings = ResourceMappingScopeManager.getMappingsFromProviders(traversal.asTraversals(), ResourceMappingContext.LOCAL_CONTEXT, monitor); - IResourceMappingScope scope = createScopeManager().prepareScope(mappings, true, monitor); - IMergeContext context = restoreContext(scope, monitor); + // TODO: Need to restore mappings another way + ResourceMapping[] mappings = ResourceMappingScopeManager.getMappingsFromProviders(traversal.asTraversals(), ResourceMappingContext.LOCAL_CONTEXT, new NullProgressMonitor()); + manager = createScopeManager(mappings); + IMergeContext context = restoreContext(manager); initializeContext(context); } catch (CoreException e) { TeamUIPlugin.log(e); @@ -491,12 +495,11 @@ public class ModelSynchronizeParticipant extends * Recreate the context for this participant. This method is invoked when * the participant is restored after a restart. Although it is provided * with a progress monitor, long running operations should be avoided. - * @param scope the restored scope - * @param monitor a progress monitor + * @param manager the restored scope * @return the context for this participant * @throws CoreException */ - protected IMergeContext restoreContext(IResourceMappingScope scope, IProgressMonitor monitor) throws CoreException { + protected IMergeContext restoreContext(IResourceMappingScopeManager manager) throws CoreException { throw new PartInitException(NLS.bind("Participant {0} is not capable of restoring its context", getId())); } @@ -506,11 +509,12 @@ public class ModelSynchronizeParticipant extends * returns a scope manager that uses the local content. * This method can be overridden by subclasses. * + * @param mappings the restored mappings * @return a scope manager that can be used to build the scope of this * participant when it is restored after a restart */ - protected ResourceMappingScopeManager createScopeManager() { - return new ResourceMappingScopeManager(ResourceMappingContext.LOCAL_CONTEXT, true); + protected IResourceMappingScopeManager createScopeManager(ResourceMapping[] mappings) { + return new ResourceMappingScopeManager(mappings, ResourceMappingContext.LOCAL_CONTEXT, true); } /* private */ void setRefreshSchedule(SubscriberRefreshSchedule schedule) { @@ -573,5 +577,9 @@ public class ModelSynchronizeParticipant extends setCurrentModel(targetBuffer); return true; } + + public IResourceMappingScopeManager getScopeManager() { + return manager; + } } diff --git a/tests/org.eclipse.team.tests.core/src/org/eclipse/team/tests/core/mapping/ScopeBuildingTests.java b/tests/org.eclipse.team.tests.core/src/org/eclipse/team/tests/core/mapping/ScopeBuildingTests.java index 5b4a00575..afd5e9bd9 100644 --- a/tests/org.eclipse.team.tests.core/src/org/eclipse/team/tests/core/mapping/ScopeBuildingTests.java +++ b/tests/org.eclipse.team.tests.core/src/org/eclipse/team/tests/core/mapping/ScopeBuildingTests.java @@ -14,14 +14,11 @@ import java.lang.reflect.InvocationTargetException; import junit.framework.Test; -import org.eclipse.core.resources.*; -import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceMappingContext; -import org.eclipse.core.resources.mapping.ResourceTraversal; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.team.core.mapping.IResourceMappingScope; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.mapping.*; +import org.eclipse.core.runtime.*; +import org.eclipse.team.core.mapping.IResourceMappingScopeManager; import org.eclipse.team.core.mapping.provider.ResourceMappingScopeManager; import org.eclipse.team.internal.core.mapping.ResourceMappingScope; import org.eclipse.team.tests.core.TeamTest; @@ -33,45 +30,39 @@ public class ScopeBuildingTests extends TeamTest { protected static final String TEST_MODEL_PROVIDER_ID = "id1"; private class TestResourceMappingOperation extends ModelOperation { - - private ResourceMapping[] additionalMappings; - - protected TestResourceMappingOperation(ResourceMapping[] selectedMappings, ResourceMapping[] additionalMappings) { - super(null, selectedMappings); - this.additionalMappings = additionalMappings; - } - protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - // Do nothing since we're just testing the scope build - } - - protected void promptForInputChange(IProgressMonitor monitor) { - // Throw an exception to indicate that a prompt was requested - throw PROMPT_EXCEPTION; - } - - protected ResourceMappingScopeManager getScopeManager() { - return new ResourceMappingScopeManager(getResourceMappingContext(), false) { - public IResourceMappingScope prepareScope( - ResourceMapping[] selectedMappings, - boolean useLocalContext, + protected TestResourceMappingOperation(ResourceMapping[] selectedMappings, final ResourceMapping[] additionalMappings) { + super(null, new ResourceMappingScopeManager(selectedMappings, ResourceMappingContext.LOCAL_CONTEXT, false) { + public void initialize( IProgressMonitor monitor) throws CoreException { - - IResourceMappingScope resourceMappingScope = super.prepareScope(selectedMappings, useLocalContext, monitor); + super.initialize(monitor); // Add the additional test mappings to the scope for (int i = 0; i < additionalMappings.length; i++) { ResourceMapping mapping = additionalMappings[i]; ResourceTraversal[] traversals = mapping.getTraversals(getContext(), monitor); - ((ResourceMappingScope)resourceMappingScope).addMapping(mapping, traversals); + ((ResourceMappingScope)getScope()).addMapping(mapping, traversals); // TODO: The additional mappings and additional resources boolean will not be set // TODO: This may bring in mappings from the resources modle provider } - return resourceMappingScope; } - }; + }); + } + protected void endOperation(IProgressMonitor monitor) { + IResourceMappingScopeManager manager= getScopeManager(); + manager.dispose(); + super.endOperation(monitor); + } + + protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + // Do nothing since we're just testing the scope build } + protected void promptForInputChange(IProgressMonitor monitor) { + // Throw an exception to indicate that a prompt was requested + throw PROMPT_EXCEPTION; + } } + public static Test suite() { return suite(ScopeBuildingTests.class); } @@ -118,7 +109,7 @@ public class ScopeBuildingTests extends TeamTest { public String getModelProviderId() { return TEST_MODEL_PROVIDER_ID; } - public boolean isAncestorOf(ResourceMapping mapping) { + public boolean contains(ResourceMapping mapping) { return false; } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java index ca5c66d8b..0a9095ad4 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java @@ -23,7 +23,6 @@ import org.eclipse.core.tests.resources.ResourceTest; import org.eclipse.swt.widgets.Display; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.subscribers.SubscriberResourceMappingContext; import org.eclipse.team.internal.ccvs.core.*; import org.eclipse.team.internal.ccvs.core.client.*; import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; @@ -248,22 +247,18 @@ public class EclipseTest extends ResourceTest { if (options == null) options = Command.NO_LOCAL_OPTIONS; if (options == Command.NO_LOCAL_OPTIONS) { - executeHeadless(new ModelUpdateOperation(null, mappings, SubscriberResourceMappingContext.createContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber())) { + executeHeadless(new ModelUpdateOperation(null, mappings, false) { protected boolean isAttemptHeadlessMerge() { return true; } - protected void showPreview(IProgressMonitor monitor) { + protected void handlePreviewRequest() { // Don't preview anything - getContext().dispose(); } - protected void promptForNoChanges() { + protected void handleNoChanges() { // Do nothing } - protected boolean consultModelsWhenGeneratingScope() { - return false; - } - protected void promptForMergeFailure(IStatus status) { - // Don't prompt + protected void handleValidationFailure(IStatus status) { + // Do nothing } }); } else { @@ -282,21 +277,17 @@ public class EclipseTest extends ResourceTest { } protected void replace(ResourceMapping[] mappings) throws CVSException { - executeHeadless(new ModelReplaceOperation(null, mappings, SubscriberResourceMappingContext.createContext(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber())) { + executeHeadless(new ModelReplaceOperation(null, mappings, false) { protected boolean promptForOverwrite() { return true; } - protected void showPreview(IProgressMonitor monitor) { - // Don't show a preview. If the repalce failed, the sync tests will detect the failure - getContext().dispose(); - } - protected void promptForNoChanges() { - // Do nothing + protected void handlePreviewRequest() { + // Don't prompt } - protected boolean consultModelsWhenGeneratingScope() { - return false; + protected void handleMergeFailure(IStatus status) { + // Don't prompt } - protected void promptForMergeFailure(IStatus status) { + protected void handleValidationFailure(IStatus status) { // Don't prompt } }); |