blob: b9e867a33cdcfb1432c0bb6ed7cb1aafac988fcf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 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.mapping;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.compare.ICompareInputLabelProvider;
import org.eclipse.compare.IResourceProvider;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.diff.IDiffChangeEvent;
import org.eclipse.team.core.diff.IDiffChangeListener;
import org.eclipse.team.core.diff.IDiffTree;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.mapping.provider.ResourceDiffTree;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.internal.ui.Utils;
import org.eclipse.team.internal.ui.history.FileRevisionTypedElement;
import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
/**
* A change notifier for resource-based compare inputs.
*/
public class ResourceCompareInputChangeNotifier extends CompareInputChangeNotifier implements IDiffChangeListener {
static final String RESOURCE_CHANGE_NOTIFIER_PROPERTY = "org.eclipse.team.ui.ResourceChangeNotifier"; //$NON-NLS-1$
private ISynchronizationContext context;
private class CompareInputLabelProvider extends BaseLabelProvider implements ICompareInputLabelProvider {
@Override
public Image getAncestorImage(Object input) {
// No image desired
return null;
}
@Override
public String getAncestorLabel(Object input) {
if (input instanceof ResourceDiffCompareInput) {
ResourceDiffCompareInput rdci = (ResourceDiffCompareInput) input;
ITypedElement element = rdci.getAncestor();
if (element != null) {
final IFileRevision revision = ((FileRevisionTypedElement)element).getFileRevision();
if (revision != null) {
if (Utils.isShowAuthor()) {
String author = ((FileRevisionTypedElement)element).getAuthor();
if (author != null) {
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_baseLabelAuthorExists, new String[] { revision.getContentIdentifier(), author });
} else if (revision.isPropertyMissing()) {
fetchAuthors(rdci);
}
}
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_baseLabelExists, new String[] { revision.getContentIdentifier() });
} else {
return TeamUIMessages.SyncInfoCompareInput_baseLabel;
}
}
}
return null;
}
@Override
public Image getLeftImage(Object input) {
// No image desired
return null;
}
@Override
public String getLeftLabel(Object input) {
if (input instanceof ResourceDiffCompareInput) {
ResourceDiffCompareInput rdci = (ResourceDiffCompareInput) input;
String localContentId = rdci.getLocalContentId();
if (localContentId != null) {
ITypedElement element= rdci.getLeft();
if (element instanceof LocalResourceTypedElement) {
if (Utils.isShowAuthor()) {
String author= ((LocalResourceTypedElement)element).getAuthor();
if (author != null) {
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_localLabelAuthorExists, new String[] { localContentId, author });
} else { // NOTE: Must not check for revision#isPropertyMissing() as this will always return true for the workspace file revision
fetchAuthors(rdci);
}
}
}
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_localLabelExists, new String[] { localContentId });
} else {
return TeamUIMessages.SyncInfoCompareInput_localLabel;
}
}
return null;
}
@Override
public Image getRightImage(Object input) {
// No image desired
return null;
}
@Override
public String getRightLabel(Object input) {
if (input instanceof ResourceDiffCompareInput) {
ResourceDiffCompareInput rdci = (ResourceDiffCompareInput) input;
ITypedElement element = rdci.getRight();
if (element != null) {
final IFileRevision revision = ((FileRevisionTypedElement)element).getFileRevision();
if (revision != null) {
if (Utils.isShowAuthor()) {
String author = ((FileRevisionTypedElement)element).getAuthor();
if (author != null) {
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_remoteLabelAuthorExists, new String[] { revision.getContentIdentifier(), author });
} else if (revision.isPropertyMissing()) {
fetchAuthors(rdci);
}
}
return NLS.bind(TeamUIMessages.SyncInfoCompareInput_remoteLabelExists, new String[] { revision.getContentIdentifier() });
} else {
return TeamUIMessages.SyncInfoCompareInput_remoteLabel;
}
}
}
return null;
}
@Override
public Image getImage(Object element) {
if (element instanceof ICompareInput) {
ICompareInput ci = (ICompareInput) element;
return ci.getImage();
}
return null;
}
@Override
public String getText(Object element) {
if (element instanceof ICompareInput) {
ICompareInput ci = (ICompareInput) element;
return ci.getName();
}
return null;
}
public void fireChangeEvent(final Object element) {
Display.getDefault().asyncExec(() -> fireLabelProviderChanged(new LabelProviderChangedEvent(CompareInputLabelProvider.this, element)));
}
}
/**
* Return a compare input change notifier that will detect changes in the synchronization context and
* translate them into compare input change events by calling {@link ResourceDiffCompareInput#update()}.
* @param context the synchronization context
* @return a compare input change notifier
*/
public static ResourceCompareInputChangeNotifier getChangeNotifier(ISynchronizationContext context) {
ResourceCompareInputChangeNotifier notifier = (ResourceCompareInputChangeNotifier)context.getCache().get(ResourceCompareInputChangeNotifier.RESOURCE_CHANGE_NOTIFIER_PROPERTY);
if (notifier == null) {
notifier = new ResourceCompareInputChangeNotifier(context);
context.getCache().put(ResourceCompareInputChangeNotifier.RESOURCE_CHANGE_NOTIFIER_PROPERTY, notifier);
}
return notifier;
}
private final CompareInputLabelProvider labelProvider = new CompareInputLabelProvider();
private Object fetchingInput;
/**
* Create a notifier
* @param context a synchronization context
*/
public ResourceCompareInputChangeNotifier(ISynchronizationContext context) {
super();
this.context = context;
// We can initialize in the constructor since the context will allow us to dispose
initialize();
}
@Override
public void initialize() {
context.getDiffTree().addDiffChangeListener(this);
context.getCache().addCacheListener(cache -> dispose());
super.initialize();
}
@Override
public void dispose() {
super.dispose();
context.getDiffTree().removeDiffChangeListener(this);
labelProvider.dispose();
}
@Override
public void diffsChanged(IDiffChangeEvent event, IProgressMonitor monitor) {
Set<ICompareInput> changedInputs = new HashSet<>();
IDiff[] added = event.getAdditions();
for (IDiff diff : added) {
ICompareInput input = findInput(ResourceDiffTree.getResourceFor(diff));
if (input != null)
changedInputs.add(input);
}
IDiff[] changed = event.getChanges();
for (IDiff diff : changed) {
ICompareInput input = findInput(ResourceDiffTree.getResourceFor(diff));
if (input != null)
changedInputs.add(input);
}
IPath[] paths = event.getRemovals();
for (IPath path : paths) {
ICompareInput input = findInput(path);
if (input != null)
changedInputs.add(input);
}
if (!changedInputs.isEmpty())
handleInputChanges(changedInputs.toArray(new ICompareInput[changedInputs.size()]), false);
}
@Override
public void propertyChanged(IDiffTree tree, int property, IPath[] paths) {
// Property changes are not interesting w.r.t. state changes
}
@Override
protected IResource[] getResources(ICompareInput input) {
IResource resource = getResource(input);
if (resource == null)
return new IResource[0];
return new IResource[] { resource };
}
private IResource getResource(ICompareInput input) {
if (input instanceof IResourceProvider) {
IResourceProvider rp = (IResourceProvider) input;
return rp.getResource();
}
return Utils.getResource(input);
}
private ICompareInput findInput(IPath path) {
ICompareInput[] inputs = getConnectedInputs();
for (ICompareInput input : inputs) {
IResource inputResource = getResource(input);
if (inputResource != null && inputResource.getFullPath().equals(path)) {
return input;
}
}
return null;
}
private ICompareInput findInput(IResource resource) {
ICompareInput[] inputs = getConnectedInputs();
for (ICompareInput input : inputs) {
IResource inputResource = getResource(input);
if (inputResource != null && inputResource.equals(resource)) {
return input;
}
}
return null;
}
@Override
protected void prepareInput(ICompareInput input, IProgressMonitor monitor) {
if (input instanceof ResourceDiffCompareInput) {
ResourceDiffCompareInput rdci = (ResourceDiffCompareInput) input;
IResource resource = rdci.getResource();
IDiff diff = getContext().getDiffTree().getDiff(resource);
try {
ResourceDiffCompareInput.ensureContentsCached(diff, monitor);
} catch (CoreException e) {
// Log the exception and continue
TeamUIPlugin.log(e);
}
}
super.prepareInput(input, monitor);
}
/**
* Return the label provider for resource compare inputs.
* @return the label provider for resource compare inputs
*/
public ICompareInputLabelProvider getLabelProvider() {
return labelProvider;
}
public void fetchAuthors(final ResourceDiffCompareInput input) {
if (fetchingInput == input)
return;
fetchingInput= input;
runInBackground(monitor -> fetchAuthors(input, monitor));
}
protected void fetchAuthors(ResourceDiffCompareInput input, IProgressMonitor monitor) throws CoreException {
if (input.updateAuthorInfo(monitor))
fireLabelProviderChange(input);
}
private void fireLabelProviderChange(Object input) {
labelProvider.fireChangeEvent(input);
}
/**
* Return the synchronization context to which this notifier is associated.
* @return the synchronization context to which this notifier is associated
*/
public final ISynchronizationContext getContext() {
return context;
}
@Override
protected boolean belongsTo(Object family) {
return family == getContext();
}
}