diff options
author | james | 2002-02-08 19:41:32 +0000 |
---|---|---|
committer | james | 2002-02-08 19:41:32 +0000 |
commit | c04dc2de603d387c4d9e046b6560094e6e7509c0 (patch) | |
tree | e0856936b6c036e7a61461963ead172ccffc12dd | |
parent | 6f9d802d76fc53c9f36a22cf6c9ef0f7c88ac052 (diff) | |
download | eclipse.platform.team-c04dc2de603d387c4d9e046b6560094e6e7509c0.tar.gz eclipse.platform.team-c04dc2de603d387c4d9e046b6560094e6e7509c0.tar.xz eclipse.platform.team-c04dc2de603d387c4d9e046b6560094e6e7509c0.zip |
Sync view improvements.
-Support auto-merge of mergeable conflicts in the sync and merge views.
-Backing out of incoming or outgoing changes in the sync views.
-Indicate unmanaged files with '?' in sync view
Fixes bugs 16, 123, 132, 7570, 7571, 8559, 8642, 7278, and others.
17 files changed, 704 insertions, 444 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java index ddbcf2e76..412fe08a6 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java @@ -929,6 +929,7 @@ public class CVSTeamProvider implements ITeamNature, ITeamProvider { ResponseHandler oldHandler = null; if(handler!=null) { oldHandler = Command.getResponseHandler(handler.getResponseID()); + Command.registerResponseHandler(handler); } // Build the arguments list diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/NullCopyHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/NullCopyHandler.java new file mode 100644 index 000000000..f3e4b9916 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/NullCopyHandler.java @@ -0,0 +1,21 @@ +package org.eclipse.team.internal.ccvs.core.client; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.internal.ccvs.core.CVSException; + +public class NullCopyHandler extends CopyHandler { + /* + * @see ResponseHandler#handle(Session, String, IProgressMonitor) + */ + public void handle(Session session, String argument, IProgressMonitor monitor) + throws CVSException { + // read additional data for the response + String repositoryFile = session.readLine(); + String newFile = session.readLine(); + } +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java index 7e402ecd2..42db0813c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java @@ -235,7 +235,7 @@ public class CVSRemoteSyncElement extends RemoteSyncElement { * XXX This is a quick fix to allow conflicts to be loaded and has not been tested for non-conflict cases
*/
public void makeIncoming(IProgressMonitor monitor) throws TeamException {
-
+ if (!getLocal().exists()) return;
int syncKind = getSyncKind(GRANULARITY_TIMESTAMP, monitor);
boolean conflict = (syncKind & DIRECTION_MASK) == CONFLICTING;
boolean incoming = (syncKind & DIRECTION_MASK) == INCOMING;
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java index aa5e2955e..c952e8c60 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java @@ -139,6 +139,8 @@ public class CVSUIPlugin extends AbstractUIPlugin { createImageDescriptor(ICVSUIConstants.IMG_WIZBAN_BRANCH, baseURL); createImageDescriptor(ICVSUIConstants.IMG_WIZBAN_MERGE, baseURL); createImageDescriptor(ICVSUIConstants.IMG_WIZBAN_SHARE, baseURL); + createImageDescriptor(ICVSUIConstants.IMG_MERGEABLE_CONFLICT, baseURL); + createImageDescriptor(ICVSUIConstants.IMG_QUESTIONABLE, baseURL); } /** * Convenience method for logging statuses to the plugin log diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/ICVSUIConstants.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/ICVSUIConstants.java index 984487282..f28ef47a1 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/ICVSUIConstants.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/ICVSUIConstants.java @@ -12,6 +12,10 @@ public interface ICVSUIConstants { // images + // overlays + public final String IMG_MERGEABLE_CONFLICT = "ovr16/confauto_ov.gif"; + public final String IMG_QUESTIONABLE = "ovr16/question_ov.gif"; + // objects public final String IMG_REPOSITORY = "obj16/repository_rep.gif"; public final String IMG_TAG = "obj16/tag.gif"; diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/RepositoryManager.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/RepositoryManager.java index 2a859e291..3f6c1ce15 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/RepositoryManager.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/RepositoryManager.java @@ -18,12 +18,9 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; -import java.util.Properties; import java.util.Set; -import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; @@ -39,14 +36,14 @@ import org.eclipse.team.ccvs.core.ICVSRemoteFile; import org.eclipse.team.ccvs.core.ICVSRemoteResource; import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.ccvs.core.ILogEntry; -import org.eclipse.team.core.ITeamManager; import org.eclipse.team.core.ITeamProvider; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.core.sync.IRemoteResource; import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.internal.ccvs.core.client.Command; -import org.eclipse.team.internal.ccvs.core.client.Update; +import org.eclipse.team.internal.ccvs.core.client.NullCopyHandler; +import org.eclipse.team.internal.ccvs.core.client.ResponseHandler; import org.eclipse.team.internal.ccvs.ui.model.BranchTag; /** @@ -419,10 +416,7 @@ public class RepositoryManager { provider.delete(providerResources, subMonitor); } } - /** - * Update the given resources with depth zero. - */ - public void update(IResource[] resources, IProgressMonitor monitor) throws TeamException { + public void update(IResource[] resources, Command.LocalOption[] options, boolean createBackups, IProgressMonitor monitor) throws TeamException { Hashtable table = getProviderMapping(resources); Set keySet = table.keySet(); monitor.beginTask("", keySet.size() * 1000); @@ -431,10 +425,13 @@ public class RepositoryManager { while (iterator.hasNext()) { IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); - provider.setComment(previousComment); List list = (List)table.get(provider); IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); - provider.update(providerResources, new Command.LocalOption[] {Command.DO_NOT_RECURSE}, null, null, subMonitor); + ResponseHandler handler = null; + if (!createBackups) { + handler = new NullCopyHandler(); + } + provider.update(providerResources, options, null, handler, subMonitor); } } /** @@ -497,27 +494,6 @@ public class RepositoryManager { } /** - * Get the given resources from their associated providers. - * - * @param resources the resources to commit - * @param monitor the progress monitor - */ - public void get(IResource[] resources, IProgressMonitor monitor) throws TeamException { - Hashtable table = getProviderMapping(resources); - Set keySet = table.keySet(); - monitor.beginTask("", keySet.size() * 1000); - monitor.setTaskName(Policy.bind("RepositoryManager.getting")); - Iterator iterator = keySet.iterator(); - while (iterator.hasNext()) { - IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); - CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); - List list = (List)table.get(provider); - IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); - provider.update(providerResources, new Command.LocalOption[] {Update.IGNORE_LOCAL_CHANGES}, null, null, subMonitor); - } - } - - /** * Helper method. Return a hashtable mapping provider to a list of resources * shared with that provider. */ diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/GetMergeAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/GetMergeAction.java deleted file mode 100644 index 1e5d3a046..000000000 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/GetMergeAction.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.eclipse.team.internal.ccvs.ui.merge; - -/* - * (c) Copyright IBM Corp. 2000, 2002. - * All Rights Reserved. - */ - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; - -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.compare.structuremergeviewer.IDiffContainer; -import org.eclipse.compare.structuremergeviewer.IDiffElement; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.team.core.TeamException; -import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; -import org.eclipse.team.internal.ccvs.ui.Policy; -import org.eclipse.team.internal.ccvs.ui.RepositoryManager; -import org.eclipse.team.internal.ccvs.ui.sync.*; -import org.eclipse.team.ui.sync.ITeamNode; -import org.eclipse.team.ui.sync.SyncSet; -import org.eclipse.team.ui.sync.TeamFile; - -public class GetMergeAction extends GetSyncAction { - public GetMergeAction(CVSSyncCompareInput model, ISelectionProvider sp, int direction, String label, Shell shell) { - super(model, sp, direction, label, shell); - } - protected SyncSet run(SyncSet syncSet, IProgressMonitor monitor) { - // If there is a conflict in the syncSet, we need to prompt the user before proceeding. - if (syncSet.hasConflicts() || syncSet.hasOutgoingChanges()) { - String[] buttons = new String[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL}; - String question = Policy.bind("GetSyncAction.questionCatchup"); - String title = Policy.bind("GetSyncAction.titleCatchup"); - String[] tips = new String[] { - Policy.bind("GetSyncAction.catchupAll"), - Policy.bind("GetSyncAction.catchupPart"), - Policy.bind("GetSyncAction.cancelCatchup") - }; - Shell shell = getShell(); - final ToolTipMessageDialog dialog = new ToolTipMessageDialog(shell, title, null, question, MessageDialog.QUESTION, buttons, tips, 0); - shell.getDisplay().syncExec(new Runnable() { - public void run() { - dialog.open(); - } - }); - switch (dialog.getReturnCode()) { - case 0: - // Yes, synchronize conflicts as well - break; - case 1: - // No, only synchronize non-conflicting changes. - syncSet.removeConflictingNodes(); - break; - case 2: - default: - // Cancel - return null; - } - } - ITeamNode[] changed = syncSet.getChangedNodes(); - if (changed.length == 0) { - return syncSet; - } - - try { - for (int i = 0; i < changed.length; i++) { - switch (changed[i].getKind() & Differencer.CHANGE_TYPE_MASK) { - case Differencer.ADDITION: - IResource resource = changed[i].getResource(); - if (resource instanceof IFile) { - createParentStructure(((IFile)resource).getParent(), monitor); - InputStream stream = ((TeamFile)changed[i]).getMergeResource().getSyncElement().getRemote().getContents(monitor); - ((IFile)resource).create(stream, true, monitor); - } else if (resource instanceof IFolder) { - createParentStructure((IFolder)resource, monitor); - } - break; - case Differencer.DELETION: - changed[i].getResource().delete(true, monitor); - break; - case Differencer.CHANGE: - resource = changed[i].getResource(); - if (resource instanceof IFile) { - InputStream stream = ((TeamFile)changed[i]).getMergeResource().getSyncElement().getRemote().getContents(monitor); - ((IFile)resource).setContents(stream, true, true, monitor); - } - break; - } - } - } catch (TeamException e) { - ErrorDialog.openError(getShell(), null, null, e.getStatus()); - return null; - } catch (CoreException e) { - CVSUIPlugin.log(e.getStatus()); - return null; - } - return syncSet; - } - /** - * Create the folder and all its parents - */ - private void createParentStructure(IContainer container, IProgressMonitor monitor) throws CoreException { - Vector v = new Vector(); - if (container.exists()) return; - while (!container.exists()) { - v.add(0, container); - container = container.getParent(); - } - Iterator it = v.iterator(); - while (it.hasNext()) { - ((IFolder)it.next()).create(true, true, monitor); - } - } -} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/MergeEditorInput.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/MergeEditorInput.java index 6925c2dd8..50d13755b 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/MergeEditorInput.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/MergeEditorInput.java @@ -53,6 +53,12 @@ public class MergeEditorInput extends CVSSyncCompareInput { monitor.done(); } } + public CVSTag getStartTag() { + return start; + } + public CVSTag getEndTag() { + return end; + } public String getTitle() { return Policy.bind("MergeEditorInput.title", start.getName(), end.getName()); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/UpdateMergeAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/UpdateMergeAction.java new file mode 100644 index 000000000..71ea6f694 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/UpdateMergeAction.java @@ -0,0 +1,33 @@ +package org.eclipse.team.internal.ccvs.ui.merge; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.team.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.client.Command; +import org.eclipse.team.internal.ccvs.core.client.Update; +import org.eclipse.team.internal.ccvs.ui.sync.CVSSyncCompareInput; +import org.eclipse.team.internal.ccvs.ui.sync.UpdateSyncAction; + +public class UpdateMergeAction extends UpdateSyncAction { + public UpdateMergeAction(CVSSyncCompareInput model, ISelectionProvider sp, String label, Shell shell) { + super(model, sp, label, shell); + } + protected Command.LocalOption[] getLocalOptions(Command.LocalOption[] baseOptions) { + List list = new ArrayList(); + list.addAll(Arrays.asList(baseOptions)); + CVSTag startTag = ((MergeEditorInput)getDiffModel()).getStartTag(); + CVSTag endTag = ((MergeEditorInput)getDiffModel()).getEndTag(); + list.add(Update.makeArgumentOption(Update.JOIN, startTag.getName())); + list.add(Update.makeArgumentOption(Update.JOIN, endTag.getName())); + return (Command.LocalOption[]) list.toArray(new Command.LocalOption[list.size()]); + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties index 66aaa13f4..8c5baa821 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties @@ -28,10 +28,10 @@ BranchWizardPage.startWorking=Start working in the branch BranchWizardPage.specifyVersion=Version the project before creating the branch BranchWizardPage.versionName=Version Name: -CVSCatchupReleaseViewer.checkIn=&Check In +CVSCatchupReleaseViewer.commit=&Commit +CVSCatchupReleaseViewer.update=&Update CVSCatchupReleaseViewer.commonFile=Common file: {0} CVSCatchupReleaseViewer.commonFileRevision=Common file: {0} {1} -CVSCatchupReleaseViewer.get=&Get CVSCatchupReleaseViewer.noCommonFile=No common file CVSCatchupReleaseViewer.noRepositoryFile=No repository file CVSCatchupReleaseViewer.repositoryFile=Repository file: {0} @@ -113,11 +113,11 @@ CheckoutAsAction.enterProject=Enter the name of the project to checkout as: CommitAction.commit=Commit CommitAction.committing=Committing... -CommitMergeAction.questionRelease=You have changes that conflict with the server. Release those changes? -CommitMergeAction.titleRelease=Release Conflicts? -CommitMergeAction.releaseAll=Release all changes, overriding any conflicting changes on the server. -CommitMergeAction.releasePart=Only release the changes that don't conflict with changes on the server. -CommitMergeAction.cancelRelease=Cancel the release operation. +CommitSyncAction.questionRelease=You have changes that conflict with the server. Release those changes? +CommitSyncAction.titleRelease=Release Conflicts? +CommitSyncAction.releaseAll=Release all changes, overriding any conflicting changes on the server. +CommitSyncAction.releasePart=Only release the changes that don't conflict with changes on the server. +CommitSyncAction.cancelRelease=Cancel the release operation. CompareWithRemoteAction.compare=Compare CompareWithRemoteAction.noRemote=No Remote Resource @@ -229,11 +229,11 @@ RemoveRootAction.removeRoot=Discard Location RemoveBranchTagAction.removeTag=Discard Branch RemoveModuleVersionAction.removeTag=Discard Version +ReplaceWithTagAction.replace=Error Replacing With Tag + ReplaceWithRemoteAction.replacing=Replacing ReplaceWithRemoteAction.problemMessage=Error Replacing With Remote -ReplaceWithTagAction.replace=Error Replacing With Tag - RepositoryDialog.getRepository=Select a repository RepositoryDialog.description=Select a repository to connect your project to @@ -342,3 +342,10 @@ TagSelectionDialog.Tag_type__5=Tag type: TagSelectionDialog.Version_6=Version TagSelectionDialog.Branch_7=Branch TagSelectionDialog.Please_select_a_tag_9=Please select a tag + +UpdateSyncAction.Conflicting_changes_found_1=Conflicting changes found +UpdateSyncAction.You_have_local_changes_you_are_about_to_overwrite_2=You have local changes you are about to overwrite +UpdateSyncAction.Only_update_resources_that_can_be_automatically_merged_3=Only update resources that can be automatically merged +UpdateSyncAction.Update_all_resources,_overwriting_local_changes_with_remote_contents_4=Update all resources, overwriting local changes with remote contents +UpdateSyncAction.Overwrite_local_changes__5=Overwrite local changes? +UpdateSyncAction.You_have_local_changes_you_are_about_to_overwrite._Do_you_wish_to_continue__6=You have local changes you are about to overwrite. Do you wish to continue? diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java index 8fbfed3a7..da89454a8 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java @@ -1,14 +1,23 @@ package org.eclipse.team.internal.ccvs.ui.sync;
/*
- * (c) Copyright IBM Corp. 2000, 2001.
+ * (c) Copyright IBM Corp. 2000, 2002.
* All Rights Reserved.
*/
import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.resource.CompositeImageDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.ccvs.core.ICVSRemoteFile;
@@ -16,40 +25,119 @@ import org.eclipse.team.ccvs.core.ICVSRemoteResource; import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.sync.IRemoteResource;
import org.eclipse.team.core.sync.IRemoteSyncElement;
+import org.eclipse.team.internal.ccvs.core.resources.LocalFile;
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.internal.ccvs.ui.merge.GetMergeAction;
+import org.eclipse.team.internal.ccvs.ui.merge.UpdateMergeAction;
import org.eclipse.team.ui.sync.CatchupReleaseViewer;
+import org.eclipse.team.ui.sync.ITeamNode;
import org.eclipse.team.ui.sync.MergeResource;
import org.eclipse.team.ui.sync.SyncView;
public class CVSCatchupReleaseViewer extends CatchupReleaseViewer {
// Actions
- private GetSyncAction getAction;
- private CommitMergeAction commitAction;
- private GetMergeAction getMergeAction;
+ private UpdateSyncAction updateAction;
+ private CommitSyncAction commitAction;
+ private UpdateMergeAction updateMergeAction;
+
+ class DiffImage extends CompositeImageDescriptor {
+ private static final int HEIGHT= 16;
+ private static final int WIDTH= 22;
+
+ Image baseImage;
+ ImageDescriptor overlay;
+
+ public DiffImage(Image baseImage, ImageDescriptor overlay) {
+ this.baseImage = baseImage;
+ this.overlay = overlay;
+ }
+
+ /*
+ * @see CompositeImageDescriptor#drawCompositeImage(int, int)
+ */
+ protected void drawCompositeImage(int width, int height) {
+ drawImage(baseImage.getImageData(), 0, 0);
+ ImageData overlayData = overlay.getImageData();
+ drawImage(overlayData, WIDTH - overlayData.width, (HEIGHT - overlayData.height) / 2);
+ }
+
+ /*
+ * @see CompositeImageDescriptor#getSize()
+ */
+ protected Point getSize() {
+ return new Point(WIDTH, HEIGHT);
+ }
+ }
public CVSCatchupReleaseViewer(Composite parent, CVSSyncCompareInput model) {
super(parent, model);
initializeActions(model);
+ initializeLabelProvider();
+ }
+
+ private void initializeLabelProvider() {
+ final ImageDescriptor conflictDescriptor = CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_MERGEABLE_CONFLICT);
+ final ImageDescriptor questionableDescriptor = CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_QUESTIONABLE);
+ final LabelProvider oldProvider = (LabelProvider)getLabelProvider();
+ setLabelProvider(new LabelProvider() {
+ public Image getImage(Object element) {
+ Image image = oldProvider.getImage(element);
+ if (element instanceof ITeamNode) {
+ ITeamNode node = (ITeamNode)element;
+ int kind = node.getKind();
+ if ((kind & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) {
+ DiffImage diffImage = new DiffImage(image, conflictDescriptor);
+ return diffImage.createImage();
+ }
+ if (kind == (IRemoteSyncElement.OUTGOING | IRemoteSyncElement.ADDITION)) {
+ IResource resource = node.getResource();
+ if (resource.getType() == IResource.FILE) {
+ try {
+ if (new LocalFile(((IFile)resource).getLocation().toFile()).getSyncInfo() == null) {
+ DiffImage diffImage = new DiffImage(image, questionableDescriptor);
+ return diffImage.createImage();
+ }
+ } catch (TeamException e) {
+ ErrorDialog.openError(getControl().getShell(), null, null, e.getStatus());
+ // Fall through and return the default image
+ }
+ }
+ }
+ }
+ return image;
+ }
+ public String getText(Object element) {
+ return oldProvider.getText(element);
+ }
+ });
}
protected void fillContextMenu(IMenuManager manager) {
- super.fillContextMenu(manager);
- manager.add(new Separator());
- int syncMode = getSyncMode();
- if (syncMode == SyncView.SYNC_OUTGOING || syncMode == SyncView.SYNC_BOTH) {
- commitAction.update();
- manager.add(commitAction);
- }
- if (syncMode == SyncView.SYNC_INCOMING || syncMode == SyncView.SYNC_BOTH) {
- getAction.update();
- manager.add(getAction);
- }
- if (syncMode == SyncView.SYNC_MERGE) {
- getMergeAction.update();
- manager.add(getMergeAction);
+ switch (getSyncMode()) {
+ case SyncView.SYNC_INCOMING:
+ updateAction.update(SyncView.SYNC_INCOMING);
+ manager.add(updateAction);
+ break;
+ case SyncView.SYNC_OUTGOING:
+ commitAction.update(SyncView.SYNC_OUTGOING);
+ manager.add(commitAction);
+ updateAction.update(SyncView.SYNC_OUTGOING);
+ manager.add(updateAction);
+ break;
+ case SyncView.SYNC_BOTH:
+ commitAction.update(SyncView.SYNC_BOTH);
+ manager.add(commitAction);
+ updateAction.update(SyncView.SYNC_BOTH);
+ manager.add(updateAction);
+ break;
+ case SyncView.SYNC_MERGE:
+ updateMergeAction.update(SyncView.SYNC_INCOMING);
+ manager.add(updateMergeAction);
+ break;
}
+ manager.add(new Separator());
+ super.fillContextMenu(manager);
}
/**
@@ -57,9 +145,9 @@ public class CVSCatchupReleaseViewer extends CatchupReleaseViewer { */
private void initializeActions(final CVSSyncCompareInput diffModel) {
Shell shell = getControl().getShell();
- commitAction = new CommitMergeAction(diffModel, this, IRemoteSyncElement.OUTGOING, Policy.bind("CVSCatchupReleaseViewer.checkIn"), shell);
- getAction = new GetSyncAction(diffModel, this, IRemoteSyncElement.INCOMING, Policy.bind("CVSCatchupReleaseViewer.get"), shell);
- getMergeAction = new GetMergeAction(diffModel, this, IRemoteSyncElement.INCOMING, Policy.bind("CVSCatchupReleaseViewer.get"), shell);
+ commitAction = new CommitSyncAction(diffModel, this, Policy.bind("CVSCatchupReleaseViewer.commit"), shell);
+ updateAction = new UpdateSyncAction(diffModel, this, Policy.bind("CVSCatchupReleaseViewer.update"), shell);
+ updateMergeAction = new UpdateMergeAction(diffModel, this, Policy.bind("CVSCatchupReleaseViewer.update"), shell);
}
/**
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitMergeAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitMergeAction.java deleted file mode 100644 index 9d9fc7dd8..000000000 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitMergeAction.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.eclipse.team.internal.ccvs.ui.sync;
-
-/*
- * (c) Copyright IBM Corp. 2000, 2002.
- * All Rights Reserved.
- */
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.compare.structuremergeviewer.Differencer;
-import org.eclipse.compare.structuremergeviewer.IDiffElement;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.dialogs.ErrorDialog;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.viewers.ISelectionProvider;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.team.core.TeamException;
-import org.eclipse.team.core.sync.IRemoteSyncElement;
-import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement;
-import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
-import org.eclipse.team.internal.ccvs.ui.Policy;
-import org.eclipse.team.internal.ccvs.ui.RepositoryManager;
-import org.eclipse.team.ui.sync.ChangedTeamContainer;
-import org.eclipse.team.ui.sync.ITeamNode;
-import org.eclipse.team.ui.sync.SyncSet;
-import org.eclipse.team.ui.sync.SyncView;
-import org.eclipse.team.ui.sync.TeamFile;
-import org.eclipse.team.ui.sync.UnchangedTeamContainer;
-
-public class CommitMergeAction extends MergeAction {
- public CommitMergeAction(CVSSyncCompareInput model, ISelectionProvider sp, int direction, String label, Shell shell) {
- super(model, sp, direction, label, shell);
- }
-
- protected SyncSet run(SyncSet syncSet, IProgressMonitor monitor) {
- // If there is a conflict in the syncSet, we need to prompt the user before proceeding.
- if (syncSet.hasConflicts() || syncSet.hasIncomingChanges()) {
- String[] buttons = new String[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL};
- String question = Policy.bind("CommitMergeAction.questionRelease");
- String title = Policy.bind("CommitMergeAction.titleRelease");
- String[] tips = new String[] {
- Policy.bind("CommitMergeAction.releaseAll"),
- Policy.bind("CommitMergeAction.releasePart"),
- Policy.bind("CommitMergeAction.cancelRelease")
- };
- Shell shell = getShell();
- final ToolTipMessageDialog dialog = new ToolTipMessageDialog(shell, title, null, question, MessageDialog.QUESTION, buttons, tips, 0);
- shell.getDisplay().syncExec(new Runnable() {
- public void run() {
- dialog.open();
- }
- });
- switch (dialog.getReturnCode()) {
- case 0:
- // Yes, synchronize conflicts as well
- break;
- case 1:
- // No, only synchronize non-conflicting changes.
- syncSet.removeConflictingNodes();
- break;
- case 2:
- default:
- // Cancel
- return null;
- }
- }
- ITeamNode[] changed = syncSet.getChangedNodes();
- if (changed.length == 0) {
- return syncSet;
- }
- IResource[] changedResources = new IResource[changed.length];
- List additions = new ArrayList();
- List deletions = new ArrayList();
- List conflicts = new ArrayList();
- List incoming = new ArrayList();
-
- for (int i = 0; i < changed.length; i++) {
- changedResources[i] = changed[i].getResource();
- int kind = changed[i].getKind();
- switch (kind & Differencer.CHANGE_TYPE_MASK) {
- case Differencer.ADDITION:
- // Outgoing addition. 'add' it before committing.
- additions.add(changed[i].getResource());
- break;
- case Differencer.DELETION:
- if ((kind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING) {
- // Incoming deletion. makeOutgoing before committing.
- incoming.add(changed[i]);
- } else {
- // Outgoing deletion. 'delete' it before committing.
- deletions.add(changed[i].getResource());
- }
- break;
- }
- // If it's a conflicting change we need to mark it as merged before committing.
- if ((changed[i].getKind() & Differencer.DIRECTION_MASK) == Differencer.CONFLICTING) {
- if (changed[i] instanceof TeamFile) {
- conflicts.add(((TeamFile)changed[i]).getMergeResource().getSyncElement());
- }
- }
- }
- try {
- RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager();
- String comment = manager.promptForComment(getShell());
- if (comment == null) {
- // User cancelled. Remove the nodes from the sync set.
- return null;
- } else {
- // Make any incoming deletions into outgoing changes before committing.
- Iterator it = incoming.iterator();
- while (it.hasNext()) {
- ITeamNode node = (ITeamNode)it.next();
- if (node instanceof TeamFile) {
- CVSRemoteSyncElement element = (CVSRemoteSyncElement)((TeamFile)node).getMergeResource().getSyncElement();
- element.makeOutgoing(monitor);
- } else if (node instanceof ChangedTeamContainer) {
- CVSRemoteSyncElement element = (CVSRemoteSyncElement)((ChangedTeamContainer)node).getMergeResource().getSyncElement();
- element.makeOutgoing(monitor);
- }
- }
-
- if (additions.size() != 0) {
- manager.add((IResource[])additions.toArray(new IResource[0]), monitor);
- }
- if (deletions.size() != 0) {
- manager.delete((IResource[])deletions.toArray(new IResource[0]), monitor);
- }
- if (conflicts.size() != 0) {
- manager.merged((IRemoteSyncElement[])conflicts.toArray(new IRemoteSyncElement[0]));
- }
- manager.commit(changedResources, comment, getShell(), monitor);
- }
- } catch (final TeamException e) {
- getShell().getDisplay().syncExec(new Runnable() {
- public void run() {
- ErrorDialog.openError(getShell(), null, null, e.getStatus());
- }
- });
- return null;
- }
- return syncSet;
- }
-
- protected boolean isEnabled(ITeamNode node) {
- int kind = node.getKind();
- if (node instanceof TeamFile) {
- int direction = kind & Differencer.DIRECTION_MASK;
- if (direction == ITeamNode.OUTGOING || direction == Differencer.CONFLICTING) {
- return true;
- }
- // allow to release over incoming deletions
- return (kind & Differencer.CHANGE_TYPE_MASK) == Differencer.DELETION;
- }
- if (node instanceof ChangedTeamContainer) {
- if ((kind & Differencer.DIRECTION_MASK) == ITeamNode.OUTGOING) {
- return true;
- }
- // Fall through to UnchangedTeamContainer code
- }
- if (node instanceof UnchangedTeamContainer) {
- IDiffElement[] children = ((UnchangedTeamContainer)node).getChildren();
- for (int i = 0; i < children.length; i++) {
- ITeamNode child = (ITeamNode)children[i];
- if (isEnabled(child)) {
- return true;
- }
- }
- return false;
- }
- return false;
- }
-}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/GetSyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java index bba2b3eb6..947de1a68 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/GetSyncAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java @@ -14,6 +14,7 @@ import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.compare.structuremergeviewer.IDiffContainer; import org.eclipse.compare.structuremergeviewer.IDiffElement; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.dialogs.ErrorDialog; @@ -22,6 +23,7 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.widgets.Shell; import org.eclipse.team.core.TeamException; +import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.Policy; @@ -30,27 +32,22 @@ import org.eclipse.team.ui.sync.ChangedTeamContainer; import org.eclipse.team.ui.sync.ITeamNode; import org.eclipse.team.ui.sync.SyncSet; import org.eclipse.team.ui.sync.TeamFile; -import org.eclipse.team.ui.sync.UnchangedTeamContainer; -/** - * GetSyncAction is run on a set of sync nodes when the "Get" menu item is performed - * in the Synchronize view. - */ -public class GetSyncAction extends MergeAction { - public GetSyncAction(CVSSyncCompareInput model, ISelectionProvider sp, int direction, String label, Shell shell) { - super(model, sp, direction, label, shell); +public class CommitSyncAction extends MergeAction { + public CommitSyncAction(CVSSyncCompareInput model, ISelectionProvider sp, String label, Shell shell) { + super(model, sp, label, shell); } protected SyncSet run(SyncSet syncSet, IProgressMonitor monitor) { // If there is a conflict in the syncSet, we need to prompt the user before proceeding. - if (syncSet.hasConflicts() || syncSet.hasOutgoingChanges()) { + if (syncSet.hasConflicts() || syncSet.hasIncomingChanges()) { String[] buttons = new String[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL}; - String question = Policy.bind("GetSyncAction.questionCatchup"); - String title = Policy.bind("GetSyncAction.titleCatchup"); + String question = Policy.bind("CommitSyncAction.questionRelease"); + String title = Policy.bind("CommitSyncAction.titleRelease"); String[] tips = new String[] { - Policy.bind("GetSyncAction.catchupAll"), - Policy.bind("GetSyncAction.catchupPart"), - Policy.bind("GetSyncAction.cancelCatchup") + Policy.bind("CommitSyncAction.releaseAll"), + Policy.bind("CommitSyncAction.releasePart"), + Policy.bind("CommitSyncAction.cancelRelease") }; Shell shell = getShell(); final ToolTipMessageDialog dialog = new ToolTipMessageDialog(shell, title, null, question, MessageDialog.QUESTION, buttons, tips, 0); @@ -66,6 +63,7 @@ public class GetSyncAction extends MergeAction { case 1: // No, only synchronize non-conflicting changes. syncSet.removeConflictingNodes(); + syncSet.removeIncomingNodes(); break; case 2: default: @@ -77,14 +75,21 @@ public class GetSyncAction extends MergeAction { if (changed.length == 0) { return syncSet; } - List changedResources = new ArrayList(); - List addedResources = new ArrayList(); + IResource[] changedResources = new IResource[changed.length]; + List additions = new ArrayList(); + List deletions = new ArrayList(); + List toMerge = new ArrayList(); + List incoming = new ArrayList(); + // A list of diff elements in the sync set which are incoming folder additions List parentCreationElements = new ArrayList(); // A list of diff elements in the sync set which are folder conflicts List parentConflictElements = new ArrayList(); for (int i = 0; i < changed.length; i++) { + changedResources[i] = changed[i].getResource(); + int kind = changed[i].getKind(); + IResource resource = changed[i].getResource(); IDiffContainer parent = changed[i].getParent(); if (parent != null) { int parentKind = changed[i].getParent().getKind(); @@ -95,14 +100,40 @@ public class GetSyncAction extends MergeAction { parentConflictElements.add(parent); } } - if ((changed[i].getKind() & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) { - addedResources.add(changed[i].getResource()); - } else { - changedResources.add(changed[i].getResource()); + switch (kind & Differencer.DIRECTION_MASK) { + case ITeamNode.INCOMING: + // Incoming change. Make it outgoing before committing. + incoming.add(changed[i]); + break; + case ITeamNode.OUTGOING: + switch (kind & Differencer.CHANGE_TYPE_MASK) { + case Differencer.ADDITION: + // Outgoing addition. 'add' it before committing. + additions.add(resource); + break; + case Differencer.DELETION: + // Outgoing deletion. 'delete' it before committing. + deletions.add(resource); + break; + case Differencer.CHANGE: + // Outgoing change. Just commit it. + break; + } + break; + case ITeamNode.CONFLICTING: + if (changed[i] instanceof TeamFile) { + toMerge.add(((TeamFile)changed[i]).getMergeResource().getSyncElement()); + } + break; } } try { RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager(); + String comment = manager.promptForComment(getShell()); + if (comment == null) { + // User cancelled. Remove the nodes from the sync set. + return null; + } if (parentCreationElements.size() > 0) { // If a node has a parent that is an incoming folder creation, we have to // create that folder locally and set its sync info before we can get the @@ -123,14 +154,52 @@ public class GetSyncAction extends MergeAction { makeInSync((IDiffElement)it.next()); } } - if (addedResources.size() > 0) { - manager.update((IResource[])addedResources.toArray(new IResource[0]), monitor); + + // Make any incoming file changes or deletions into outgoing changes before committing. + Iterator it = incoming.iterator(); + while (it.hasNext()) { + ITeamNode node = (ITeamNode)it.next(); + if (node instanceof TeamFile) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((TeamFile)node).getMergeResource().getSyncElement(); + element.makeOutgoing(monitor); + } + } + + if (additions.size() != 0) { + manager.add((IResource[])additions.toArray(new IResource[0]), monitor); } - if (changedResources.size() > 0) { - manager.get((IResource[])changedResources.toArray(new IResource[0]), monitor); + if (deletions.size() != 0) { + manager.delete((IResource[])deletions.toArray(new IResource[0]), monitor); } - } catch (TeamException e) { - ErrorDialog.openError(getShell(), null, null, e.getStatus()); + if (toMerge.size() != 0) { + manager.merged((IRemoteSyncElement[])toMerge.toArray(new IRemoteSyncElement[0])); + } + manager.commit(changedResources, comment, getShell(), monitor); + + it = incoming.iterator(); + while (it.hasNext()) { + ITeamNode node = (ITeamNode)it.next(); + if (node instanceof ChangedTeamContainer) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((ChangedTeamContainer)node).getMergeResource().getSyncElement(); + element.makeIncoming(monitor); + element.getLocal().delete(true, monitor); + } + } + + } catch (final TeamException e) { + getShell().getDisplay().syncExec(new Runnable() { + public void run() { + ErrorDialog.openError(getShell(), null, null, e.getStatus()); + } + }); + return null; + } catch (final CoreException e) { + getShell().getDisplay().syncExec(new Runnable() { + public void run() { + ErrorDialog.openError(getShell(), Policy.bind("simpleInternal"), Policy.bind("internal"), e.getStatus()); + CVSUIPlugin.log(e.getStatus()); + } + }); return null; } return syncSet; @@ -139,11 +208,12 @@ public class GetSyncAction extends MergeAction { protected void makeInSync(IDiffElement parentElement) throws TeamException { // Recursively make the parent element (and its parents) in sync. // Walk up and find the parents which need to be made in sync too. (For - // each parent that doesn't already have sync info. + // each parent that doesn't already have sync info). Vector v = new Vector(); int parentKind = parentElement.getKind(); while (((parentKind & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) && - ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING)) { + ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING) || + ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING)) { v.add(0, parentElement); parentElement = parentElement.getParent(); parentKind = parentElement == null ? 0 : parentElement.getKind(); @@ -158,34 +228,8 @@ public class GetSyncAction extends MergeAction { } } } + protected boolean isEnabled(ITeamNode node) { - int kind = node.getKind(); - if (node instanceof TeamFile) { - int direction = kind & Differencer.DIRECTION_MASK; - if (direction == ITeamNode.INCOMING || direction == Differencer.CONFLICTING) { - return true; - } - // allow to catchup outgoing deletions - return (kind & Differencer.CHANGE_TYPE_MASK) == Differencer.DELETION; - } - if (node instanceof ChangedTeamContainer) { - // first check for changes to this folder - int direction = kind & Differencer.DIRECTION_MASK; - if (direction == ITeamNode.INCOMING || direction == Differencer.CONFLICTING) { - return true; - } - // Fall through to the UnchangedTeamContainer code - } - if (node instanceof UnchangedTeamContainer) { - IDiffElement[] children = ((UnchangedTeamContainer)node).getChildren(); - for (int i = 0; i < children.length; i++) { - ITeamNode child = (ITeamNode)children[i]; - if (isEnabled(child)) { - return true; - } - } - return false; - } - return false; - } + return true; + } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/MergeAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/MergeAction.java index 9ed79bd50..3e222c997 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/MergeAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/MergeAction.java @@ -21,11 +21,13 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Shell; +import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.Policy; import org.eclipse.team.ui.sync.ChangedTeamContainer; import org.eclipse.team.ui.sync.ITeamNode; import org.eclipse.team.ui.sync.SyncSet; +import org.eclipse.team.ui.sync.SyncView; import org.eclipse.team.ui.sync.UnchangedTeamContainer; import org.eclipse.ui.actions.WorkspaceModifyOperation; @@ -49,11 +51,10 @@ abstract class MergeAction extends Action { /** * Creates a MergeAction which works on selection and doesn't commit changes. */ - public MergeAction(CVSSyncCompareInput model, ISelectionProvider sp, int direction, String label, Shell shell) { + public MergeAction(CVSSyncCompareInput model, ISelectionProvider sp, String label, Shell shell) { super(label); this.diffModel = model; this.selectionProvider = sp; - this.direction = direction; this.shell = shell; } @@ -61,6 +62,10 @@ abstract class MergeAction extends Action { return shell; } + protected CVSSyncCompareInput getDiffModel() { + return diffModel; + } + /** * Returns true if at least one node can perform the specified action. */ @@ -90,8 +95,10 @@ abstract class MergeAction extends Action { if (!(s instanceof IStructuredSelection) || s.isEmpty()) { return; } - final SyncSet set = new SyncSet((IStructuredSelection)s, direction); - set.removeNonApplicableNodes(); + final SyncSet set = new SyncSet((IStructuredSelection)s); + if (direction != 0) { + set.removeNonApplicableNodes(direction); + } final SyncSet[] result = new SyncSet[1]; WorkspaceModifyOperation op = new WorkspaceModifyOperation() { public void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { @@ -145,7 +152,19 @@ abstract class MergeAction extends Action { * Updates the action with the latest selection, setting enablement * as necessary. */ - public void update() { + public void update(int syncMode) { + switch (syncMode) { + case SyncView.SYNC_INCOMING: + case SyncView.SYNC_MERGE: + direction = IRemoteSyncElement.INCOMING; + break; + case SyncView.SYNC_OUTGOING: + direction = IRemoteSyncElement.OUTGOING; + break; + default: + direction = 0; + break; + } IStructuredSelection selection = (IStructuredSelection)selectionProvider.getSelection(); setEnabled(isEnabled(selection.toArray())); } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/UpdateSyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/UpdateSyncAction.java new file mode 100644 index 000000000..324db0f2c --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/UpdateSyncAction.java @@ -0,0 +1,321 @@ +package org.eclipse.team.internal.ccvs.ui.sync; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.compare.structuremergeviewer.Differencer; +import org.eclipse.compare.structuremergeviewer.IDiffContainer; +import org.eclipse.compare.structuremergeviewer.IDiffElement; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.team.ccvs.core.ICVSRemoteFile; +import org.eclipse.team.core.TeamException; +import org.eclipse.team.core.sync.IRemoteSyncElement; +import org.eclipse.team.internal.ccvs.core.client.Command; +import org.eclipse.team.internal.ccvs.core.client.Update; +import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; +import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement; +import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; +import org.eclipse.team.internal.ccvs.ui.Policy; +import org.eclipse.team.internal.ccvs.ui.RepositoryManager; +import org.eclipse.team.ui.sync.ChangedTeamContainer; +import org.eclipse.team.ui.sync.ITeamNode; +import org.eclipse.team.ui.sync.SyncSet; +import org.eclipse.team.ui.sync.TeamFile; + +/** + * UpdateSyncAction is run on a set of sync nodes when the "Update" menu item is performed + * in the Synchronize view. + */ +public class UpdateSyncAction extends MergeAction { + public static class ConfirmDialog extends MessageDialog { + + private boolean autoMerge = true; + private Button radio1; + private Button radio2; + + public ConfirmDialog(Shell parentShell) { + super( + parentShell, + Policy.bind("UpdateSyncAction.Conflicting_changes_found_1"), //$NON-NLS-1$ + null, // accept the default window icon + Policy.bind("UpdateSyncAction.You_have_local_changes_you_are_about_to_overwrite_2"), //$NON-NLS-1$ + MessageDialog.QUESTION, + new String[] {IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL}, + 0); // yes is the default + } + + protected Control createCustomArea(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + radio1 = new Button(composite, SWT.RADIO); + radio1.addSelectionListener(selectionListener); + + radio1.setText(Policy.bind("UpdateSyncAction.Only_update_resources_that_can_be_automatically_merged_3")); //$NON-NLS-1$ + + radio2 = new Button(composite, SWT.RADIO); + radio2.addSelectionListener(selectionListener); + + radio2.setText(Policy.bind("UpdateSyncAction.Update_all_resources,_overwriting_local_changes_with_remote_contents_4")); //$NON-NLS-1$ + + // set initial state + radio1.setSelection(autoMerge); + radio2.setSelection(!autoMerge); + + return composite; + } + + private SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + Button button = (Button)e.widget; + if (button.getSelection()) { + autoMerge = (button == radio1); + } + } + }; + + public boolean getAutomerge() { + return autoMerge; + } + } + + public UpdateSyncAction(CVSSyncCompareInput model, ISelectionProvider sp, String label, Shell shell) { + super(model, sp, label, shell); + } + + protected SyncSet run(final SyncSet syncSet, IProgressMonitor monitor) { + // If there are conflicts or outgoing changes in the syncSet, we need to warn the user. + final boolean doAutomerge[] = new boolean[] {false}; + if (syncSet.hasConflicts() || syncSet.hasOutgoingChanges()) { + final Shell shell = getShell(); + if (syncSet.hasAutoMergeableConflicts()) { + final int[] result = new int[] {Dialog.CANCEL}; + shell.getDisplay().syncExec(new Runnable() { + public void run() { + ConfirmDialog dialog = new ConfirmDialog(shell); + result[0] = dialog.open(); + doAutomerge[0] = dialog.getAutomerge(); + } + }); + if (result[0] == Dialog.CANCEL) return null; + if (doAutomerge[0]) { + syncSet.removeNonMergeableNodes(); + } + } else { + final boolean[] result = new boolean[] { false }; + shell.getDisplay().syncExec(new Runnable() { + public void run() { + result[0] = MessageDialog.openQuestion(shell, Policy.bind("UpdateSyncAction.Overwrite_local_changes__5"), Policy.bind("UpdateSyncAction.You_have_local_changes_you_are_about_to_overwrite._Do_you_wish_to_continue__6")); //$NON-NLS-1$ //$NON-NLS-2$ + } + }); + if (!result[0]) { + return null; + } + } + } + + ITeamNode[] changed = syncSet.getChangedNodes(); + if (changed.length == 0) { + return syncSet; + } + + List updateIgnoreLocalShallow = new ArrayList(); + List updateDeep = new ArrayList(); + List updateShallow = new ArrayList(); + + // A list of diff elements in the sync set which are incoming folder additions + List parentCreationElements = new ArrayList(); + // A list of diff elements in the sync set which are folder conflicts + List parentConflictElements = new ArrayList(); + // A list of the team nodes that we need to perform makeIncoming on + List makeIncoming = new ArrayList(); + // A list of diff elements that need to be unmanaged and locally deleted + List deletions = new ArrayList(); + + for (int i = 0; i < changed.length; i++) { + IDiffContainer parent = changed[i].getParent(); + if (parent != null) { + int parentKind = changed[i].getParent().getKind(); + if (((parentKind & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) && + ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING)) { + parentCreationElements.add(parent); + } else if ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING) { + parentConflictElements.add(parent); + } + } + int kind = changed[i].getKind(); + IResource resource = changed[i].getResource(); + switch (kind & Differencer.DIRECTION_MASK) { + case ITeamNode.INCOMING: + switch (kind & Differencer.CHANGE_TYPE_MASK) { + case Differencer.ADDITION: + updateIgnoreLocalShallow.add(resource); + break; + case Differencer.DELETION: + case Differencer.CHANGE: + updateDeep.add(resource); + break; + } + break; + case ITeamNode.OUTGOING: + switch (kind & Differencer.CHANGE_TYPE_MASK) { + case Differencer.ADDITION: + // Unmanage the file if necessary and delete it. + deletions.add(changed[i]); + break; + case Differencer.DELETION: + makeIncoming.add(changed[i]); + updateDeep.add(resource); + break; + case Differencer.CHANGE: + updateIgnoreLocalShallow.add(resource); + break; + } + break; + case ITeamNode.CONFLICTING: + switch (kind & Differencer.CHANGE_TYPE_MASK) { + case Differencer.ADDITION: + // To do: conflicting addition: must make incoming first + makeIncoming.add(changed[i]); + updateIgnoreLocalShallow.add(resource); + break; + case Differencer.DELETION: + // Doesn't happen, these nodes don't appear in the tree. + break; + case Differencer.CHANGE: + // Depends on the flag. + if (doAutomerge[0] && (changed[i].getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) { + updateShallow.add(resource); + } else { + updateIgnoreLocalShallow.add(resource); + } + break; + } + break; + } + } + try { + RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager(); + if (parentCreationElements.size() > 0) { + // If a node has a parent that is an incoming folder creation, we have to + // create that folder locally and set its sync info before we can get the + // node itself. We must do this for all incoming folder creations (recursively) + // in the case where there are multiple levels of incoming folder creations. + Iterator it = parentCreationElements.iterator(); + while (it.hasNext()) { + makeInSync((IDiffElement)it.next()); + } + } + if (parentConflictElements.size() > 0) { + // If a node has a parent that is a folder conflict, that means that the folder + // exists locally but has no sync info. In order to get the node, we have to + // create the sync info for the folder (and any applicable parents) before we + // get the node itself. + Iterator it = parentConflictElements.iterator(); + while (it.hasNext()) { + makeInSync((IDiffElement)it.next()); + } + } + // Make any outgoing changes or deletions into incoming changes before updating. + Iterator it = makeIncoming.iterator(); + while (it.hasNext()) { + ITeamNode node = (ITeamNode)it.next(); + if (node instanceof TeamFile) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((TeamFile)node).getMergeResource().getSyncElement(); + element.makeIncoming(monitor); + } else if (node instanceof ChangedTeamContainer) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((ChangedTeamContainer)node).getMergeResource().getSyncElement(); + element.makeIncoming(monitor); + } + } + // Outgoing additions must be unmanaged (if necessary) and locally deleted. + it = deletions.iterator(); + while (it.hasNext()) { + ITeamNode node = (ITeamNode)it.next(); + if (node instanceof TeamFile) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((TeamFile)node).getMergeResource().getSyncElement(); + element.makeIncoming(monitor); + element.getLocal().delete(true, monitor); + } else if (node instanceof ChangedTeamContainer) { + CVSRemoteSyncElement element = (CVSRemoteSyncElement)((ChangedTeamContainer)node).getMergeResource().getSyncElement(); + element.makeIncoming(monitor); + element.getLocal().delete(true, monitor); + } + } + + if (updateShallow.size() > 0) { + manager.update((IResource[])updateShallow.toArray(new IResource[0]), getLocalOptions(new Command.LocalOption[] { Command.DO_NOT_RECURSE }), false, monitor); + } + if (updateIgnoreLocalShallow.size() > 0) { + manager.update((IResource[])updateIgnoreLocalShallow.toArray(new IResource[0]), getLocalOptions(new Command.LocalOption[] { Update.IGNORE_LOCAL_CHANGES, Command.DO_NOT_RECURSE }), false, monitor); + } + if (updateDeep.size() > 0) { + manager.update((IResource[])updateDeep.toArray(new IResource[0]), getLocalOptions(Command.NO_LOCAL_OPTIONS), false, monitor); + } + } catch (TeamException e) { + ErrorDialog.openError(getShell(), null, null, e.getStatus()); + return null; + } catch (CoreException e) { + ErrorDialog.openError(getShell(), Policy.bind("simpleInternal"), Policy.bind("internal"), e.getStatus()); //$NON-NLS-1$ //$NON-NLS-2$ + CVSUIPlugin.log(e.getStatus()); + return null; + } + return syncSet; + } + protected Command.LocalOption[] getLocalOptions(Command.LocalOption[] baseOptions) { + return baseOptions; + } + + protected void makeInSync(IDiffElement parentElement) throws TeamException { + // Recursively make the parent element (and its parents) in sync. + // Walk up and find the parents which need to be made in sync too. (For + // each parent that doesn't already have sync info). + Vector v = new Vector(); + int parentKind = parentElement.getKind(); + while (((parentKind & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) && + ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING)) { + v.add(0, parentElement); + parentElement = parentElement.getParent(); + parentKind = parentElement == null ? 0 : parentElement.getKind(); + } + Iterator parentIt = v.iterator(); + while (parentIt.hasNext()) { + IDiffElement next = (IDiffElement)parentIt.next(); + if (next instanceof ChangedTeamContainer) { + CVSRemoteSyncElement syncElement = (CVSRemoteSyncElement)((ChangedTeamContainer)next).getMergeResource().getSyncElement(); + // Create the sync info + syncElement.makeInSync(new NullProgressMonitor()); + } + } + } + protected boolean isEnabled(ITeamNode node) { + return true; + } +} diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncCompareInput.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncCompareInput.java index 8da1ff5e5..76b385efb 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncCompareInput.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncCompareInput.java @@ -156,7 +156,7 @@ public abstract class SyncCompareInput extends CompareEditorInput { if (diffRoot == null) { return false; } - SyncSet set = new SyncSet(new StructuredSelection(diffRoot.getChildren()), 0); + SyncSet set = new SyncSet(new StructuredSelection(diffRoot.getChildren())); return set.hasIncomingChanges() || set.hasConflicts(); } @@ -250,7 +250,7 @@ public abstract class SyncCompareInput extends CompareEditorInput { } IDiffElement collectResourceChanges(IDiffContainer parent, IRemoteSyncElement tree, IProgressMonitor pm) { - int type = tree.getSyncKind(IRemoteSyncElement.GRANULARITY_CONTENTS, new NullProgressMonitor()); + int type = tree.getSyncKind(IRemoteSyncElement.GRANULARITY_TIMESTAMP, new NullProgressMonitor()); MergeResource mergeResource = new MergeResource(tree); if (tree.isContainer()) { @@ -358,7 +358,7 @@ public abstract class SyncCompareInput extends CompareEditorInput { statusLine.setErrorMessage(null); return; } - SyncSet set = new SyncSet(new StructuredSelection(diffRoot.getChildren()), 0); + SyncSet set = new SyncSet(new StructuredSelection(diffRoot.getChildren())); if (set.hasConflicts()) { statusLine.setMessage(null); statusLine.setErrorMessage(set.getStatusLineMessage()); diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncSet.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncSet.java index 81234ede9..c595c95c8 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncSet.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/sync/SyncSet.java @@ -25,14 +25,10 @@ import org.eclipse.team.internal.ui.Policy; public class SyncSet { private HashSet set; - // One of INCOMING or OUTGOING - private int direction; - /** * Creates a new sync set on the nodes in the given selection. */ - public SyncSet(IStructuredSelection nodeSelection, int direction) { - this.direction = direction; + public SyncSet(IStructuredSelection nodeSelection) { this.set = new HashSet(nodeSelection.size() + 1); collectNodes(nodeSelection); } @@ -54,7 +50,7 @@ public class SyncSet { private void collectParentCreations(ITeamNode node) { IDiffElement parent = node.getParent(); if (parent != null && parent instanceof ITeamNode) { - if ((parent.getKind() & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) { + if (parent.getKind() != IRemoteSyncElement.IN_SYNC) { set.add(parent); collectParentCreations((ITeamNode)parent); } @@ -173,6 +169,19 @@ public class SyncSet { } /** + * Returns true if this sync set has auto-mergeable conflicts. + */ + public boolean hasAutoMergeableConflicts() { + for (Iterator it = set.iterator(); it.hasNext();) { + ITeamNode node = (ITeamNode)it.next(); + if ((node.getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) { + return true; + } + } + return false; + } + + /** * Adds the given node, plus all its children, to the given set. */ private void recursivelyAdd(ITeamNode node) { @@ -198,22 +207,54 @@ public class SyncSet { public void removeConflictingNodes() { for (Iterator it = set.iterator(); it.hasNext();) { ITeamNode node = (ITeamNode)it.next(); - if ((node.getKind() & IRemoteSyncElement.CONFLICTING) > 0) { + if (node.getChangeDirection() == IRemoteSyncElement.CONFLICTING) { + it.remove(); + } + } + } + /** + * Removes all outgoing nodes from this set. + */ + public void removeOutgoingNodes() { + for (Iterator it = set.iterator(); it.hasNext();) { + ITeamNode node = (ITeamNode)it.next(); + if (node.getChangeDirection() == IRemoteSyncElement.OUTGOING) { + it.remove(); + } + } + } + /** + * Removes all incoming nodes from this set. + */ + public void removeIncomingNodes() { + for (Iterator it = set.iterator(); it.hasNext();) { + ITeamNode node = (ITeamNode)it.next(); + if (node.getChangeDirection() == IRemoteSyncElement.INCOMING) { + it.remove(); + } + } + } + /** + * Removes all conflicting nodes from this set that are not auto-mergeable + */ + public void removeNonMergeableNodes() { + for (Iterator it = set.iterator(); it.hasNext();) { + ITeamNode node = (ITeamNode)it.next(); + if ((node.getKind() & IRemoteSyncElement.MANUAL_CONFLICT) != 0) { it.remove(); } } } /** - * Removes all nodes that aren't applicable for the change type. + * Removes all nodes that aren't applicable for the direction. */ - public void removeNonApplicableNodes() { + public void removeNonApplicableNodes(int direction) { for (Iterator it = set.iterator(); it.hasNext();) { ITeamNode node = (ITeamNode)it.next(); int nodeDirection = node.getKind() & IRemoteSyncElement.DIRECTION_MASK; - if ((nodeDirection != IRemoteSyncElement.CONFLICTING) && (nodeDirection != direction)) { - // Deletions always belong in the set. - if ((node.getKind() & IRemoteSyncElement.CHANGE_MASK) != Differencer.DELETION) { + if (nodeDirection != IRemoteSyncElement.CONFLICTING) { + if (nodeDirection != direction) { it.remove(); } } |