Bug 64396 [Sync View] Sync compare goes to server twice for the file?
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
index c4638fb..f217188 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -14,6 +14,7 @@
 import java.io.InputStream;
 import java.util.*;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.*;
 import org.eclipse.team.core.TeamException;
@@ -609,4 +610,15 @@
 		return super.isContentsCached();
 	}
 
+	/**
+	 * Cache the contents of the given IFile as the contents for this remote file handle.
+	 * The caller must ensure that the local file is mapped to the same revision and is
+	 * not modified since it was loaded from CVS.
+	 * @param file
+	 * @throws CoreException
+	 * @throws TeamException
+	 */
+	public void setContents(IFile file, IProgressMonitor monitor) throws TeamException, CoreException {
+	    setContents(file.getContents(), monitor);
+	}
 }
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSParticipant.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSParticipant.java
index 62f3b84..3d0bc58 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSParticipant.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSParticipant.java
@@ -11,17 +11,16 @@
 package org.eclipse.team.internal.ccvs.ui.subscriber;
 
 import org.eclipse.compare.CompareConfiguration;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
 import org.eclipse.jface.viewers.ILabelDecorator;
 import org.eclipse.team.core.TeamException;
 import org.eclipse.team.core.synchronize.SyncInfo;
 import org.eclipse.team.core.variants.IResourceVariant;
-import org.eclipse.team.internal.ccvs.core.ICVSRemoteFile;
-import org.eclipse.team.internal.ccvs.core.ILogEntry;
+import org.eclipse.team.internal.ccvs.core.*;
+import org.eclipse.team.internal.ccvs.core.resources.RemoteFile;
 import org.eclipse.team.internal.ccvs.ui.*;
-import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
-import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants;
+import org.eclipse.team.internal.ccvs.ui.Policy;
 import org.eclipse.team.ui.synchronize.*;
 
 /**
@@ -42,9 +41,12 @@
 	/* (non-Javadoc)
      * @see org.eclipse.team.ui.synchronize.SubscriberParticipant#updateLabels(org.eclipse.team.ui.synchronize.ISynchronizeModelElement, org.eclipse.compare.CompareConfiguration, org.eclipse.core.runtime.IProgressMonitor)
      */
-    public void updateLabels(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) {
-        super.updateLabels(element, config, monitor);
-        updateLabelsForCVS(element, config, monitor);
+    public void prepareCompareInput(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) throws TeamException {
+        monitor.beginTask(null, 100);
+        deriveBaseContentsFromLocal(element, Policy.subMonitorFor(monitor, 10));
+        super.prepareCompareInput(element, config, Policy.subMonitorFor(monitor, 80));
+        updateLabelsForCVS(element, config, Policy.subMonitorFor(monitor, 10));
+        monitor.done();
     }
 
     /**
@@ -91,4 +93,40 @@
 	    }
 	    return null;
 	}
+
+    /**
+     * If the local is not modified and the base matches the local then 
+     * cache the local contents as the contents of the base.
+     * @param element
+     * @throws CoreException
+     * @throws TeamException
+     */
+    public static void deriveBaseContentsFromLocal(ISynchronizeModelElement element, IProgressMonitor monitor) throws TeamException {
+        SyncInfo info = getSyncInfo(element);
+        if (info == null) 
+            return;
+        
+        // We need a base that is a file and a local that is a file
+        IResource local = info.getLocal();
+        IResourceVariant base = info.getBase();
+        if (base == null || base.isContainer() || local.getType() != IResource.FILE || !local.exists())
+            return;
+        
+        // We can only use the local contents for incoming changes.
+        // Outgoing or conflicting changes imply that the local has changed
+        if ((info.getKind() & SyncInfo.DIRECTION_MASK) != SyncInfo.INCOMING)
+            return;
+        
+        try {
+            RemoteFile remoteFile = (RemoteFile)base;
+            if (!remoteFile.isContentsCached())
+                (remoteFile).setContents((IFile)local, monitor);
+        } catch (CoreException e) {
+            if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
+                // The file must have just been deleted
+                return;
+            }
+            throw CVSException.wrapException(e);
+        }
+    }
 }
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/WorkspaceSynchronizeParticipant.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/WorkspaceSynchronizeParticipant.java
index 4f08dbe..d334c58 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/WorkspaceSynchronizeParticipant.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/WorkspaceSynchronizeParticipant.java
@@ -13,7 +13,9 @@
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.team.core.TeamException;
 import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
+import org.eclipse.team.internal.ccvs.ui.Policy;
 import org.eclipse.team.internal.ccvs.ui.actions.*;
 import org.eclipse.team.internal.ui.synchronize.ScopableSubscriberParticipant;
 import org.eclipse.team.internal.ui.synchronize.SynchronizePageConfiguration;
@@ -173,8 +175,11 @@
 	/* (non-Javadoc)
      * @see org.eclipse.team.ui.synchronize.SubscriberParticipant#updateLabels(org.eclipse.team.ui.synchronize.ISynchronizeModelElement, org.eclipse.compare.CompareConfiguration, org.eclipse.core.runtime.IProgressMonitor)
      */
-    public void updateLabels(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) {
-        super.updateLabels(element, config, monitor);
-        CVSParticipant.updateLabelsForCVS(element, config, monitor);
+    public void prepareCompareInput(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) throws TeamException {
+        monitor.beginTask(null, 100);
+        CVSParticipant.deriveBaseContentsFromLocal(element, Policy.subMonitorFor(monitor, 10));
+        super.prepareCompareInput(element, config, Policy.subMonitorFor(monitor, 80));
+        CVSParticipant.updateLabelsForCVS(element, config, Policy.subMonitorFor(monitor, 10));
+        monitor.done();
     }
 }
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/AbstractSynchronizeParticipant.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/AbstractSynchronizeParticipant.java
index c672904..657fa68 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/AbstractSynchronizeParticipant.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/AbstractSynchronizeParticipant.java
@@ -16,9 +16,11 @@
 import org.eclipse.jface.util.*;
 import org.eclipse.jface.viewers.IBasicPropertyConstants;
 import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.synchronize.SyncInfo;
 import org.eclipse.team.internal.ui.*;
 import org.eclipse.team.internal.ui.Policy;
 import org.eclipse.team.internal.ui.registry.SynchronizeParticipantDescriptor;
+import org.eclipse.team.internal.ui.synchronize.SyncInfoModelElement;
 import org.eclipse.team.internal.ui.synchronize.SynchronizePageConfiguration;
 import org.eclipse.team.ui.TeamImages;
 import org.eclipse.ui.IMemento;
@@ -328,16 +330,40 @@
 	protected abstract void initializeConfiguration(ISynchronizePageConfiguration configuration);
 	
 	/**
-	 * Update the labels in the given configuration using information from the provided
-	 * element. The configuration is used to configure the compare editor used to display
-	 * the given sync info.
+	 * Default implementation will update the labels in the given configuration using 
+	 * information from the provided element if it adapts to <code>SyncInfo</code>.
+	 * It will also cache the contents for the remote and base if the element is
+	 * sync info based.
 	 * @param element the sync model element whose contents are about to be displayed to the user
-	 * @param config the compare configuration that willbe used to configure the compare editor
-	 * @param monitor a progress monitor that can be used if contacting a server to configure the labels
+	 * 		in a compare editor or compare dialog
+	 * @param configuration the compare configuration that will be used to configure the compare editor or dialog
+	 * @param monitor a progress monitor that can be used if contacting a server to prepare the element and configuration
+	 * @throws TeamException if an error occurred that shoudl rpevent the display of the compare editor containing
+	 * the element
 	 * 
 	 * @since 3.1
+	 * @see org.eclipse.team.ui.synchronize.ISynchronizeParticipant#prepareCompareInput(org.eclipse.team.ui.synchronize.ISynchronizeModelElement, org.eclipse.compare.CompareConfiguration, org.eclipse.core.runtime.IProgressMonitor)
 	 */
-	public void updateLabels(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) {
-	    // Do nothing, by default
+	public void prepareCompareInput(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) throws TeamException {
+	    SyncInfo sync = getSyncInfo(element);
+	    if (sync != null)
+	        Utils.updateLabels(sync, config);
+	    if (element instanceof SyncInfoModelElement) {
+			SyncInfoModelElement node = (SyncInfoModelElement)element;
+            (node).cacheContents(monitor);
+	    }
+	}
+	
+	/*
+	 * Get the sync info node from the element using the adaptable mechanism.
+	 * A <code>null</code> is returned if the element doesn't have a sync info
+	 * @param element the sync model element
+	 * @return the sync info for the element or <code>null</code>
+	 */
+	private SyncInfo getSyncInfo(ISynchronizeModelElement element) {
+	    if (element instanceof IAdaptable) {
+		    return (SyncInfo)((IAdaptable)element).getAdapter(SyncInfo.class);
+	    }
+	    return null;
 	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeParticipant.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeParticipant.java
index 6d8fa48..214f3f5 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeParticipant.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ISynchronizeParticipant.java
@@ -15,6 +15,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.team.core.TeamException;
 import org.eclipse.ui.*;
 import org.eclipse.ui.part.IPageBookViewPage;
 
@@ -221,14 +222,20 @@
 	public void removePropertyChangeListener(IPropertyChangeListener listener);
 	
 	/**
-	 * Update the labels in the given configuration using information from the provided
-	 * element. The configuration is used to configure the compare editor used to display
-	 * the given sync info.
+	 * Prepare the given element and compare configuration for use with a compare editor
+	 * input.
 	 * @param element the sync model element whose contents are about to be displayed to the user
-	 * @param config the compare configuration that willbe used to configure the compare editor
-	 * @param monitor a progress monitor that can be used if contacting a server to configure the labels
+	 * 		in a compare editor or compare dialog
+	 * @param configuration the compare configuration that will be used to configure the compare editor or dialog
+	 * @param monitor a progress monitor that can be used if contacting a server to prepare the element and configuration
+	 * @throws TeamException if an error occurred that shoudl rpevent the display of the compare editor containing
+	 * 		the element
 	 * 
 	 * @since 3.1
 	 */
-	public void updateLabels(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor);
+	public void prepareCompareInput(
+	        ISynchronizeModelElement element, 
+	        CompareConfiguration configuration, 
+	        IProgressMonitor monitor) 
+				throws TeamException;
 }
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ParticipantPageSaveablePart.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ParticipantPageSaveablePart.java
index f7d4ee4..28e9e64 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ParticipantPageSaveablePart.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/ParticipantPageSaveablePart.java
@@ -390,14 +390,10 @@
 								manager.busyCursorWhile(new IRunnableWithProgress() {
 									public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
 										try {	
-											node.cacheContents(monitor);
+										    participant.prepareCompareInput(node, cc, monitor);
 											hookContentChangeListener(node);
 										} catch (TeamException e) {
 											Utils.handle(e);
-										} finally {
-											// Update the labels even if the content wasn't fetched correctly. This is
-											// required because the selection would still of changed.
-										    participant.updateLabels(node, cc, monitor);
 										}
 									}
 								});
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SubscriberParticipant.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SubscriberParticipant.java
index 0124699..ca9df20 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SubscriberParticipant.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SubscriberParticipant.java
@@ -12,7 +12,6 @@
 
 import java.util.Arrays;
 
-import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.*;
 import org.eclipse.jface.util.IPropertyChangeListener;
@@ -20,7 +19,8 @@
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.team.core.TeamException;
 import org.eclipse.team.core.subscribers.Subscriber;
-import org.eclipse.team.core.synchronize.*;
+import org.eclipse.team.core.synchronize.SyncInfoFilter;
+import org.eclipse.team.core.synchronize.SyncInfoTree;
 import org.eclipse.team.internal.core.subscribers.SubscriberSyncInfoCollector;
 import org.eclipse.team.internal.ui.*;
 import org.eclipse.team.internal.ui.synchronize.*;
@@ -422,33 +422,4 @@
 	public ISynchronizeScope getScope() {
 		return scope;
 	}
-	
-	/**
-	 * Update the labels in the given configuration using information from the provided
-	 * sync info. The configuration is used to configure the compare editor used to display
-	 * the given sync info.
-	 * @param sync the sync info node whose contents are about to be displayed to the user
-	 * @param config the compare configuration that willbe used to configure the compare editor
-	 * @param monitor a progress monitor that can be used if contacting a server to configure the labels
-	 * 
-	 * @since 3.1
-	 */
-	public void updateLabels(ISynchronizeModelElement element, CompareConfiguration config, IProgressMonitor monitor) {
-	    SyncInfo sync = getSyncInfo(element);
-	    if (sync != null)
-	        Utils.updateLabels(sync, config);
-	}
-	
-	/**
-	 * Get the sync info node from the element using the adaptable mechanism.
-	 * A <code>null</code> is returned if the element doesn't have a sync info
-	 * @param element the sync model element
-	 * @return the sync info for the element or <code>null</code>
-	 */
-	private SyncInfo getSyncInfo(ISynchronizeModelElement element) {
-	    if (element instanceof IAdaptable) {
-		    return (SyncInfo)((IAdaptable)element).getAdapter(SyncInfo.class);
-	    }
-	    return null;
-	}
 }
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SyncInfoCompareInput.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SyncInfoCompareInput.java
index 4f8cc3d..86845d5 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SyncInfoCompareInput.java
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/SyncInfoCompareInput.java
@@ -207,13 +207,13 @@
 		// update the title now that the remote revision number as been fetched
 		// from the server
 		setTitle(getTitle());
-		if (participant != null) {
-		    participant.updateLabels(node, getCompareConfiguration(), monitor);
-		} else {
-		    Utils.updateLabels(node.getSyncInfo(), getCompareConfiguration());
-		}
 		try {
-			node.cacheContents(monitor);
+			if (participant != null) {
+			    participant.prepareCompareInput(node, getCompareConfiguration(), monitor);
+			} else {
+			    Utils.updateLabels(node.getSyncInfo(), getCompareConfiguration());
+				node.cacheContents(monitor);
+			}
 		} catch (TeamException e) {
 			throw new InvocationTargetException(e);
 		}