blob: 1f10296c37fc67109a304fe13e8080f2e4a80025 [file] [log] [blame]
package org.eclipse.team.internal.ccvs.ui;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.ccvs.core.CVSTag;
import org.eclipse.team.ccvs.core.CVSTeamProvider;
import org.eclipse.team.ccvs.core.ICVSRepositoryLocation;
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.resources.ICVSFile;
import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.resources.ICVSResource;
import org.eclipse.team.internal.ccvs.core.resources.LocalFile;
import org.eclipse.team.internal.ccvs.core.resources.LocalFolder;
import org.eclipse.team.internal.ccvs.core.syncinfo.*;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.ui.ISharedImages;
import org.eclipse.team.ui.TeamUIPlugin;
/**
* Performs the decoration calculation for elements made available via the decoration notifier.
*/
public class CVSDecorationRunnable implements Runnable {
// Images cached for better performance
private ImageDescriptor dirty;
private ImageDescriptor checkedIn;
private ImageDescriptor checkedOut;
// Provides resources to be decorated and is notified when decoration has been calculated
private IDecorationNotifier notifier;
/*
* Define a cached image descriptor which only creates the image data once
*/
public class CachedImageDescriptor extends ImageDescriptor {
ImageDescriptor descriptor;
ImageData data;
public CachedImageDescriptor(ImageDescriptor descriptor) {
this.descriptor = descriptor;
}
public ImageData getImageData() {
if (data == null) {
data = descriptor.getImageData();
}
return data;
}
}
/* package */
CVSDecorationRunnable(IDecorationNotifier notifier) {
dirty = new CachedImageDescriptor(TeamUIPlugin.getPlugin().getImageDescriptor(ISharedImages.IMG_DIRTY_OVR));
checkedIn = new CachedImageDescriptor(TeamUIPlugin.getPlugin().getImageDescriptor(ISharedImages.IMG_CHECKEDIN_OVR));
checkedOut = new CachedImageDescriptor(TeamUIPlugin.getPlugin().getImageDescriptor(ISharedImages.IMG_CHECKEDOUT_OVR));
this.notifier = notifier;
}
/*
* @see Runnable#run()
*/
public void run() {
while (true) {
// will block if there are no resources to be decorated
IResource resource = notifier.next();
// if next() returned null, we are done and should shut down.
if (resource == null) {
return;
}
// it is possible that the resource to be decorated is no longer associated
// with a CVS provider. This could happen if the team nature was removed
// between the time the decoration event was posted to the thread and the time
// the thread processes the decoration.
ITeamProvider provider = TeamPlugin.getManager().getProvider(resource);
if(!resource.exists() || provider==null || !(provider instanceof CVSTeamProvider)) {
continue;
}
// determine a if resource has outgoing changes (e.g. is dirty).
IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
boolean isDirty = false;
boolean computeDeepDirtyCheck = store.getBoolean(ICVSUIConstants.PREF_CALCULATE_DIRTY);
int type = resource.getType();
if(type == IResource.FILE || computeDeepDirtyCheck) {
isDirty = isDirty(resource);
}
// compute decorations
CVSDecoration decoration = computeTextLabelFor(resource, isDirty, provider);
decoration.setOverlays(computeLabelOverlaysFor(resource, isDirty, provider));
// notify that decoration is ready
notifier.decorated(resource, decoration);
}
}
private CVSDecoration computeTextLabelFor(IResource resource, boolean isDirty, ITeamProvider provider) {
Map bindings = new HashMap(3);
String format = ""; //$NON-NLS-1$
IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
IPath resourceLocation = resource.getLocation();
int type = resource.getType();
// if the resource does not have a location then return. This can happen if the resource
// has been deleted after we where asked to decorate it.
if(resourceLocation==null) {
return new CVSDecoration(format, bindings, null);
}
if(type==IResource.FOLDER) {
format = store.getString(ICVSUIConstants.PREF_FOLDERTEXT_DECORATION);
} else if(type==IResource.PROJECT) {
format = store.getString(ICVSUIConstants.PREF_PROJECTTEXT_DECORATION);
} else {
format = store.getString(ICVSUIConstants.PREF_FILETEXT_DECORATION);
}
if(isDirty) {
bindings.put(CVSDecoratorConfiguration.DIRTY_FLAG, store.getString(ICVSUIConstants.PREF_DIRTY_FLAG));
}
try {
switch (type) {
case IResource.FOLDER :
case IResource.PROJECT :
ICVSFolder folder = new LocalFolder(resourceLocation.toFile());
FolderSyncInfo folderInfo = folder.getFolderSyncInfo();
if (folderInfo != null) {
CVSTag tag = folderInfo.getTag();
if(tag!=null) {
bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, tag.getName());
}
ICVSRepositoryLocation location = CVSProviderPlugin.getProvider().getRepository(folderInfo.getRoot());
bindings.put(CVSDecoratorConfiguration.REMOTELOCATION_HOST, location.getHost());
bindings.put(CVSDecoratorConfiguration.REMOTELOCATION_METHOD, location.getMethod().getName());
bindings.put(CVSDecoratorConfiguration.REMOTELOCATION_USER, location.getUsername());
bindings.put(CVSDecoratorConfiguration.REMOTELOCATION_ROOT, location.getRootDirectory());
bindings.put(CVSDecoratorConfiguration.REMOTELOCATION_REPOSITORY, folderInfo.getRepository());
}
break;
case IResource.FILE :
format = store.getString(ICVSUIConstants.PREF_FILETEXT_DECORATION);
ICVSFile file = new LocalFile(resourceLocation.toFile());
ResourceSyncInfo fileInfo = file.getSyncInfo();
if (fileInfo != null) {
CVSTag tag = fileInfo.getTag();
if(fileInfo.isAdded()) {
bindings.put(CVSDecoratorConfiguration.ADDED_FLAG, store.getString(ICVSUIConstants.PREF_ADDED_FLAG));
} else {
bindings.put(CVSDecoratorConfiguration.FILE_REVISION, fileInfo.getRevision());
}
bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(fileInfo.getName(), fileInfo.getKeywordMode()));
if (tag != null && (tag.getType() != CVSTag.HEAD)) {
bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, tag.getName());
}
} else {
// only show the type that cvs will use when comitting the file
bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(file.getName(), null));
}
break;
}
return new CVSDecoration(format, bindings, null);
} catch (CVSException e) {
return new CVSDecoration();
}
}
private List computeLabelOverlaysFor(IResource resource, boolean isDirty, ITeamProvider provider) {
List overlays = new ArrayList(3);
IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore();
boolean showDirty = store.getBoolean(ICVSUIConstants.PREF_SHOW_DIRTY_DECORATION);
boolean showHasRemote = store.getBoolean(ICVSUIConstants.PREF_SHOW_HASREMOTE_DECORATION);
boolean showAdded = store.getBoolean(ICVSUIConstants.PREF_SHOW_ADDED_DECORATION);
if(showDirty && isDirty) {
overlays.add(dirty);
}
if (showHasRemote && provider.hasRemote(resource)) {
overlays.add(checkedIn);
}
if (showAdded && resource.getType() == IResource.FILE && provider.isCheckedOut(resource)) {
overlays.add(checkedOut);
}
if(overlays.isEmpty()) {
return null;
} else {
return overlays;
}
}
private boolean isDirty(IResource resource) {
final CoreException DECORATOR_EXCEPTION = new CoreException(new Status(IStatus.OK, "id", 1, "", null)); //$NON-NLS-1$ //$NON-NLS-2$
try {
resource.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
// a project can't be dirty, continue with its children
if (resource.getType() == IResource.PROJECT) {
return true;
}
// if the resource does not exist in the workbench or on the file system, stop searching.
if(!resource.exists()) {
return false;
}
ICVSResource cvsResource;
if (resource.getType() == IResource.FILE) {
cvsResource = new LocalFile(resource.getLocation().toFile());
} else {
cvsResource = new LocalFolder(resource.getLocation().toFile());
}
try {
if (!cvsResource.isManaged()) {
if (cvsResource.isIgnored() || cvsResource.getParent().isIgnored()) {
return false;
} else {
// new resource, show as dirty
throw DECORATOR_EXCEPTION;
}
}
if (!cvsResource.isFolder()) {
if (((ICVSFile) cvsResource).isModified()) {
// file has changed, show as dirty
throw DECORATOR_EXCEPTION;
}
}
} catch (CVSException e) {
return true;
}
// no change -- keep looking in children
return true;
}
}, IResource.DEPTH_INFINITE, true);
} catch (CoreException e) {
//if our exception was caught, we know there's a dirty child
return e == DECORATOR_EXCEPTION;
}
return false;
}
}