blob: 0ef734b5627541748f799ec873d91b07dcc1a356 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2018 Obeo and others.
* 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
* Michael Borkowski - bug 462863
* Stefan Dirix - bug 473985
* Philip Langer - bug 516645, 521948, 527567, 514079
* Martin Fleck - bug 514079
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer;
import com.google.common.base.Predicate;
import com.google.common.eventbus.Subscribe;
import java.util.Collection;
import java.util.EventObject;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareViewerSwitchingPane;
import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
import org.eclipse.compare.internal.CompareHandlerService;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.command.CommandStackListener;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.command.ICompareCommandStack;
import org.eclipse.emf.compare.command.ICompareCopyCommand;
import org.eclipse.emf.compare.domain.ICompareEditingDomain;
import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.DynamicObject;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.EMFCompareColor;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.RedoAction;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.UndoAction;
import org.eclipse.emf.compare.ide.ui.mergeresolution.MergeResolutionManager;
import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
import org.eclipse.emf.compare.rcp.ui.internal.configuration.IAdapterFactoryChange;
import org.eclipse.emf.compare.rcp.ui.internal.configuration.ICompareEditingDomainChange;
import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.IColorChangeEvent;
import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem;
import org.eclipse.emf.compare.rcp.ui.internal.util.SWTUtil;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.ICompareColor;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.IDifferenceFilterChange;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProviderChange;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.part.IPage;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.themes.ITheme;
import org.eclipse.ui.themes.IThemeManager;
import org.eclipse.ui.views.properties.PropertySheet;
/**
* @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
*/
@SuppressWarnings("restriction")
public abstract class EMFCompareContentMergeViewer extends ContentMergeViewer implements ISelectionChangedListener, ICompareColor.Provider, IAdaptable, CommandStackListener {
private static final String HANDLER_SERVICE = "fHandlerService"; //$NON-NLS-1$
/**
* Width of center bar
*/
protected static final int CENTER_WIDTH = 34;
private IMergeViewer fAncestor;
private IMergeViewer fLeft;
private IMergeViewer fRight;
private final AtomicBoolean fSyncingSelections = new AtomicBoolean(false);
private EMFCompareColor fColors;
private final DynamicObject fDynamicObject;
private UndoAction undoAction;
private RedoAction redoAction;
private AdapterFactoryContentProvider fAdapterFactoryContentProvider;
private Predicate<? super EObject> differenceFilterPredicate;
private IDifferenceGroupProvider differenceGroupProvider;
private MergeResolutionManager mergeResolutionManager;
private IPropertyChangeListener propertyChangeListener;
private MirrorManager mirrorManager;
/**
* @param style
* @param bundle
* @param cc
*/
protected EMFCompareContentMergeViewer(int style, ResourceBundle bundle, EMFCompareConfiguration cc) {
super(style, new EMFCompareContentMergeViewerResourceBundle(bundle), cc);
fDynamicObject = new DynamicObject(this);
if (getCompareConfiguration().getAdapterFactory() != null) {
fAdapterFactoryContentProvider = new AdapterFactoryContentProvider(
getCompareConfiguration().getAdapterFactory());
}
redoAction = new RedoAction(getCompareConfiguration().getEditingDomain());
undoAction = new UndoAction(getCompareConfiguration().getEditingDomain());
editingDomainChange(null, getCompareConfiguration().getEditingDomain());
getCompareConfiguration().getEventBus().register(this);
mergeResolutionManager = new MergeResolutionManager(
EMFCompareIDEUIPlugin.getDefault().getMergeResolutionListenerRegistry());
propertyChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
handlePropertyChangeEvent(event);
}
};
getCompareConfiguration().getPreferenceStore().addPropertyChangeListener(propertyChangeListener);
mirrorManager = new MirrorManager(cc);
}
@Override
public void setContentProvider(IContentProvider contentProvider) {
if (mirrorManager != null) {
super.setContentProvider(mirrorManager.getContentProvider(contentProvider));
} else {
super.setContentProvider(contentProvider);
}
}
@Subscribe
public void handleAdapterFactoryChange(IAdapterFactoryChange event) {
AdapterFactory oldValue = event.getOldValue();
AdapterFactory newValue = event.getNewValue();
if (oldValue != null) {
fAdapterFactoryContentProvider.dispose();
}
if (newValue != oldValue) {
fAdapterFactoryContentProvider = new AdapterFactoryContentProvider(newValue);
}
}
@Subscribe
public void colorChanged(
@SuppressWarnings("unused") /* necessary for @Subscribe */IColorChangeEvent changeColorEvent) {
getControl().redraw();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration#editingDomainChange(org.eclipse.emf.compare.domain.ICompareEditingDomain,
* org.eclipse.emf.compare.domain.ICompareEditingDomain)
*/
@Subscribe
public void handleEditingDomainChange(ICompareEditingDomainChange event) {
ICompareEditingDomain oldValue = event.getOldValue();
ICompareEditingDomain newValue = event.getNewValue();
editingDomainChange(oldValue, newValue);
}
protected void editingDomainChange(ICompareEditingDomain oldValue, ICompareEditingDomain newValue) {
if (oldValue != null) {
ICompareCommandStack commandStack = oldValue.getCommandStack();
commandStack.removeCommandStackListener(this);
}
if (newValue != oldValue) {
if (newValue != null) {
ICompareCommandStack commandStack = newValue.getCommandStack();
commandStack.addCommandStackListener(this);
setLeftDirty(commandStack.isLeftSaveNeeded());
setRightDirty(commandStack.isRightSaveNeeded());
}
undoAction.setEditingDomain(newValue);
redoAction.setEditingDomain(newValue);
}
}
@Subscribe
public void handleDifferenceFiltersChange(IDifferenceFilterChange event) {
differenceFilterPredicate = event.getPredicate();
redrawCenterControl();
}
/**
* @return the differenceFilterPredicate
*/
protected final Predicate<? super EObject> getDifferenceFilterPredicate() {
if (differenceFilterPredicate == null) {
differenceFilterPredicate = getCompareConfiguration().getStructureMergeViewerFilter()
.getAggregatedPredicate();
}
return differenceFilterPredicate;
}
@Subscribe
public void handleDifferenceGroupProviderChange(IDifferenceGroupProviderChange event) {
differenceGroupProvider = event.getDifferenceGroupProvider();
redrawCenterControl();
}
/**
* @return the differenceGroupProvider
*/
protected final IDifferenceGroupProvider getDifferenceGroupProvider() {
if (differenceGroupProvider == null) {
differenceGroupProvider = getCompareConfiguration().getStructureMergeViewerGrouper()
.getProvider();
}
return differenceGroupProvider;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.ICompareColorProvider#getCompareColor()
*/
public ICompareColor getCompareColor() {
return fColors;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#updateContent(java.lang.Object,
* java.lang.Object, java.lang.Object)
*/
@Override
protected void updateContent(Object ancestor, Object left, Object right) {
fAncestor.setInput(ancestor);
fLeft.setInput(left);
fRight.setInput(right);
IMergeViewerItem leftInitialItem = null;
if (left instanceof ICompareAccessor) {
leftInitialItem = ((ICompareAccessor)left).getInitialItem();
}
// Bug 458818: In some cases, the left initial item is null because
// the item that should be selected has been deleted on the right
// and this delete is part of a conflict
if (leftInitialItem == null) {
if (right instanceof ICompareAccessor) {
IMergeViewerItem rightInitialItem = ((ICompareAccessor)right).getInitialItem();
if (rightInitialItem == null) {
fLeft.setSelection(StructuredSelection.EMPTY, true);
} else {
fRight.setSelection(new StructuredSelection(rightInitialItem), true);
}
} else {
// Strange case: left is an ICompareAccessor but right is not?
fLeft.setSelection(StructuredSelection.EMPTY, true);
}
} else {
// others will synchronize on this one :)
fLeft.setSelection(new StructuredSelection(leftInitialItem), true);
}
redrawCenterControl();
}
/**
* Inhibits this method to avoid asking to save on each input change!!
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#doSave(java.lang.Object,
* java.lang.Object)
*/
@Override
protected boolean doSave(Object newInput, Object oldInput) {
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createControls(org.eclipse.swt.widgets.Composite)
*/
@Override
protected void createControls(Composite composite) {
fAncestor = createMergeViewer(composite, MergeViewerSide.ANCESTOR);
fAncestor.addSelectionChangedListener(this);
fLeft = createMergeViewer(composite, getEffectiveSide(MergeViewerSide.LEFT));
fLeft.addSelectionChangedListener(this);
fRight = createMergeViewer(composite, getEffectiveSide(MergeViewerSide.RIGHT));
fRight.addSelectionChangedListener(this);
final ITheme currentTheme = getCurrentTheme();
boolean leftIsLocal = getCompareConfiguration().getBooleanProperty("LEFT_IS_LOCAL", false);
fColors = new EMFCompareColor(composite.getDisplay(), leftIsLocal, currentTheme,
getCompareConfiguration().getEventBus());
composite.addControlListener(new ControlListener() {
public void controlResized(ControlEvent e) {
redrawCenterControl();
}
public void controlMoved(ControlEvent e) {
// Do nothing.
}
});
}
/**
* Returns the effective side taking into account {@link CompareConfiguration#isMirrored()} to switch left
* and right.
*
* @param side
* @return the effective side with respect to mirroring.
*/
protected MergeViewerSide getEffectiveSide(MergeViewerSide side) {
if (side != null && getCompareConfiguration().isMirrored()) {
return side.opposite();
}
return side;
}
/**
* Determines the current used theme.
*
* @return The currently used theme if available, {@code null} otherwise.
*/
private ITheme getCurrentTheme() {
if (PlatformUI.isWorkbenchRunning()) {
final IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
if (themeManager != null) {
return themeManager.getCurrentTheme();
}
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createToolItems(org.eclipse.jface.action.ToolBarManager)
*/
@Override
protected void createToolItems(final ToolBarManager toolBarManager) {
getHandlerService().setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction);
getHandlerService().setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction);
IContributionItem[] items = toolBarManager.getItems();
for (IContributionItem iContributionItem : items) {
if (iContributionItem instanceof ActionContributionItem) {
IAction action = ((ActionContributionItem)iContributionItem).getAction();
String id = action.getActionDefinitionId();
if ("org.eclipse.compare.copyAllLeftToRight".equals(id)) {
toolBarManager.remove(iContributionItem);
} else if ("org.eclipse.compare.copyAllRightToLeft".equals(id)) {
toolBarManager.remove(iContributionItem);
}
}
}
// Add extension point contributions to the content merge viewer toolbar
if (PlatformUI.isWorkbenchRunning()) {
IServiceLocator workbench = PlatformUI.getWorkbench();
final IMenuService menuService = (IMenuService)workbench.getService(IMenuService.class);
if (menuService != null) {
// This is kind of a hack, but the code below will materialize all the SWT tool items and
// unless the check state is set on the actions, the right style of tool item won't be
// created.
updateToolItems();
menuService.populateContributionManager(toolBarManager,
"toolbar:org.eclipse.emf.compare.contentmergeviewer.toolbar"); //$NON-NLS-1$
toolBarManager.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
menuService.releaseContributions(toolBarManager);
// re-populate and release menu contributions to fix memory leak (see bug 516645)
menuService.populateContributionManager(toolBarManager, "nothing"); //$NON-NLS-1$
menuService.releaseContributions(toolBarManager);
}
});
}
}
}
public void commandStackChanged(EventObject event) {
undoAction.update();
redoAction.update();
if (getCompareConfiguration().getEditingDomain() != null) {
ICompareCommandStack commandStack = getCompareConfiguration().getEditingDomain()
.getCommandStack();
setLeftDirty(commandStack.isLeftSaveNeeded());
setRightDirty(commandStack.isRightSaveNeeded());
}
final Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand();
if (mostRecentCommand instanceof ICompareCopyCommand
|| mostRecentCommand instanceof CompoundCommand && ((CompoundCommand)mostRecentCommand)
.getCommandList().get(0) instanceof ICompareCopyCommand) {
SWTUtil.safeRefresh(this, true, false);
} else if (mostRecentCommand != null) {
// Model has changed, but not by EMFCompare. Typical case is update from properties view.
// In this case, we don't want to refresh all viewers and lost selected element, just refresh
// appropriate side and keep selected element.
IMergeViewer affectedMergeViewer = getAffectedMergeViewer(mostRecentCommand);
if (affectedMergeViewer instanceof Viewer) {
SWTUtil.safeRefresh(((Viewer)affectedMergeViewer), true, false);
}
}
// Refresh the properties view.
SWTUtil.safeAsyncExec(new Runnable() {
public void run() {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
ExtendedPropertySheetPage extendedPropertySheetPage = getExtendedPropertySheetPage(page);
if (extendedPropertySheetPage != null) {
Control control = extendedPropertySheetPage.getControl();
// Check that there isn't currently a cell editor active.
// If there is a focus control that isn't the control of the property sheet page...
Control focusControl = control.getDisplay().getFocusControl();
if (focusControl != null && focusControl != control) {
// Check if that focus control is contained by the property sheet page's control.
for (Control parent = focusControl.getParent(); parent != null; parent = parent
.getParent()) {
if (parent == control) {
// If it is, then don't refresh the property sheet page
// because that will make the cell editor deactivate.
return;
}
}
}
extendedPropertySheetPage.refresh();
}
}
});
}
/**
* Get the merge viewer affected by this command.
*
* @param command
* the command.
* @return the merge viewer affected by this command if found, null otherwise.
*/
private IMergeViewer getAffectedMergeViewer(Command command) {
final IMergeViewer viewer;
final IMergeViewer leftMergeViewer = this.getLeftMergeViewer();
final ISelection leftSelection = leftMergeViewer.getSelection();
final Collection<?> affectedObjects = command.getAffectedObjects();
if (affectedObjects != null && !affectedObjects.isEmpty()) {
Object firstAffectedObject = affectedObjects.iterator().next();
if (firstAffectedObject
.equals(getElement(leftSelection, getEffectiveSide(MergeViewerSide.LEFT)))) {
viewer = leftMergeViewer;
} else if (firstAffectedObject
.equals(getElement(leftSelection, getEffectiveSide(MergeViewerSide.RIGHT)))) {
viewer = this.getRightMergeViewer();
} else if (firstAffectedObject.equals(getElement(leftSelection, MergeViewerSide.ANCESTOR))) {
viewer = this.getAncestorMergeViewer();
} else {
viewer = null;
}
} else {
viewer = null;
}
return viewer;
}
/**
* From the given selection, get the model element from the given side.
*
* @param selection
* the given selection.
* @param side
* the given side.
* @return the model element from the given side if it exists, null otherwise.
*/
private Object getElement(ISelection selection, MergeViewerSide side) {
final Object element;
if (selection instanceof TreeSelection) {
Object firstElement = ((TreeSelection)selection).getFirstElement();
if (firstElement instanceof IMergeViewerItem) {
if (MergeViewerSide.LEFT == side) {
element = ((IMergeViewerItem)firstElement).getLeft();
} else if (MergeViewerSide.RIGHT == side) {
element = ((IMergeViewerItem)firstElement).getRight();
} else if (MergeViewerSide.ANCESTOR == side) {
element = ((IMergeViewerItem)firstElement).getAncestor();
} else {
element = null;
}
} else {
element = null;
}
} else {
element = null;
}
return element;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#copy(boolean)
*/
@Override
protected void copy(final boolean leftToRight) {
// do nothing, merge is done through merge actions in structure merge viewer.
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeAncestor(int, int, int, int)
*/
@Override
protected void handleResizeAncestor(int x, int y, int width, int height) {
if (width > 0) {
getAncestorMergeViewer().getControl().setVisible(true);
getAncestorMergeViewer().getControl().setBounds(x, y, width, height);
} else {
getAncestorMergeViewer().getControl().setVisible(false);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeLeftRight(int, int, int,
* int, int, int)
*/
@Override
protected void handleResizeLeftRight(int x, int y, int width1, int centerWidth, int width2, int height) {
fLeft.getControl().setBounds(x, y, width1, height);
fRight.getControl().setBounds(x + width1 + centerWidth, y, width2, height);
}
/**
* Creates the merge viewer for the given parent and the given side.
*
* @param parent
* composite in which to create the merge viewer.
* @param side
* the side of the new viewer.
* @return a new merge viewer.
*/
protected abstract IMergeViewer createMergeViewer(Composite parent, MergeViewerSide side);
@Override
protected final int getCenterWidth() {
return CENTER_WIDTH;
}
protected final CompareHandlerService getHandlerService() {
return (CompareHandlerService)fDynamicObject.get(HANDLER_SERVICE);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getControl()
*/
@Override
public Composite getControl() {
return (Composite)super.getControl();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createCenterControl(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createCenterControl(final Composite parent) {
final Sash ret = (Sash)super.createCenterControl(parent);
final SelectionAdapter selectionListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
SWTUtil.safeAsyncExec(new Runnable() {
public void run() {
parent.layout();
}
});
}
};
ret.addSelectionListener(selectionListener);
final PaintListener paintListener = new PaintListener() {
public void paintControl(PaintEvent e) {
paintCenter(e.gc);
}
};
ret.addPaintListener(paintListener);
ret.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
ret.removePaintListener(paintListener);
ret.removeSelectionListener(selectionListener);
}
});
return ret;
}
protected abstract void paintCenter(GC g);
public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
if (adapter == CompareHandlerService.class) {
return getHandlerService();
}
if (adapter == CompareHandlerService[].class) {
return new CompareHandlerService[] {getHandlerService(), };
}
return null;
}
/**
* @return the fAncestor
*/
protected IMergeViewer getAncestorMergeViewer() {
return fAncestor;
}
/**
* @return the fLeft
*/
protected IMergeViewer getLeftMergeViewer() {
return fLeft;
}
/**
* @return the fRight
*/
protected IMergeViewer getRightMergeViewer() {
return fRight;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
public void selectionChanged(SelectionChangedEvent event) {
synchronizeSelection(event);
updateToolItems();
}
private void synchronizeSelection(SelectionChangedEvent event) {
if (fSyncingSelections.compareAndSet(false, true)) { // prevents stack overflow :)
try {
ISelection selection = event.getSelection();
updatePropertiesView(selection);
fLeft.setSelection(selection, true);
fRight.setSelection(selection, true);
fAncestor.setSelection(selection, true);
} finally {
fSyncingSelections.set(false);
}
}
}
/**
* Update the properties view with the given selection.
*
* @param selection
* the given selection.
*/
private void updatePropertiesView(ISelection selection) {
if (!PlatformUI.isWorkbenchRunning()) {
// no update of property view outside of workbench
return;
}
if (selection instanceof StructuredSelection) {
StructuredSelection structuredSelection = (StructuredSelection)selection;
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
final ExtendedPropertySheetPage propertySheetPage = getExtendedPropertySheetPage(page);
if (propertySheetPage != null) {
StructuredSelection selectionForPropertySheet = null;
final IWorkbenchPart activePart = page.getActivePart();
Object firstElement = structuredSelection.getFirstElement();
if (firstElement instanceof MergeViewerItem) {
MergeViewerItem mergeViewerItem = (MergeViewerItem)firstElement;
MergeViewerSide side = mergeViewerItem.getSide();
Object newSelectedObject = mergeViewerItem.getSideValue(side);
propertySheetPage.setPropertySourceProvider(fAdapterFactoryContentProvider);
getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
propertySheetPage.setPropertySourceProvider(null);
// bug 551238 : protect from potential NPEs
if (propertySheetPage.getControl() != null
&& !propertySheetPage.getControl().isDisposed()) {
propertySheetPage.selectionChanged(activePart, null);
}
}
});
if (newSelectedObject != null) {
if (newSelectedObject instanceof EObject) {
manageReadOnly((EObject)newSelectedObject, side);
}
selectionForPropertySheet = new StructuredSelection(newSelectedObject);
propertySheetPage.selectionChanged(activePart, selectionForPropertySheet);
}
}
if (selectionForPropertySheet == null) {
selectionForPropertySheet = new StructuredSelection(new Object());
propertySheetPage.selectionChanged(activePart, selectionForPropertySheet);
}
}
}
}
/**
* Returns the extended property sheet page.
*
* @return the extended property sheet page.
*/
private ExtendedPropertySheetPage getExtendedPropertySheetPage(IWorkbenchPage activePage) {
ExtendedPropertySheetPage propertyPage = null;
if (activePage != null) {
IViewPart view = activePage.findView("org.eclipse.ui.views.PropertySheet"); //$NON-NLS-1$
if (view != null) {
if (view instanceof PropertySheet) {
PropertySheet propertySheet = (PropertySheet)view;
IPage currentPage = propertySheet.getCurrentPage();
if (currentPage instanceof ExtendedPropertySheetPage) {
propertyPage = (ExtendedPropertySheetPage)currentPage;
} else {
IEditorPart activeEditor = activePage.getActiveEditor();
if (activeEditor != null && Platform.getAdapterManager().hasAdapter(activeEditor,
"org.eclipse.ui.views.properties.IPropertySheetPage")) { //$NON-NLS-1$
propertySheet.partActivated(activePage.getActivePart());
}
}
}
}
}
return propertyPage;
}
/**
* Manages the read-only state of the properties sheet page for the given selected object.
*
* @param selectedObject
* the given selected object.
* @param side
* the side of the selected object.
*/
private void manageReadOnly(EObject selectedObject, MergeViewerSide side) {
if (MergeViewerSide.LEFT == side) {
if (!getCompareConfiguration().isLeftEditable()) {
setToReadOnly(selectedObject);
}
} else if (MergeViewerSide.RIGHT == side) {
if (!getCompareConfiguration().isRightEditable()) {
setToReadOnly(selectedObject);
}
} else if (MergeViewerSide.ANCESTOR == side) {
setToReadOnly(selectedObject);
}
}
/**
* Sets the resource of the selected object to read-only in the appropriate editing domain.
*
* @param selectedObject
* the given selected object.
*/
private void setToReadOnly(EObject selectedObject) {
EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(selectedObject);
if (editingDomain instanceof AdapterFactoryEditingDomain) {
Resource r = selectedObject.eResource();
Map<Resource, Boolean> resourceToReadOnlyMap = ((AdapterFactoryEditingDomain)editingDomain)
.getResourceToReadOnlyMap();
if (!resourceToReadOnlyMap.containsKey(r)) {
resourceToReadOnlyMap.put(r, Boolean.TRUE);
}
}
}
/**
* Checks the element selected in the given viewer in order to determine whether it can be adapted into a
* Diff.
*
* @param viewer
* The viewer which selection is to be checked.
* @return The first of the Diffs selected in the given viewer, if any.
*/
protected Diff getDiffFrom(IMergeViewer viewer) {
Diff diff = null;
final ISelection selection = viewer.getSelection();
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
final Iterator<?> selectedElements = ((IStructuredSelection)selection).iterator();
while (diff == null && selectedElements.hasNext()) {
final Object element = selectedElements.next();
if (element instanceof IMergeViewerItem) {
diff = ((IMergeViewerItem)element).getDiff();
}
}
}
return diff;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
*/
@Override
protected void handleDispose(DisposeEvent event) {
EMFCompareConfiguration compareConfiguration = getCompareConfiguration();
editingDomainChange(compareConfiguration.getEditingDomain(), null);
compareConfiguration.getEventBus().unregister(this);
compareConfiguration.getPreferenceStore().removePropertyChangeListener(propertyChangeListener);
compareConfiguration.disposeListeners();
differenceGroupProvider = null;
undoAction = null;
redoAction = null;
if (fAdapterFactoryContentProvider != null) {
fAdapterFactoryContentProvider.setAdapterFactory(null);
}
if (fColors != null) {
fColors.dispose();
}
super.handleDispose(event);
}
protected final void redrawCenterControl() {
if (getCenterControl() != null) {
SWTUtil.safeRedraw(getCenterControl(), false);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getCompareConfiguration()
*/
@Override
protected EMFCompareConfiguration getCompareConfiguration() {
return (EMFCompareConfiguration)super.getCompareConfiguration();
}
@Override
protected void flushContent(Object input, IProgressMonitor monitor) {
super.flushContent(input, monitor);
mergeResolutionManager.handleFlush(input);
}
/**
* {@inheritDoc}
* <p>
* This override uses a {@link MirrorManager} to intercept switches to the swap preference for controlling
* the mirror mode. When that preference property changes, {@link #handleMirroredChanged()} is called.
* </p>
*/
@Override
protected void handlePropertyChangeEvent(PropertyChangeEvent event) {
if (mirrorManager != null && mirrorManager.handlePropertyChangeEvent(event)) {
handleMirroredChanged();
} else {
super.handlePropertyChangeEvent(event);
}
}
/**
* This does the processing
*/
protected void handleMirroredChanged() {
Composite parent = getControl().getParent();
if (parent instanceof CompareViewerSwitchingPane) {
// Disable painting during the switching to avoid flicker of the toolbar and other controls.
parent.setRedraw(false);
try {
CompareViewerSwitchingPane switchingPane = (CompareViewerSwitchingPane)parent;
Object input = switchingPane.getInput();
switchingPane.setInput(null);
switchingPane.setInput(input);
} finally {
parent.setRedraw(true);
}
}
}
}