blob: abcacc2cdee8aa76eeee969ad1986bc78ca99fcf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.synchronize;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.core.resources.IEncodedStorage;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
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.TeamUIPlugin;
/**
* 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 parent
* @param info
*/
public SyncInfoModelElement(IDiffContainer parent, SyncInfo info) {
super(parent);
Assert.isNotNull(info);
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());
// 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 {
setRight(createRemoteTypeElement(info));
}
}
// Base
RemoteResourceTypedElement ancestorEl = (RemoteResourceTypedElement)getAncestor();
IResourceVariant base = info.getBase();
if(ancestorEl == null && base != null) {
setAncestor(createBaseTypeElement(info));
} else if(ancestorEl != null) {
if(base == null) {
setAncestor(null);
} else {
setAncestor(createBaseTypeElement(info));
}
}
fireChange();
}
@Override
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
*/
@Override
public void setAncestor(ITypedElement ancestor) {
this.ancestor = ancestor;
}
@Override
public ITypedElement getAncestor() {
return this.ancestor;
}
@Override
public String getName() {
IResource resource = getResource();
if(resource != null) {
return resource.getName();
} else {
return super.getName();
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAdapter(Class<T> adapter) {
if(adapter == SyncInfo.class) {
return (T) 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.
*/
@Override
public IResource getResource() {
return info.getLocal();
}
@Override
public String toString() {
return getResource().getFullPath().toString();
}
/**
* 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));
}
} catch (CoreException e) {
throw TeamException.asTeamException(e);
} 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);
}
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, String encoding) {
return new RemoteResourceTypedElement(remoteResource,encoding);
}
protected static ITypedElement createRemoteTypeElement(SyncInfo info) {
if(info != null && info.getRemote() != null) {
return createTypeElement(info.getRemote(), getEncoding(info.getLocal()));
}
return null;
}
private static String getEncoding(IResource local) {
if (local instanceof IEncodedStorage) {
IEncodedStorage es = (IEncodedStorage) local;
try {
return es.getCharset();
} catch (CoreException e) {
TeamUIPlugin.log(e);
}
}
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(), getEncoding(info.getLocal()));
}
return null;
}
}