blob: 3dfe6685848d60de0094fdfc2a8a5332aedc1711 [file] [log] [blame]
package org.eclipse.team.internal.ccvs.core.util;
/*
* (c) Copyright IBM Corp. 2000, 2002.
* All Rights Reserved.
*/
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.ccvs.core.CVSTeamProvider;
import org.eclipse.team.ccvs.core.ICVSFile;
import org.eclipse.team.ccvs.core.ICVSFolder;
import org.eclipse.team.core.ITeamProvider;
import org.eclipse.team.core.TeamPlugin;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
/**
* Listen for the addition of orphaned subtrees as a result of a copy or move.
*
* Listen in IResourceChangeEvent.PRE_AUTO_BUILD so that other interested parties
* (most notably, the file synchronizer) will receive up to date notifications
*/
public class ResourceDeltaSyncHandler implements IResourceDeltaVisitor {
private static IResourceChangeListener listener;
private static ResourceDeltaSyncHandler visitor;
public static IResource getResourceFor(IProject container, IResource destination, IPath originating) {
switch(destination.getType()) {
case IResource.FILE : return container.getFile(originating);
case IResource.FOLDER: return container.getFolder(originating);
case IResource.PROJECT: return ResourcesPlugin.getWorkspace().getRoot().getProject(originating.toString());
}
return destination;
}
/**
* @see IResourceDeltaVisitor#visit(IResourceDelta)
*/
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
IProject project = resource.getProject();
boolean movedTo = (delta.getFlags() & IResourceDelta.MOVED_TO) > 0;
boolean movedFrom = (delta.getFlags() & IResourceDelta.MOVED_FROM) > 0;
switch (delta.getKind()) {
case IResourceDelta.ADDED :
if (resource.getType() == IResource.FOLDER) {
return ! handleOrphanedSubtree((IContainer)resource);
} else if (resource.getType() == IResource.FILE) {
handleReplacedDeletion((IFile)resource);
}
break;
case IResourceDelta.REMOVED :
if (resource.getType() == IResource.FOLDER) {
// Only record files as there's nothing we can do about folders
} else if (resource.getType() == IResource.FILE) {
if (movedTo) {
IPath target = delta.getMovedToPath();
if (target.segment(0).equals(project.getName())) {
handleMovedFile(project, (IFile)resource, project.getFile(target.removeFirstSegments(1)));
} else {
handleDeletedFile((IFile)resource);
}
} else {
handleDeletedFile((IFile)resource);
}
}
break;
case IResourceDelta.CHANGED :
// This state means there is a resource before and after but changes were made by deleting and moving.
// For files, we shouldn'd do anything.
// For folders, we should purge the CVS info
if (resource.getType() == IResource.FOLDER) {
// When folders are moved, purge the CVS folders
if (movedFrom)
return ! handleOrphanedSubtree((IContainer)resource);
}
break;
}
return true;
}
/*
* Determine if the container is an orphaned subtree.
* If it is, handle it and return true.
* Otherwise, return false
*/
private boolean handleOrphanedSubtree(IContainer resource) {
try {
ICVSFolder mFolder = CVSWorkspaceRoot.getCVSFolderFor((IContainer)resource);
if (mFolder.isCVSFolder() && ! mFolder.isManaged() && mFolder.getParent().isCVSFolder()) {
mFolder.unmanage();
return true;
}
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
return false;
}
/*
* Mark deleted managed files as outgoing deletions
*/
private void handleDeletedFile(IFile resource) {
try {
ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
if (mFile.isManaged()) {
ResourceSyncInfo info = mFile.getSyncInfo();
if (info.isAdded()) {
mFile.unmanage();
} else {
mFile.setSyncInfo(new ResourceSyncInfo(info.getName(), info.DELETED_PREFIX + info.getRevision(), info.getTimeStamp(), info.getKeywordMode(), info.getTag(), info.getPermissions()));
}
}
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
}
/*
* Handle the case where an added file has the same name as a "cvs removed" file
* by restoring the sync info to what it was before the delete
*/
private void handleReplacedDeletion(IFile resource) {
try {
ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
if (mFile.isManaged()) {
ResourceSyncInfo info = mFile.getSyncInfo();
if (info.isDeleted()) {
mFile.setSyncInfo(new ResourceSyncInfo(info.getName(), info.getRevision(), info.getTimeStamp(), info.getKeywordMode(), info.getTag(), info.getPermissions()));
}
}
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
}
/*
* Managed new location if old location was managed.
* Also ensure that replaced deletions are handled.
*/
private void handleMovedFile(IProject project, IFile fromResource, IFile toResource) {
try {
ResourceSyncInfo fromInfo = null;
ICVSFile fromFile = CVSWorkspaceRoot.getCVSFileFor(fromResource);
// If the from file was managed mark it as an outgoing deletion
if (fromFile.isManaged()) {
fromInfo = fromFile.getSyncInfo();
if (fromInfo.isAdded()) {
fromFile.unmanage();
} else {
fromFile.setSyncInfo(new ResourceSyncInfo(fromInfo.getName(), fromInfo.DELETED_PREFIX + fromInfo.getRevision(), fromInfo.getTimeStamp(), fromInfo.getKeywordMode(), fromInfo.getTag(), fromInfo.getPermissions()));
}
}
ICVSFile toFile = CVSWorkspaceRoot.getCVSFileFor(toResource);
// If the to file is not managed, mark it as an outgoing addition
if (toFile.isManaged()) {
ResourceSyncInfo info = toFile.getSyncInfo();
if (info.isDeleted()) {
toFile.setSyncInfo(new ResourceSyncInfo(info.getName(), info.getRevision(), info.getTimeStamp(), info.getKeywordMode(), info.getTag(), info.getPermissions()));
}
} else if (fromInfo != null) {
toFile.setSyncInfo(new ResourceSyncInfo(toFile.getName(), ResourceSyncInfo.ADDED_REVISION, ResourceSyncInfo.DUMMY_TIMESTAMP, fromInfo.getKeywordMode(), fromInfo.getTag(), fromInfo.getPermissions()));
}
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
}
public static void startup() {
if (visitor == null)
visitor = new ResourceDeltaSyncHandler();
if (listener == null)
listener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
try {
IResourceDelta root = event.getDelta();
IResourceDelta[] projectDeltas = root.getAffectedChildren();
for (int i = 0; i < projectDeltas.length; i++) {
IResourceDelta delta = projectDeltas[i];
IResource resource = delta.getResource();
ITeamProvider provider = TeamPlugin.getManager().getProvider(resource);
// if a project is moved the originating project will not be associated with the CVS provider
// however listeners will probably still be interested in the move delta.
if ((delta.getFlags() & IResourceDelta.MOVED_TO) > 0) {
IResource destination = getResourceFor(resource.getProject(), resource, delta.getMovedToPath());
provider = TeamPlugin.getManager().getProvider(destination);
}
if (provider instanceof CVSTeamProvider) {
delta.accept(visitor);
}
}
} catch (CoreException e) {
Util.logError(Policy.bind("ResourceDeltaVisitor.visitError"), e);//$NON-NLS-1$
}
}
};
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_AUTO_BUILD);
}
public static void shutdown() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
}
}