blob: fd3c93b4423159b94697c935d4e19772915f55dc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.ui.synchronize.viewers;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.compare.structuremergeviewer.*;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.core.variants.IResourceVariant;
import org.eclipse.team.internal.ui.Policy;
import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
import org.eclipse.team.internal.ui.synchronize.RemoteResourceTypedElement;
/**
* A diff node used to display the synchronization state for resources described by
* existing {@link SyncInfo} objects. The synchronization state for a node can
* change after it has been created. Since it implements the <code>ITypedElement</code>
* and <code>ICompareInput</code> interfaces it can be used directly to
* display the compare result in a <code>DiffTreeViewer</code> and as the
* input to any other compare/merge viewer.
* <p>
* Clients typically use this class as is, but may subclass if required.
* </p>
* @see DiffTreeViewer
* @see Differencer
*/
public class SyncInfoModelElement extends SynchronizeModelElement {
private ITypedElement ancestor;
private SyncInfo info;
/**
* Construct a <code>SyncInfoModelElement</code> for the given resource.
*
* @param set The set associated with the diff tree veiwer
* @param resource The resource for the node
*/
public SyncInfoModelElement(IDiffContainer parent, SyncInfo info) {
super(parent);
this.info = info;
// update state
setKind(info.getKind());
// local
setLeft(createLocalTypeElement(info));
// remote
setRight(createRemoteTypeElement(info));
// base
setAncestor(createBaseTypeElement(info));
fireChange();
}
/**
* Update this element with a changed sync info. The remote and base handles have to be updated
* with the new handles in the sync info.
*
* @param info the new sync info
*/
public void update(SyncInfo info) {
this.info = info;
// update state
setKind(info.getKind());
// never have to update the local, it's always the workspace resource
// Remote
RemoteResourceTypedElement rightEl = (RemoteResourceTypedElement)getRight();
IResourceVariant remote = info.getRemote();
if(rightEl == null && remote != null) {
setRight(createRemoteTypeElement(info));
} else if(rightEl != null) {
if(remote == null) {
setRight(null);
} else {
rightEl.update(remote);
}
}
// Base
RemoteResourceTypedElement ancestorEl = (RemoteResourceTypedElement)getRight();
IResourceVariant base = info.getBase();
if(ancestorEl == null && base != null) {
setAncestor(createBaseTypeElement(info));
} else if(ancestorEl != null) {
if(base == null) {
setAncestor(null);
} else {
ancestorEl.update(base);
}
}
fireChange();
}
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.DiffElement#getKind()
*/
public int getKind() {
SyncInfo info = getSyncInfo();
if (info != null) {
return info.getKind();
} else {
return SyncInfo.IN_SYNC;
}
}
/**
* We have to track the base because <code>DiffNode</code> doesn't provide a
* setter. See:
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=52261
*/
public void setAncestor(ITypedElement ancestor) {
this.ancestor = ancestor;
}
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.DiffNode#getAncestor()
*/
public ITypedElement getAncestor() {
return this.ancestor;
}
/* (non-Javadoc)
* @see org.eclipse.compare.structuremergeviewer.DiffNode#getName()
*/
public String getName() {
IResource resource = getResource();
if(resource != null) {
return resource.getName();
} else {
return super.getName();
}
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if(adapter == SyncInfo.class) {
return getSyncInfo();
}
return super.getAdapter(adapter);
}
/**
* Helper method that returns the resource associated with this node. A node is not
* required to have an associated local resource.
* @return the resource associated with this node or <code>null</code> if the local
* contributor is not a resource.
*/
public IResource getResource() {
ITypedElement element = getLeft();
if(element instanceof ResourceNode) {
return ((ResourceNode)element).getResource();
}
return null;
}
/**
* Return true if the receiver's Subscriber and Resource are equal to that of object.
* @param object The object to test
* @return true has the same subsriber and resource
*/
public boolean equals(Object object) {
return this==object;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
IResource resource = getResource();
if (resource == null) {
return super.hashCode();
}
return resource.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return getResource() != null ? getResource().getFullPath().toString() : getName();
}
/**
* Cache the contents for the base and remote.
* @param monitor
*/
public void cacheContents(IProgressMonitor monitor) throws TeamException {
ITypedElement base = getAncestor();
ITypedElement remote = getRight();
int work = Math.min((remote== null ? 0 : 50) + (base == null ? 0 : 50), 10);
monitor.beginTask(null, work);
try {
if (base != null && base instanceof RemoteResourceTypedElement) {
((RemoteResourceTypedElement)base).cacheContents(Policy.subMonitorFor(monitor, 50));
}
if (remote != null && remote instanceof RemoteResourceTypedElement) {
((RemoteResourceTypedElement)remote).cacheContents(Policy.subMonitorFor(monitor, 50));
}
} finally {
monitor.done();
}
}
public SyncInfo getSyncInfo() {
return info;
}
/**
* Create an ITypedElement for the given local resource. The returned ITypedElement
* will prevent editing of outgoing deletions.
*/
private static ITypedElement createTypeElement(final IResource resource, final int kind) {
if(resource != null) {
return new LocalResourceTypedElement(resource) {
public boolean isEditable() {
if(! resource.exists() && SyncInfo.getDirection(kind) == SyncInfo.OUTGOING && SyncInfo.getChange(kind) == SyncInfo.DELETION) {
return false;
}
return super.isEditable();
}
};
}
return null;
}
/**
* Create an ITypedElement for the given remote resource. The contents for the remote resource
* will be retrieved from the given IStorage which is a local cache used to buffer the remote contents
*/
protected static ITypedElement createTypeElement(IResourceVariant remoteResource) {
return new RemoteResourceTypedElement(remoteResource);
}
protected static ITypedElement createRemoteTypeElement(SyncInfo info) {
if(info != null && info.getRemote() != null) {
return createTypeElement(info.getRemote());
}
return null;
}
protected static ITypedElement createLocalTypeElement(SyncInfo info) {
if(info != null && info.getLocal() != null) {
return createTypeElement(info.getLocal(), info.getKind());
}
return null;
}
protected static ITypedElement createBaseTypeElement(SyncInfo info) {
if(info != null && info.getBase() != null) {
return createTypeElement(info.getBase());
}
return null;
}
}