/*******************************************************************************
* Copyright (c) 2013, 2015 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Obeo - initial API and implementation
* Philip Langer - integrated model update strategy (bug 457839)
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Conflict;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.MatchResource;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.accessor.AccessorAdapter;
import org.eclipse.emf.compare.internal.utils.ComparisonUtil;
import org.eclipse.emf.compare.provider.ExtendedAdapterFactoryItemDelegator;
import org.eclipse.emf.compare.rcp.ui.EMFCompareRCPUIPlugin;
import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.factory.IAccessorFactory;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategy;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategyProvider;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.SingleValuedAttributeModelUpdateStrategy;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
import org.eclipse.emf.edit.provider.IDisposable;
import org.eclipse.emf.edit.tree.TreeNode;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.progress.IDeferredWorkbenchAdapter;
/**
* @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
*/
public abstract class CompareInputAdapter extends AdapterImpl implements ICompareInput, IDisposable, IAdaptable {
/**
* Store the listeners for notifications.
*/
private final ListenerList fListener;
/**
* The {@link AdapterFactory} used to implement {@link #getName()} and {@link #getImage()}.
*/
private final AdapterFactory fAdapterFactory;
/** The item delegator to use to retrieve item */
private final ExtendedAdapterFactoryItemDelegator itemDelegator;
/** A {@link IDeferredWorkbenchAdapter} to which this compareInput can adapt to. */
private IDeferredWorkbenchAdapter deferredWorkbenchAdapter;
/** A {@link IModelUpdateStrategyProvider} providing the strategy for updating the underlying model. */
private IModelUpdateStrategyProvider modelUpdateStrategyProvider;
/**
* Simple constructor storing the given {@link AdapterFactory}.
*
* @param adapterFactory
* the factory.
*/
public CompareInputAdapter(AdapterFactory adapterFactory) {
fAdapterFactory = adapterFactory;
itemDelegator = new ExtendedAdapterFactoryItemDelegator(getRootAdapterFactory());
fListener = new ListenerList();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(java.lang.Object)
*/
@Override
public boolean isAdapterForType(Object type) {
return type == fAdapterFactory;
}
/**
* Final accessor to the {@link AdapterFactory} for sub classses.
*
* @return the wrapped {@link AdapterFactory}.
*/
protected final AdapterFactory getAdapterFactory() {
return fAdapterFactory;
}
/**
* Gets the root factory if this local adapter factory is composed, otherwise just the local one.
*/
protected final AdapterFactory getRootAdapterFactory() {
if (fAdapterFactory instanceof ComposeableAdapterFactory) {
return ((ComposeableAdapterFactory)fAdapterFactory).getRootAdapterFactory();
}
return fAdapterFactory;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
*/
public void addCompareInputChangeListener(ICompareInputChangeListener listener) {
fListener.add(listener);
}
/**
* {@inheritDoc}.
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#removeCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
*/
public void removeCompareInputChangeListener(ICompareInputChangeListener listener) {
fListener.remove(listener);
}
/**
* Sends out notification that a change has occurred on the <code>ICompareInput</code>.
*/
protected void fireChange() {
if (fListener != null) {
final Object[] listeners = fListener.getListeners();
for (int i = 0; i < listeners.length; i++) {
final ICompareInputChangeListener listener = (ICompareInputChangeListener)listeners[i];
SafeRunnable runnable = new SafeRunnable() {
public void run() throws Exception {
listener.compareInputChanged(CompareInputAdapter.this);
}
};
SafeRunner.run(runnable);
}
}
}
/**
* {@inheritDoc}
*/
public EObject getComparisonObject() {
// target can be null when getLeft/Right/Ancestor is requested after StructureMergeViewer is disposed.
if (getTarget() != null) {
return ((TreeNode)getTarget()).getData();
} else {
return null;
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#copy(boolean)
*/
public void copy(boolean leftToRight) {
}
/**
* Returns the appropriate {@link IAccessorFactory} from the accessor factory registry.
*
* @return the appropriate {@link IAccessorFactory}.
*/
protected IAccessorFactory getAccessorFactoryForTarget() {
IAccessorFactory.Registry factoryRegistry = EMFCompareRCPUIPlugin.getDefault()
.getAccessorFactoryRegistry();
return factoryRegistry.getHighestRankingFactory(getComparisonObject());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.ITypedElement#getImage()
*/
public Image getImage() {
Object imageObject = itemDelegator.getImage(getComparisonObject());
return ExtendedImageRegistry.getInstance().getImage(imageObject);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#getKind()
*/
public int getKind() {
Notifier notifier = getComparisonObject();
boolean isThreeWay = isThreeWay(notifier);
if (isThreeWay) {
return Differencer.CONFLICTING;
}
return Differencer.NO_CHANGE;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#getName()
*/
public String getName() {
return itemDelegator.getText(getComparisonObject());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#getAncestor()
*/
public ITypedElement getAncestor() {
final ITypedElement ret;
Notifier notifier = getComparisonObject();
boolean isThreeWay = isThreeWay(notifier);
if (isThreeWay) {
IAccessorFactory accessorFactory = getAccessorFactoryForTarget();
if (accessorFactory != null) {
org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement typedElement = accessorFactory
.createAncestor(getAdapterFactory(), getComparisonObject());
if (typedElement != null) {
ret = AccessorAdapter.adapt(typedElement);
} else {
ret = null;
}
} else {
ret = null;
}
} else {
ret = null;
}
return ret;
}
protected boolean isThreeWay(Notifier notifier) {
final boolean isThreeWay;
if (notifier instanceof Diff) {
if (((Diff)notifier).eContainer() instanceof MatchResource) {
isThreeWay = ((MatchResource)((Diff)notifier).eContainer()).getComparison().isThreeWay();
} else {
isThreeWay = ComparisonUtil.getComparison((Diff)notifier).isThreeWay();
}
} else if (notifier instanceof Match) {
isThreeWay = ((Match)notifier).getComparison().isThreeWay();
} else if (notifier instanceof Conflict) {
isThreeWay = true;
} else if (notifier instanceof MatchResource) {
isThreeWay = ((MatchResource)notifier).getComparison().isThreeWay();
} else if (notifier instanceof Comparison) {
isThreeWay = ((Comparison)notifier).isThreeWay();
} else {
isThreeWay = false;
}
return isThreeWay;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#getLeft()
*/
public ITypedElement getLeft() {
final ITypedElement ret;
IAccessorFactory accessorFactory = getAccessorFactoryForTarget();
if (accessorFactory != null) {
org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement typedElement = accessorFactory
.createLeft(getAdapterFactory(), getComparisonObject());
if (typedElement != null) {
ret = AccessorAdapter.adapt(typedElement);
} else {
ret = null;
}
} else {
ret = null;
}
return ret;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.structuremergeviewer.ICompareInput#getRight()
*/
public ITypedElement getRight() {
final ITypedElement ret;
IAccessorFactory accessorFactory = getAccessorFactoryForTarget();
if (accessorFactory != null) {
org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement typedElement = accessorFactory
.createRight(getAdapterFactory(), getComparisonObject());
if (typedElement != null) {
ret = AccessorAdapter.adapt(typedElement);
} else {
ret = null;
}
} else {
ret = null;
}
return ret;
}
/**
* This will remove this adapter from all its the targets and dispose any remaining children wrappers in
* the children store.
*/
public void dispose() {
Notifier oldTarget = target;
target = null;
if (oldTarget != null) {
oldTarget.eAdapters().remove(this);
}
deferredWorkbenchAdapter = null;
modelUpdateStrategyProvider = null;
}
/**
* Set a {@link IDeferredWorkbenchAdapter} for this.
*
* @param deferredWorkbenchAdapter
*/
public void setDeferredAdapter(IDeferredWorkbenchAdapter deferredWorkbenchAdapter) {
this.deferredWorkbenchAdapter = deferredWorkbenchAdapter;
}
/**
* {@inheritDoc}
*
* @see IAdaptable#getAdapter(Class)
*/
@SuppressWarnings("rawtypes")
public Object getAdapter(Class adapter) {
if (adapter == IDeferredWorkbenchAdapter.class) {
return deferredWorkbenchAdapter;
}
return null;
}
/**
* Returns the {@link IModelUpdateStrategy} to be used by content mergers for this compare input.
*
* @return The {@link IModelUpdateStrategy} to be used.
*/
public IModelUpdateStrategy getModelUpdateStrategy() {
if (modelUpdateStrategyProvider == null) {
modelUpdateStrategyProvider = createModelUpdateStrategyProvider();
}
return modelUpdateStrategyProvider.getModelUpdateStrategy();
}
/**
* Creates a {@link IModelUpdateStrategyProvider}.
* <p>
* Checks if the {@link #getAccessorFactoryForTarget() accessor factory for the target} is a
* {@link IModelUpdateStrategyProvider} and, if yes, returns this accessor factory as
* {@link IModelUpdateStrategyProvider}. If it is not a model update strategy provider, it will default to
* one that always returns the tolerant {@link SingleValuedAttributeModelUpdateStrategy}.
* </p>
*
* @return The created {@link IModelUpdateStrategyProvider}.
*/
private IModelUpdateStrategyProvider createModelUpdateStrategyProvider() {
final IModelUpdateStrategyProvider ret;
IAccessorFactory accessorFactory = getAccessorFactoryForTarget();
if (accessorFactory instanceof IModelUpdateStrategyProvider) {
ret = (IModelUpdateStrategyProvider)accessorFactory;
} else {
ret = new IModelUpdateStrategyProvider() {
public IModelUpdateStrategy getModelUpdateStrategy() {
return new SingleValuedAttributeModelUpdateStrategy();
}
};
}
return ret;
}
}