Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2002-05-06 21:18:47 +0000
committerMichael Valenta2002-05-06 21:18:47 +0000
commit3eda34823265fa8cf1d115d6bb811864e6afb40c (patch)
tree9632fcf21064d6edeb1df943a8e611c020fe776e /bundles/org.eclipse.team.cvs.ui
parentdcfd4485d8b22de3eeb8a344fad6263538f7d0f0 (diff)
downloadeclipse.platform.team-3eda34823265fa8cf1d115d6bb811864e6afb40c.tar.gz
eclipse.platform.team-3eda34823265fa8cf1d115d6bb811864e6afb40c.tar.xz
eclipse.platform.team-3eda34823265fa8cf1d115d6bb811864e6afb40c.zip
Added phantoms for deleted folders with file deletion children
Diffstat (limited to 'bundles/org.eclipse.team.cvs.ui')
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSMoveDeleteHook.java364
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java2
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/OverrideUpdateMergeAction.java2
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/UpdateMergeAction.java3
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties12
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSSyncCompareInput.java41
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java262
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceCommitSyncAction.java43
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceUpdateSyncAction.java47
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/MergeAction.java131
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/UpdateSyncAction.java38
11 files changed, 286 insertions, 659 deletions
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSMoveDeleteHook.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSMoveDeleteHook.java
deleted file mode 100644
index a1f5a4231..000000000
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSMoveDeleteHook.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2002 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v0.5
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
- *
- * Contributors:
- * IBM - Initial API and implementation
- ******************************************************************************/
-
-package org.eclipse.team.internal.ccvs.ui;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IProjectDescription;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.team.IMoveDeleteHook;
-import org.eclipse.core.resources.team.IResourceTree;
-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.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
-import org.eclipse.team.internal.ccvs.core.ICVSFile;
-import org.eclipse.team.internal.ccvs.core.ICVSFolder;
-import org.eclipse.team.internal.ccvs.core.ICVSResource;
-import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
-import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
-import org.eclipse.ui.IWorkbenchWindow;
-
-public class CVSMoveDeleteHook implements IMoveDeleteHook {
-
- public interface IRunnableWithShell {
- public void run(Shell shell);
- }
-
- private void showDialog(final IRunnableWithShell runnable) {
- Display.getDefault().syncExec(new Runnable() {
- public void run() {
- IWorkbenchWindow window = CVSUIPlugin.getPlugin().getWorkbench().getActiveWorkbenchWindow();
- if (window != null) {
- runnable.run(window.getShell());
- } else {
- Display display = Display.getCurrent();
- Shell shell = new Shell(display);
- runnable.run(shell);
- }
- }
- });
- }
-
- /*
- * Delete the file and return true if an outgoing deletion will result
- * and the parent folder needs to remain
- */
- private boolean makeFileOutgoingDeletion(IResourceTree tree, IFile source, IFile destination, int updateFlags, IProgressMonitor monitor) throws CoreException {
- // Delete or move the file
- if (destination == null) {
- tree.standardDeleteFile(source, updateFlags, monitor);
- } else {
- tree.standardMoveFile(source, destination, updateFlags, monitor);
- }
- // Indicate whether the parent folder must remain for outgoing deletions
- ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(source);
- boolean mustRemain;
- try {
- mustRemain = (cvsFile.isManaged() && ! cvsFile.getSyncInfo().isAdded());
- } catch (CVSException e) {
- tree.failed(e.getStatus());
- mustRemain = true;
- }
- return mustRemain;
- }
-
- /*
- * Delete the files contained in the folder structure rooted at source.
- * Return true if at least one file has been marked as an outgoing deletion and the parent folder must remain
- */
- private boolean makeFolderOutgoingDeletion(IResourceTree tree, IFolder source, IFolder destination, int updateFlags, IProgressMonitor monitor) throws CoreException {
- boolean fileFound = false;
-
- // Create the destination for a move
- if (destination != null && ! destination.exists()) {
- destination.create(false, true, monitor);
- }
-
- // Move or delete the children
- IResource[] members = source.members();
- for (int i = 0; i < members.length; i++) {
- IResource child = members[i];
- if (child.getType() == IResource.FOLDER) {
- // Determine the corresponding destination folder
- IFolder destFolder = null;
- if (destination != null) {
- destFolder = destination.getFolder(child.getFullPath().removeFirstSegments(source.getFullPath().segmentCount()));
- }
-
- // Try to delete/move the child
- if (makeFolderOutgoingDeletion(tree, (IFolder)child, destFolder, updateFlags, monitor)) {
- fileFound = true;
- // XXX Below line commented out for now
- // tree.failed(new CVSStatus(IStatus.WARNING, CVSStatus.FOLDER_NEEDED_FOR_FILE_DELETIONS, Policy.bind("CVSMoveDeleteHook.folderDeletionFailure", resource.getFullPath().toString()))); //$NON-NLS-1$
- }
- } else if (child.getType() == IResource.FILE) {
- IFile destFile = null;
- if (destination != null) {
- destFile = destination.getFile(child.getFullPath().removeFirstSegments(source.getFullPath().segmentCount()));
- }
- fileFound = makeFileOutgoingDeletion(tree, (IFile)child, destFile, updateFlags, monitor);
- }
- }
-
- // If there were no files, delete the folder
- if ( ! fileFound) {
- try {
- ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(source);
- // We we need to check if the folder already has outgoing deletions
- ICVSResource[] files = folder.members(ICVSFolder.FILE_MEMBERS);
- for (int i = 0; i < files.length; i++) {
- ICVSFile cvsFile = (ICVSFile)files[i];
- if (cvsFile.isManaged() && ! cvsFile.getSyncInfo().isAdded()) {
- fileFound = true;
- break;
- }
- }
- // If there is still no file, we can delete the folder
- if ( ! fileFound) {
- tree.standardDeleteFolder(source, updateFlags, monitor);
- folder.unmanage(null);
- }
- } catch (CVSException e) {
- tree.failed(e.getStatus());
- }
- }
- return fileFound;
- }
-
- private boolean checkForTeamPrivate(final IResource resource) {
- if (resource.isTeamPrivateMember()) {
- showDialog(new IRunnableWithShell() {
- public void run(Shell shell) {
- ErrorDialog.openError(shell, Policy.bind("CVSMoveDeleteHook.Team_Private_Resource_1"), Policy.bind("CVSMoveDeleteHook.Deletion_of_team_private_resources_is_not_permitted_2", resource.getFullPath().toString()), null); //$NON-NLS-1$ //$NON-NLS-2$
- }
- });
- return true;
- }
- return false;
- }
-
- private boolean deleteFile(
- final IResourceTree tree,
- final IFile source,
- final IFile destination,
- final int updateFlags,
- final String title,
- final String message,
- final IProgressMonitor monitor) {
-
- if (checkForTeamPrivate(source)) {
- return true;
- }
-
- final ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(source);
- ResourceSyncInfo info = null;
- try {
- info = cvsFile.getSyncInfo();
- } catch (CVSException e) {
- }
- if (info != null && ! info.isAdded()) {
- // prompt the user for choices: Mark as outgoing deletion or cancel
- final boolean[] performDelete = new boolean[] { ! CVSProviderPlugin.getPlugin().getPromptOnFileDelete()};
- if ( ! performDelete[0]){
- showDialog(new IRunnableWithShell() {
- public void run(Shell shell) {
- AvoidableMessageDialog dialog = new AvoidableMessageDialog(
- shell,
- title,
- null, // accept the default window icon
- message,
- MessageDialog.QUESTION,
- new String[] {IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL},
- 0); // yes is the default
- performDelete[0] = dialog.open() == 0;
- if (performDelete[0]) {
- // The CVS core delta listener will mark the file as an outgoing deletion
- // so we just need to say that we didn't handle it. Core will delete the
- // file and the delta listener will do it's thing.
- CVSProviderPlugin.getPlugin().setPromptOnFileDelete( ! dialog.isDontShowAgain());
- CVSUIPlugin.getPlugin().getPreferenceStore().setValue(ICVSUIConstants.PREF_PROMPT_ON_FILE_DELETE, CVSProviderPlugin.getPlugin().getPromptOnFileDelete());
- }
- }
- });
- }
- if (performDelete[0]) {
- // Issue a delete for all child files
- // The CVS core delta listener will mark each file as an outgoing deletion
- // so we just need to delete each file and let the delta listener do its thing
- try {
- makeFileOutgoingDeletion(tree, source, destination, updateFlags, monitor);
- } catch (final CoreException e) {
- showDialog(new IRunnableWithShell() {
- public void run(Shell shell) {
- ErrorDialog.openError(shell, null, null, e.getStatus());
- }
- });
- }
- }
- return true;
- }
- return false;
- }
-
- private boolean deleteFolder(
- final IResourceTree tree,
- final IFolder source,
- final IFolder destination,
- final int updateFlags,
- final String title,
- final String message,
- final IProgressMonitor monitor) {
-
- if (checkForTeamPrivate(source)) {
- return true;
- }
-
- final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(source);
- if (cvsFolder.isManaged()) {
- // prompt the user for choices: Mark as outgoing deletion or cancel
- final boolean[] performDelete = new boolean[] { ! CVSProviderPlugin.getPlugin().getPromptOnFolderDelete()};
- boolean dialogShown = false;
- if ( ! performDelete[0]) {
- dialogShown = true;
- showDialog(new IRunnableWithShell() {
- public void run(Shell shell) {
- AvoidableMessageDialog dialog = new AvoidableMessageDialog(
- shell,
- title,
- null, // accept the default window icon
- message,
- MessageDialog.QUESTION,
- new String[] {IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL},
- 0); // yes is the default
- performDelete[0] = dialog.open() == 0;
- if (performDelete[0]) {
- CVSProviderPlugin.getPlugin().setPromptOnFolderDelete( ! dialog.isDontShowAgain());
- CVSUIPlugin.getPlugin().getPreferenceStore().setValue(ICVSUIConstants.PREF_PROMPT_ON_FOLDER_DELETE, CVSProviderPlugin.getPlugin().getPromptOnFolderDelete());
- }
- }
- });
- }
- if (performDelete[0]) {
- // Issue a delete for all child files
- // The CVS core delta listener will mark each file as an outgoing deletion
- // so we just need to delete each file and let the delta listener do its thing
- try {
- makeFolderOutgoingDeletion(tree, source, destination, updateFlags, monitor);
- } catch (final CoreException e) {
- showDialog(new IRunnableWithShell() {
- public void run(Shell shell) {
- ErrorDialog.openError(shell, null, null, e.getStatus());
- }
- });
- }
- }
- return true;
- }
- return false;
- }
-
- /**
- * @see IMoveDeleteHook#deleteFile(IResourceTree, IFile, int, IProgressMonitor)
- */
- public boolean deleteFile(
- final IResourceTree tree,
- final IFile file,
- int updateFlags,
- final IProgressMonitor monitor) {
-
- return deleteFile(tree, file, null, updateFlags,
- Policy.bind("CVSMoveDeleteHook.deleteFileTitle"), //$NON-NLS-1$
- Policy.bind("CVSMoveDeleteHook.deleteFileMessage", file.getFullPath().toString()), //$NON-NLS-1$
- monitor);
- }
-
- /**
- * @see IMoveDeleteHook#deleteFolder(IResourceTree, IFolder, int, IProgressMonitor)
- */
- public boolean deleteFolder(
- final IResourceTree tree,
- final IFolder folder,
- final int updateFlags,
- final IProgressMonitor monitor) {
-
- return deleteFolder(tree, folder, null, updateFlags,
- Policy.bind("CVSMoveDeleteHook.deleteFolderTitle"), //$NON-NLS-1$
- Policy.bind("CVSMoveDeleteHook.deleteFolderMessage", folder.getFullPath().toString()), //$NON-NLS-1$
- monitor);
- }
-
- /**
- * @see IMoveDeleteHook#deleteProject(IResourceTree, IProject, int, IProgressMonitor)
- */
- public boolean deleteProject(
- IResourceTree tree,
- IProject project,
- int updateFlags,
- IProgressMonitor monitor) {
-
- // No special action needed
- return false;
- }
-
- /**
- * @see IMoveDeleteHook#moveFile(IResourceTree, IFile, IFile, int, IProgressMonitor)
- */
- public boolean moveFile(
- IResourceTree tree,
- IFile source,
- IFile destination,
- int updateFlags,
- IProgressMonitor monitor) {
-
- return deleteFile(tree, source, destination, updateFlags,
- Policy.bind("CVSMoveDeleteHook.moveFileTitle"), //$NON-NLS-1$
- Policy.bind("CVSMoveDeleteHook.moveFileMessage", source.getFullPath().toString()), //$NON-NLS-1$
- monitor);
- }
-
- /**
- * @see IMoveDeleteHook#moveFolder(IResourceTree, IFolder, IFolder, int, IProgressMonitor)
- */
- public boolean moveFolder(
- IResourceTree tree,
- IFolder source,
- IFolder destination,
- int updateFlags,
- IProgressMonitor monitor) {
-
- return deleteFolder(tree, source, destination, updateFlags,
- Policy.bind("CVSMoveDeleteHook.moveFolderTitle"), //$NON-NLS-1$
- Policy.bind("CVSMoveDeleteHook.moveFolderMessage", source.getFullPath().toString()), //$NON-NLS-1$
- monitor);
- }
-
- /**
- * @see IMoveDeleteHook#moveProject(IResourceTree, IProject, IProjectDescription, int, IProgressMonitor)
- */
- public boolean moveProject(
- IResourceTree tree,
- IProject source,
- IProjectDescription description,
- int updateFlags,
- IProgressMonitor monitor) {
-
- // No special action
- return false;
- }
-}
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 d6973e23f..b38e70b24 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
@@ -322,8 +322,6 @@ public class CVSUIPlugin extends AbstractUIPlugin {
throw new CoreException(e.getStatus());
}
- CVSTeamProvider.setMoveDeleteHook(new CVSMoveDeleteHook());
-
Console.startup();
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/OverrideUpdateMergeAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/OverrideUpdateMergeAction.java
index 098f1a364..151e7625f 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/OverrideUpdateMergeAction.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/merge/OverrideUpdateMergeAction.java
@@ -26,6 +26,6 @@ public class OverrideUpdateMergeAction extends UpdateMergeAction {
protected boolean isEnabled(ITeamNode node) {
// The force update action is enabled only for conflicting and outgoing changes
SyncSet set = new SyncSet(new StructuredSelection(node));
- return set.hasConflicts();
+ return (set.hasConflicts() && hasRealChanges(node, new int[] { ITeamNode.CONFLICTING }));
}
}
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
index 781ad44b3..0512945ed 100644
--- 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
@@ -119,7 +119,8 @@ public class UpdateMergeAction extends UpdateSyncAction {
if(!local.exists()) {
((IFolder)local).create(false /*don't force*/, true /*local*/, monitor);
}
- CVSWorkspaceRoot.getCVSFolderFor((IContainer)local).setFolderSyncInfo(((ICVSFolder)remote).getFolderSyncInfo());
+ // XXX This copies the tag from the remote (which is a branch tag)!!!
+ // CVSWorkspaceRoot.getCVSFolderFor((IContainer)local).setFolderSyncInfo(((ICVSFolder)remote).getFolderSyncInfo());
} else {
monitor.beginTask(null, 200);
try {
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 2a7a48ba9..5415dc74d 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
@@ -128,18 +128,6 @@ CVSFolderPropertiesPage.repository=Repository Path:
CVSFolderPropertiesPage.static=Static:
CVSLocalCompareEditorInput.title=CVS Compare [{0}]
-
-CVSMoveDeleteHook.deleteFileTitle=Deletion of CVS Controlled File
-CVSMoveDeleteHook.deleteFileMessage=File ''{0}'' is under CVS control. In order to properly communicate the deletion to CVS, this file will be marked as an outgoing deletion.
-CVSMoveDeleteHook.moveFileTitle=Move of CVS Controlled File
-CVSMoveDeleteHook.moveFileMessage =File ''{0}'' is under CVS control. A move results in the deletion of the file at its old location. In order to properly communicate this deletion to CVS, it will be marked as an outgoing deletion.
-CVSMoveDeleteHook.deleteFolderTitle=Deletion of CVS Controlled Folder
-CVSMoveDeleteHook.deleteFolderMessage=Folder ''{0}'' is under CVS control. Files are marked as outgoing deletions. The deletion of the folder and any subfolders will be postponed until you commit the file deletions.
-CVSMoveDeleteHook.moveFolderTitle=Move of CVS Controlled Folder
-CVSMoveDeleteHook.moveFolderMessage=Folder ''{0}'' is under CVS control. A move results in the deletion of the folder from its old location. In order to properly communicate this deletion to CVS, the old folder and any subfolders will remain and files contained in this folder will be marked as outgoing deletions. Any empty folders will be pruned when the deletions are committed.
-CVSMoveDeleteHook.Team_Private_Resource_1=Team Private Resource
-CVSMoveDeleteHook.Deletion_of_team_private_resources_is_not_permitted_2=Deletion of team private resource ''{0}'' is not permitted
-CVSMoveDeleteHook.folderDeletionFailure=Folder ''{0}'' was not deleted in order to properly communicate file deletions to CVS
CVSOperationCancelledException.operationCancelled=Operation Cancelled
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSSyncCompareInput.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSSyncCompareInput.java
index 54b3cf1b5..7c63f0998 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSSyncCompareInput.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSSyncCompareInput.java
@@ -7,7 +7,10 @@ package org.eclipse.team.internal.ccvs.ui.sync;
import java.lang.reflect.InvocationTargetException;
+import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
+import org.eclipse.compare.structuremergeviewer.IDiffContainer;
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
@@ -30,6 +33,7 @@ import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants;
import org.eclipse.team.internal.ccvs.ui.Policy;
import org.eclipse.team.internal.ui.sync.CatchupReleaseViewer;
import org.eclipse.team.internal.ui.sync.ChangedTeamContainer;
+import org.eclipse.team.internal.ui.sync.ITeamNode;
import org.eclipse.team.internal.ui.sync.SyncCompareInput;
import org.eclipse.team.internal.ui.sync.TeamFile;
@@ -243,4 +247,41 @@ public class CVSSyncCompareInput extends SyncCompareInput {
return result[0];
}
+
+ /**
+ * Adjust the sync info (to conflicting change) for locally deleted
+ * folders (i.e. outgoing folder deletions)
+ * that have incoming or conflicting changes in one or more children.
+ *
+ * @see MergeAction#removeNodes(ITeamNode[])
+ */
+ protected IDiffElement collectResourceChanges(IDiffContainer parent, IRemoteSyncElement tree, IProgressMonitor pm) {
+ IDiffElement element = super.collectResourceChanges(parent, tree, pm);
+ int kind = element.getKind();
+ if ((element instanceof ChangedTeamContainer)
+ && ((kind & Differencer.CHANGE_TYPE_MASK) == Differencer.DELETION)
+ && ((kind & Differencer.DIRECTION_MASK) == ITeamNode.OUTGOING)) {
+ // Check the children to see if there are any incomming changes
+ if (hasIncomingChanges((ChangedTeamContainer)element)) {
+ ((ChangedTeamContainer)element).setKind(ITeamNode.CONFLICTING | Differencer.CHANGE);
+ }
+ }
+ return element;
+ }
+
+ private boolean hasIncomingChanges(ChangedTeamContainer container) {
+ IDiffElement[] children = container.getChildren();
+ for (int i = 0; i < children.length; i++) {
+ IDiffElement element = children[i];
+ int direction = element.getKind() & Differencer.DIRECTION_MASK;
+ if (direction == ITeamNode.CONFLICTING || direction == ITeamNode.INCOMING) {
+ return true;
+ }
+ if (element instanceof ChangedTeamContainer) {
+ boolean hasIncomingChanges = hasIncomingChanges((ChangedTeamContainer)element);
+ if (hasIncomingChanges) return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java
index e740e4a23..bc8fa91f2 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CommitSyncAction.java
@@ -1,26 +1,16 @@
-package org.eclipse.team.internal.ccvs.ui.sync;
+/*******************************************************************************
+ * Copyright (c) 2000, 2002 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM - Initial API and implementation
+ ******************************************************************************/
-/*
- * (c) Copyright IBM Corp. 2000, 2002.
- * All Rights Reserved.
- */
+package org.eclipse.team.internal.ccvs.ui.sync;
-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.IFile;
-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;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Shell;
@@ -37,239 +27,17 @@ import org.eclipse.team.internal.ui.sync.ITeamNode;
import org.eclipse.team.internal.ui.sync.SyncSet;
import org.eclipse.team.internal.ui.sync.TeamFile;
-public class CommitSyncAction extends MergeAction {
+/**
+ * Override ForceCommitSyncAction to only work on outgoing nodes
+ */
+public class CommitSyncAction extends ForceCommitSyncAction {
public CommitSyncAction(CVSSyncCompareInput model, ISelectionProvider sp, String label, Shell shell) {
super(model, sp, label, shell);
}
- protected SyncSet run(SyncSet syncSet, IProgressMonitor monitor) {
- boolean result = saveIfNecessary();
- if (!result) return null;
-
- // If there is a conflict in the syncSet, we need to prompt the user before proceeding.
- if (syncSet.hasConflicts() || syncSet.hasIncomingChanges()) {
- switch (promptForConflicts(syncSet)) {
- case 0:
- // Yes, synchronize conflicts as well
- break;
- case 1:
- // No, only synchronize non-conflicting changes.
- syncSet.removeConflictingNodes();
- syncSet.removeIncomingNodes();
- 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 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();
- 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);
- }
- }
- 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 = promptForComment(manager);
- 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
- // 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 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 (deletions.size() != 0) {
- manager.delete((IResource[])deletions.toArray(new IResource[0]), monitor);
- }
- if (toMerge.size() != 0) {
- manager.merged((IRemoteSyncElement[])toMerge.toArray(new IRemoteSyncElement[0]));
- }
- manager.commit(changedResources, comment, 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);
- }
- }
-
- // Reset the timestamps for any files that were not committed
- // because their contents match that of the server
- for (int i = 0; i < changedResources.length; i++) {
- IResource resource = changedResources[i];
- if (resource.getType() == IResource.FILE) {
- ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
- // If the file is still modified after the commit, it probably is a pseudo change
- if (cvsFile.exists() && cvsFile.isModified()) {
- cvsFile.setTimeStamp(cvsFile.getSyncInfo().getTimeStamp());
- }
- }
- }
-
- } 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()); //$NON-NLS-1$ //$NON-NLS-2$
- CVSUIPlugin.log(e.getStatus());
- }
- });
- return null;
- }
- return syncSet;
- }
-
- 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) ||
- ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING)) {
- 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) {
// The commit action is enabled only for non-conflicting outgoing changes
return new SyncSet(new StructuredSelection(node)).hasOutgoingChanges();
- }
-
- /**
- * Prompts the user to determine how conflicting changes should be handled.
- * Note: This method is designed to be overridden by test cases.
- * @return 0 to sync conflicts, 1 to sync all non-conflicts, 2 to cancel
- */
- protected int promptForConflicts(SyncSet syncSet) {
- String[] buttons = new String[] {IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL};
- String question = Policy.bind("CommitSyncAction.questionRelease"); //$NON-NLS-1$
- String title = Policy.bind("CommitSyncAction.titleRelease"); //$NON-NLS-1$
- String[] tips = new String[] {
- Policy.bind("CommitSyncAction.releaseAll"), //$NON-NLS-1$
- Policy.bind("CommitSyncAction.releasePart"), //$NON-NLS-1$
- Policy.bind("CommitSyncAction.cancelRelease") //$NON-NLS-1$
- };
- 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();
- }
- });
- return dialog.getReturnCode();
- }
-
- /**
- * Prompts the user for a release comment.
- * Note: This method is designed to be overridden by test cases.
- * @return the comment, or null to cancel
- */
- protected String promptForComment(RepositoryManager manager) {
- return manager.promptForComment(getShell());
}
protected void removeNonApplicableNodes(SyncSet set, int syncMode) {
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceCommitSyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceCommitSyncAction.java
index 8631bdacb..86fbc8589 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceCommitSyncAction.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceCommitSyncAction.java
@@ -1,9 +1,15 @@
-package org.eclipse.team.internal.ccvs.ui.sync;
+/*******************************************************************************
+ * Copyright (c) 2000, 2002 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM - Initial API and implementation
+ ******************************************************************************/
-/*
- * (c) Copyright IBM Corp. 2000, 2002.
- * All Rights Reserved.
- */
+package org.eclipse.team.internal.ccvs.ui.sync;
import java.util.ArrayList;
import java.util.HashSet;
@@ -15,6 +21,7 @@ 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.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
@@ -26,6 +33,7 @@ import org.eclipse.jface.viewers.StructuredSelection;
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.ICVSFile;
import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
@@ -67,7 +75,7 @@ public class ForceCommitSyncAction extends MergeAction {
if (changed.length == 0) {
return syncSet;
}
- IResource[] changedResources = new IResource[changed.length];
+ List commits = new ArrayList();
List additions = new ArrayList();
List deletions = new ArrayList();
List toMerge = new ArrayList();
@@ -79,9 +87,11 @@ public class ForceCommitSyncAction extends MergeAction {
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();
+ if (resource.getType() == resource.FILE) {
+ commits.add(resource);
+ }
IDiffContainer parent = changed[i].getParent();
if (parent != null) {
int parentKind = changed[i].getParent().getKind();
@@ -180,7 +190,20 @@ public class ForceCommitSyncAction extends MergeAction {
if (toMerge.size() != 0) {
manager.merged((IRemoteSyncElement[])toMerge.toArray(new IRemoteSyncElement[0]));
}
- manager.commit(changedResources, comment, monitor);
+ manager.commit((IResource[])commits.toArray(new IResource[commits.size()]), comment, monitor);
+
+ // Reset the timestamps for any files that were not committed
+ // because their contents match that of the server
+ for (Iterator iter = commits.iterator(); iter.hasNext(); ) {
+ IResource resource = (IResource)iter.next();
+ if (resource.getType() == IResource.FILE) {
+ ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
+ // If the file is still modified after the commit, it probably is a pseudo change
+ if (cvsFile.exists() && cvsFile.isModified()) {
+ cvsFile.setTimeStamp(cvsFile.getSyncInfo().getTimeStamp());
+ }
+ }
+ }
} catch (final TeamException e) {
getShell().getDisplay().syncExec(new Runnable() {
@@ -222,9 +245,9 @@ public class ForceCommitSyncAction extends MergeAction {
// The force commit action is enabled only for conflicting and incoming changes
SyncSet set = new SyncSet(new StructuredSelection(node));
if (syncMode == SyncView.SYNC_OUTGOING) {
- return set.hasConflicts();
+ return (set.hasConflicts() && hasRealChanges(node, new int[] { ITeamNode.CONFLICTING }));
} else {
- return set.hasIncomingChanges() || set.hasConflicts();
+ return ((set.hasIncomingChanges() || set.hasConflicts()) && hasRealChanges(node, new int[] { ITeamNode.CONFLICTING, ITeamNode.INCOMING }));
}
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceUpdateSyncAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceUpdateSyncAction.java
index 569469c94..f33f0f209 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceUpdateSyncAction.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/ForceUpdateSyncAction.java
@@ -36,9 +36,11 @@ import org.eclipse.swt.widgets.Control;
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.ICVSFolder;
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.resources.CVSRemoteSyncElement;
+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.internal.ccvs.ui.RepositoryManager;
@@ -145,6 +147,8 @@ public class ForceUpdateSyncAction extends MergeAction {
Set parentCreationElements = new HashSet();
// A list of diff elements in the sync set which are folder conflicts
Set parentConflictElements = new HashSet();
+ // A list of diff elements in the sync set which are outgoing folder deletions
+ Set parentDeletionElements = new HashSet();
// 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
@@ -157,6 +161,8 @@ public class ForceUpdateSyncAction extends MergeAction {
if (((parentKind & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) &&
((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING)) {
parentCreationElements.add(parent);
+ } else if (isLocallyDeletedFolder(parent)) {
+ parentDeletionElements.add(parent);
} else if ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING) {
parentConflictElements.add(parent);
}
@@ -182,8 +188,10 @@ public class ForceUpdateSyncAction extends MergeAction {
deletions.add(changed[i]);
break;
case Differencer.DELETION:
- makeIncoming.add(changed[i]);
- updateDeep.add(resource);
+ if (resource.getType() == IResource.FILE) {
+ makeIncoming.add(changed[i]);
+ updateDeep.add(resource);
+ }
break;
case Differencer.CHANGE:
updateIgnoreLocalShallow.add(resource);
@@ -205,14 +213,20 @@ public class ForceUpdateSyncAction extends MergeAction {
// Doesn't happen, these nodes don't appear in the tree.
break;
case Differencer.CHANGE:
- // Depends on the flag.
- if (onlyUpdateAutomergeable && (changed[i].getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) {
- updateShallow.add(resource);
- } else {
- updateIgnoreLocalShallow.add(resource);
- if (!resource.exists()) {
- makeIncoming.add(changed[i]);
+ if (resource.getType() == IResource.FILE) {
+ // Depends on the flag.
+ if (onlyUpdateAutomergeable && (changed[i].getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) {
+ updateShallow.add(resource);
+ } else {
+ updateIgnoreLocalShallow.add(resource);
+ if (!resource.exists()) {
+ makeIncoming.add(changed[i]);
+ }
}
+ } else {
+ // Conflicting change on a folder only occurs if the folder has been deleted locally
+ // The folder should only be recreated if there were children in the changed set.
+ // Such folders would have been added to the parentDeletionElements set above
}
break;
}
@@ -225,6 +239,16 @@ public class ForceUpdateSyncAction extends MergeAction {
monitor.beginTask(null, work);
RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager();
+ if (parentDeletionElements.size() > 0) {
+ // If a node has a parent that is an outgoing folder deletion, we have to
+ // recreate that folder locally (it's sync info already exists locally).
+ // We must do this for all outgoing folder deletions (recursively)
+ // in the case where there are multiple levels of outgoing folder deletions.
+ Iterator it = parentDeletionElements.iterator();
+ while (it.hasNext()) {
+ recreateLocallyDeletedFolder((IDiffElement)it.next());
+ }
+ }
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
@@ -328,13 +352,14 @@ public class ForceUpdateSyncAction extends MergeAction {
}
}
}
+
protected boolean isEnabled(ITeamNode node) {
// The force update action is enabled only for conflicting and outgoing changes
SyncSet set = new SyncSet(new StructuredSelection(node));
if (syncMode == SyncView.SYNC_INCOMING) {
- return set.hasConflicts();
+ return (set.hasConflicts() && hasRealChanges(node, new int[] { ITeamNode.CONFLICTING }));
} else {
- return set.hasOutgoingChanges() || set.hasConflicts();
+ return ((set.hasOutgoingChanges() || set.hasConflicts()) && hasRealChanges(node, new int[] { ITeamNode.CONFLICTING, ITeamNode.OUTGOING }));
}
}
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 73a019319..5836bbadb 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
@@ -6,7 +6,11 @@ package org.eclipse.team.internal.ccvs.ui.sync;
*/
import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.runtime.CoreException;
@@ -21,6 +25,10 @@ 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.TeamException;
+import org.eclipse.team.internal.ccvs.core.ICVSFolder;
+import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement;
+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.internal.ui.sync.ChangedTeamContainer;
@@ -119,9 +127,16 @@ abstract class MergeAction extends Action {
/**
* The given nodes have been synchronized. Remove them from
* the sync set.
+ *
+ * For folders that are outgoing deletions, we may need to leave the
+ * folder as is or adjust the sync kind depending on the sync kind of
+ * the folder's children.
+ *
+ * @see CVSSyncCompareInput#collectResourceChanges(IDiffContainer, IRemoteSyncElement, IProgressMonitor)
*/
private void removeNodes(final ITeamNode[] nodes) {
// Update the model
+ Set outgoingFolderDeletions = new HashSet();
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].getClass() == UnchangedTeamContainer.class) {
// Unchanged containers get removed automatically when all
@@ -135,18 +150,32 @@ abstract class MergeAction extends Action {
ChangedTeamContainer container = (ChangedTeamContainer)nodes[i];
IDiffElement[] children = container.getChildren();
if (children.length > 0) {
- IDiffContainer parent = container.getParent();
- UnchangedTeamContainer unchanged = new UnchangedTeamContainer(parent, container.getResource());
- for (int j = 0; j < children.length; j++) {
- unchanged.add(children[j]);
+ if (isLocallyDeletedFolder(container)) {
+ // For locally deleted folders, we postpone the handling until all other children are removed
+ outgoingFolderDeletions.add(container);
+ } else {
+ IDiffContainer parent = container.getParent();
+ UnchangedTeamContainer unchanged = new UnchangedTeamContainer(parent, container.getResource());
+ for (int j = 0; j < children.length; j++) {
+ unchanged.add(children[j]);
+ }
+ parent.removeToRoot(container);
}
- parent.removeToRoot(container);
continue;
}
// No children, it will get removed below.
+ } else if (nodes[i].getParent().getClass() == ChangedTeamContainer.class) {
+ // If the parent is a locally deleted folder, we may want to update it's sync state as well
+ if (isLocallyDeletedFolder(nodes[i].getParent())) {
+ outgoingFolderDeletions.add(nodes[i].getParent());
+ }
}
nodes[i].getParent().removeToRoot(nodes[i]);
}
+ // Remove any locally deleted folders from the sync tree as appropriate
+ for (Iterator iter = outgoingFolderDeletions.iterator(); iter.hasNext();) {
+ removeLocallyDeletedFolder((ChangedTeamContainer)iter.next());
+ }
}
/**
@@ -193,4 +222,96 @@ abstract class MergeAction extends Action {
protected boolean saveIfNecessary() {
return getDiffModel().saveIfNecessary();
}
+
+ /**
+ * Answer true if the given diff element represents a locally deleted CVS folder.
+ * The sync state of locally deleted CVS folders is either outgoing deletion or
+ * conflicting change.
+ */
+ protected boolean isLocallyDeletedFolder(IDiffElement element) {
+ if ( ! (element.getType() == IDiffElement.FOLDER_TYPE)) return false;
+ int kind = element.getKind();
+ return (((kind & Differencer.CHANGE_TYPE_MASK) == Differencer.DELETION) &&
+ ((kind & Differencer.DIRECTION_MASK) == ITeamNode.OUTGOING))
+ || (((kind & Differencer.CHANGE_TYPE_MASK) == Differencer.CHANGE) &&
+ ((kind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING));
+ }
+
+ /**
+ * Recreate any parents that are outgoing folder deletions
+ */
+ protected void recreateLocallyDeletedFolder(IDiffElement element) 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).
+ if (element == null) return;
+ if (element instanceof ChangedTeamContainer) {
+ CVSRemoteSyncElement syncElement = (CVSRemoteSyncElement)((ChangedTeamContainer)element).getMergeResource().getSyncElement();
+ // recreate the folder
+ ICVSFolder cvsFolder = (ICVSFolder) CVSWorkspaceRoot.getCVSResourceFor(syncElement.getLocal());
+ if (! cvsFolder.exists()) {
+ recreateLocallyDeletedFolder(element.getParent());
+ cvsFolder.mkdir();
+ syncElement.makeInSync(Policy.monitorFor(null));
+ ((ChangedTeamContainer)element).makeInSync();
+ }
+ }
+ }
+
+ /**
+ * Adjust the sync kind of the locally deleted folder and remove
+ * the folder if it doesn't contain any real changes
+ */
+ private void removeLocallyDeletedFolder(ChangedTeamContainer container) {
+ boolean hasIncoming = hasRealChanges(container, new int[] { ITeamNode.INCOMING });
+ boolean hasOutgoing = hasRealChanges(container, new int[] { ITeamNode.OUTGOING });
+ boolean hasConflicting = hasRealChanges(container, new int[] { ITeamNode.CONFLICTING });
+ IDiffContainer parent = container.getParent();
+ if (hasConflicting || (hasOutgoing && hasIncoming)) {
+ // Leave as a conflict
+ return;
+ } else if (hasOutgoing) {
+ // Convert to an outgoing deletion
+ container.setKind(ITeamNode.OUTGOING | Differencer.DELETION);
+ } else if (hasIncoming) {
+ container.setKind(ITeamNode.INCOMING | Differencer.ADDITION);
+ } else {
+ // The folder is empty, remove it
+ if (parent != null) {
+ parent.removeToRoot(container);
+ }
+ }
+ // The parent may need adjusting as well
+ if (parent != null && isLocallyDeletedFolder(parent)) {
+ removeLocallyDeletedFolder((ChangedTeamContainer)parent);
+ }
+ }
+
+ /**
+ * Look for real changes of the given type. Real changes are those that
+ * are not locally deleted folders that are persisted as phantoms
+ * to report local file deletions to the server.
+ */
+ protected boolean hasRealChanges(IDiffElement node, int[] changeDirections) {
+ // For regular nodes (i.e. not local folder deletions), check the sync kind of the node
+ if ( ! isLocallyDeletedFolder(node)) {
+ int direction = node.getKind() & Differencer.DIRECTION_MASK;
+ for (int i = 0; i < changeDirections.length; i++) {
+ if (direction == changeDirections[i]) {
+ return true;
+ }
+ }
+ }
+ // For folders, check their children (if we didn't get a match above)
+ if (node.getType() == node.FOLDER_TYPE) {
+ IDiffElement[] children = ((IDiffContainer)node).getChildren();
+ for (int i = 0; i < children.length; i++) {
+ if (hasRealChanges(children[i], changeDirections)) {
+ return true;
+ }
+ }
+ }
+ // If no matches occured above, we don't have any "real" changes in the given directions
+ return false;
+ }
}
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
index 9724097a8..1f4ca49fa 100644
--- 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
@@ -49,6 +49,9 @@ import org.eclipse.team.internal.ui.sync.SyncSet;
/**
* UpdateSyncAction is run on a set of sync nodes when the "Update" menu item is performed
* in the Synchronize view.
+ *
+ * This class is also used as the super class of the merge update actions for regular and forced
+ * update.
*/
public class UpdateSyncAction extends MergeAction {
public static class ConfirmDialog extends MessageDialog {
@@ -143,6 +146,8 @@ public class UpdateSyncAction extends MergeAction {
Set parentCreationElements = new HashSet();
// A list of diff elements in the sync set which are folder conflicts
Set parentConflictElements = new HashSet();
+ // A list of diff elements in the sync set which are outgoing folder deletions
+ Set parentDeletionElements = new HashSet();
// 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
@@ -155,11 +160,14 @@ public class UpdateSyncAction extends MergeAction {
if (((parentKind & Differencer.CHANGE_TYPE_MASK) == Differencer.ADDITION) &&
((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.INCOMING)) {
parentCreationElements.add(parent);
+ } else if (isLocallyDeletedFolder(parent)) {
+ parentDeletionElements.add(parent);
} else if ((parentKind & Differencer.DIRECTION_MASK) == ITeamNode.CONFLICTING) {
parentConflictElements.add(parent);
}
}
ITeamNode changedNode = changed[i];
+ IResource resource = changedNode.getResource();
int kind = changedNode.getKind();
switch (kind & Differencer.DIRECTION_MASK) {
case ITeamNode.INCOMING:
@@ -180,8 +188,10 @@ public class UpdateSyncAction extends MergeAction {
deletions.add(changedNode);
break;
case Differencer.DELETION:
- makeIncoming.add(changedNode);
- updateDeep.add(changedNode);
+ if (resource.getType() == IResource.FILE) {
+ makeIncoming.add(changedNode);
+ updateDeep.add(changedNode);
+ }
break;
case Differencer.CHANGE:
updateIgnoreLocalShallow.add(changedNode);
@@ -203,11 +213,17 @@ public class UpdateSyncAction extends MergeAction {
// Doesn't happen, these nodes don't appear in the tree.
break;
case Differencer.CHANGE:
- // Depends on the flag.
- if (onlyUpdateAutomergeable && (changedNode.getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) {
- updateShallow.add(changedNode);
+ if (resource.getType() == IResource.FILE) {
+ // Depends on the flag.
+ if (onlyUpdateAutomergeable && (changedNode.getKind() & IRemoteSyncElement.AUTOMERGE_CONFLICT) != 0) {
+ updateShallow.add(changedNode);
+ } else {
+ updateIgnoreLocalShallow.add(changedNode);
+ }
} else {
- updateIgnoreLocalShallow.add(changedNode);
+ // Conflicting change on a folder only occurs if the folder has been deleted locally
+ // The folder should only be recreated if there were children in the changed set.
+ // Such folders would have been added to the parentDeletionElements set above
}
break;
}
@@ -220,6 +236,16 @@ public class UpdateSyncAction extends MergeAction {
monitor.beginTask(null, work);
RepositoryManager manager = CVSUIPlugin.getPlugin().getRepositoryManager();
+ if (parentDeletionElements.size() > 0) {
+ // If a node has a parent that is an outgoing folder deletion, we have to
+ // recreate that folder locally (it's sync info already exists locally).
+ // We must do this for all outgoing folder deletions (recursively)
+ // in the case where there are multiple levels of outgoing folder deletions.
+ Iterator it = parentDeletionElements.iterator();
+ while (it.hasNext()) {
+ recreateLocallyDeletedFolder((IDiffElement)it.next());
+ }
+ }
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

Back to the top