[529212] Dispose EMFCompareColor
[EMFCompare2.git] / plugins / org.eclipse.emf.compare.ide.ui / src / org / eclipse / emf / compare / ide / ui / internal / contentmergeviewer / EMFCompareContentMergeViewer.java
blob3ae062f8c9fe59a26aa68490e08f0deeb2504406
1 /*******************************************************************************
2 * Copyright (c) 2012, 2017 Obeo and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Obeo - initial API and implementation
10 * Michael Borkowski - bug 462863
11 * Stefan Dirix - bug 473985
12 * Philip Langer - bug 516645
13 * Martin Fleck - bug 514079
14 *******************************************************************************/
15 package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer;
17 import com.google.common.base.Predicate;
18 import com.google.common.eventbus.Subscribe;
20 import java.util.Collection;
21 import java.util.EventObject;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.ResourceBundle;
25 import java.util.concurrent.atomic.AtomicBoolean;
27 import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
28 import org.eclipse.compare.internal.CompareHandlerService;
29 import org.eclipse.core.runtime.IAdaptable;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.Platform;
32 import org.eclipse.emf.common.command.Command;
33 import org.eclipse.emf.common.command.CommandStack;
34 import org.eclipse.emf.common.command.CommandStackListener;
35 import org.eclipse.emf.common.notify.AdapterFactory;
36 import org.eclipse.emf.compare.Diff;
37 import org.eclipse.emf.compare.command.ICompareCommandStack;
38 import org.eclipse.emf.compare.command.ICompareCopyCommand;
39 import org.eclipse.emf.compare.domain.ICompareEditingDomain;
40 import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
41 import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
42 import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.DynamicObject;
43 import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.EMFCompareColor;
44 import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.RedoAction;
45 import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.UndoAction;
46 import org.eclipse.emf.compare.ide.ui.mergeresolution.MergeResolutionManager;
47 import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
48 import org.eclipse.emf.compare.rcp.ui.internal.configuration.IAdapterFactoryChange;
49 import org.eclipse.emf.compare.rcp.ui.internal.configuration.ICompareEditingDomainChange;
50 import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.IColorChangeEvent;
51 import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem;
52 import org.eclipse.emf.compare.rcp.ui.internal.util.SWTUtil;
53 import org.eclipse.emf.compare.rcp.ui.mergeviewer.ICompareColor;
54 import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer;
55 import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
56 import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
57 import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.IDifferenceFilterChange;
58 import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider;
59 import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProviderChange;
60 import org.eclipse.emf.ecore.EObject;
61 import org.eclipse.emf.ecore.resource.Resource;
62 import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
63 import org.eclipse.emf.edit.domain.EditingDomain;
64 import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
65 import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage;
66 import org.eclipse.jface.action.Action;
67 import org.eclipse.jface.action.ActionContributionItem;
68 import org.eclipse.jface.action.IAction;
69 import org.eclipse.jface.action.IContributionItem;
70 import org.eclipse.jface.action.ToolBarManager;
71 import org.eclipse.jface.viewers.IContentProvider;
72 import org.eclipse.jface.viewers.ISelection;
73 import org.eclipse.jface.viewers.ISelectionChangedListener;
74 import org.eclipse.jface.viewers.IStructuredSelection;
75 import org.eclipse.jface.viewers.SelectionChangedEvent;
76 import org.eclipse.jface.viewers.StructuredSelection;
77 import org.eclipse.jface.viewers.TreeSelection;
78 import org.eclipse.jface.viewers.Viewer;
79 import org.eclipse.swt.events.ControlEvent;
80 import org.eclipse.swt.events.ControlListener;
81 import org.eclipse.swt.events.DisposeEvent;
82 import org.eclipse.swt.events.DisposeListener;
83 import org.eclipse.swt.events.PaintEvent;
84 import org.eclipse.swt.events.PaintListener;
85 import org.eclipse.swt.events.SelectionAdapter;
86 import org.eclipse.swt.events.SelectionEvent;
87 import org.eclipse.swt.graphics.GC;
88 import org.eclipse.swt.widgets.Composite;
89 import org.eclipse.swt.widgets.Control;
90 import org.eclipse.swt.widgets.Sash;
91 import org.eclipse.ui.IEditorPart;
92 import org.eclipse.ui.IViewPart;
93 import org.eclipse.ui.IWorkbenchPage;
94 import org.eclipse.ui.IWorkbenchPart;
95 import org.eclipse.ui.PlatformUI;
96 import org.eclipse.ui.actions.ActionFactory;
97 import org.eclipse.ui.menus.IMenuService;
98 import org.eclipse.ui.part.IPage;
99 import org.eclipse.ui.services.IServiceLocator;
100 import org.eclipse.ui.themes.ITheme;
101 import org.eclipse.ui.themes.IThemeManager;
102 import org.eclipse.ui.views.properties.PropertySheet;
105 * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
107 public abstract class EMFCompareContentMergeViewer extends ContentMergeViewer implements ISelectionChangedListener, ICompareColor.Provider, IAdaptable, CommandStackListener {
109 private static final String HANDLER_SERVICE = "fHandlerService"; //$NON-NLS-1$
112 * Width of center bar
114 protected static final int CENTER_WIDTH = 34;
116 private IMergeViewer fAncestor;
118 private IMergeViewer fLeft;
120 private IMergeViewer fRight;
122 private final AtomicBoolean fSyncingSelections = new AtomicBoolean(false);
124 private EMFCompareColor fColors;
126 private final DynamicObject fDynamicObject;
128 private UndoAction undoAction;
130 private RedoAction redoAction;
132 private AdapterFactoryContentProvider fAdapterFactoryContentProvider;
134 private Predicate<? super EObject> differenceFilterPredicate;
136 private IDifferenceGroupProvider differenceGroupProvider;
138 private MergeResolutionManager mergeResolutionManager;
140 private Boolean fIsMirrored;
143 * @param style
144 * @param bundle
145 * @param cc
147 protected EMFCompareContentMergeViewer(int style, ResourceBundle bundle, EMFCompareConfiguration cc) {
148 super(style, new EMFCompareContentMergeViewerResourceBundle(bundle), cc);
150 fDynamicObject = new DynamicObject(this);
152 if (getCompareConfiguration().getAdapterFactory() != null) {
153 fAdapterFactoryContentProvider = new AdapterFactoryContentProvider(
154 getCompareConfiguration().getAdapterFactory());
157 redoAction = new RedoAction(getCompareConfiguration().getEditingDomain());
158 undoAction = new UndoAction(getCompareConfiguration().getEditingDomain());
160 editingDomainChange(null, getCompareConfiguration().getEditingDomain());
161 getCompareConfiguration().getEventBus().register(this);
163 mergeResolutionManager = new MergeResolutionManager(
164 EMFCompareIDEUIPlugin.getDefault().getMergeResolutionListenerRegistry());
167 @Subscribe
168 public void handleAdapterFactoryChange(IAdapterFactoryChange event) {
169 AdapterFactory oldValue = event.getOldValue();
170 AdapterFactory newValue = event.getNewValue();
171 if (oldValue != null) {
172 fAdapterFactoryContentProvider.dispose();
174 if (newValue != oldValue) {
175 fAdapterFactoryContentProvider = new AdapterFactoryContentProvider(newValue);
179 @Subscribe
180 public void colorChanged(
181 @SuppressWarnings("unused") /* necessary for @Subscribe */IColorChangeEvent changeColorEvent) {
182 getControl().redraw();
186 * {@inheritDoc}
188 * @see org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration#editingDomainChange(org.eclipse.emf.compare.domain.ICompareEditingDomain,
189 * org.eclipse.emf.compare.domain.ICompareEditingDomain)
191 @Subscribe
192 public void handleEditingDomainChange(ICompareEditingDomainChange event) {
193 ICompareEditingDomain oldValue = event.getOldValue();
194 ICompareEditingDomain newValue = event.getNewValue();
195 editingDomainChange(oldValue, newValue);
198 protected void editingDomainChange(ICompareEditingDomain oldValue, ICompareEditingDomain newValue) {
199 if (oldValue != null) {
200 ICompareCommandStack commandStack = oldValue.getCommandStack();
201 commandStack.removeCommandStackListener(this);
203 if (newValue != oldValue) {
204 if (newValue != null) {
205 ICompareCommandStack commandStack = newValue.getCommandStack();
206 commandStack.addCommandStackListener(this);
207 setLeftDirty(commandStack.isLeftSaveNeeded());
208 setRightDirty(commandStack.isRightSaveNeeded());
210 undoAction.setEditingDomain(newValue);
211 redoAction.setEditingDomain(newValue);
215 @Subscribe
216 public void handleDifferenceFiltersChange(IDifferenceFilterChange event) {
217 differenceFilterPredicate = event.getPredicate();
218 redrawCenterControl();
222 * @return the differenceFilterPredicate
224 protected final Predicate<? super EObject> getDifferenceFilterPredicate() {
225 if (differenceFilterPredicate == null) {
226 differenceFilterPredicate = getCompareConfiguration().getStructureMergeViewerFilter()
227 .getAggregatedPredicate();
229 return differenceFilterPredicate;
232 @Subscribe
233 public void handleDifferenceGroupProviderChange(IDifferenceGroupProviderChange event) {
234 differenceGroupProvider = event.getDifferenceGroupProvider();
235 redrawCenterControl();
239 * @return the differenceGroupProvider
241 protected final IDifferenceGroupProvider getDifferenceGroupProvider() {
242 if (differenceGroupProvider == null) {
243 differenceGroupProvider = getCompareConfiguration().getStructureMergeViewerGrouper()
244 .getProvider();
246 return differenceGroupProvider;
250 * {@inheritDoc}
252 * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.ICompareColorProvider#getCompareColor()
254 public ICompareColor getCompareColor() {
255 return fColors;
259 * {@inheritDoc}
261 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#updateContent(java.lang.Object,
262 * java.lang.Object, java.lang.Object)
264 @Override
265 protected void updateContent(Object ancestor, Object left, Object right) {
266 fAncestor.setInput(ancestor);
267 fLeft.setInput(left);
268 fRight.setInput(right);
270 IMergeViewerItem leftInitialItem = null;
271 if (left instanceof ICompareAccessor) {
272 leftInitialItem = ((ICompareAccessor)left).getInitialItem();
274 // Bug 458818: In some cases, the left initial item is null because
275 // the item that should be selected has been deleted on the right
276 // and this delete is part of a conflict
277 if (leftInitialItem == null) {
278 if (right instanceof ICompareAccessor) {
279 IMergeViewerItem rightInitialItem = ((ICompareAccessor)right).getInitialItem();
280 if (rightInitialItem == null) {
281 fLeft.setSelection(StructuredSelection.EMPTY, true);
282 } else {
283 fRight.setSelection(new StructuredSelection(rightInitialItem), true);
285 } else {
286 // Strange case: left is an ICompareAccessor but right is not?
287 fLeft.setSelection(StructuredSelection.EMPTY, true);
289 } else {
290 // others will synchronize on this one :)
291 fLeft.setSelection(new StructuredSelection(leftInitialItem), true);
293 redrawCenterControl();
297 * Inhibits this method to avoid asking to save on each input change!!
299 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#doSave(java.lang.Object,
300 * java.lang.Object)
302 @Override
303 protected boolean doSave(Object newInput, Object oldInput) {
304 return false;
308 * {@inheritDoc}
310 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createControls(org.eclipse.swt.widgets.Composite)
312 @Override
313 protected void createControls(Composite composite) {
314 fAncestor = createMergeViewer(composite, MergeViewerSide.ANCESTOR);
315 fAncestor.addSelectionChangedListener(this);
317 fLeft = createMergeViewer(composite, MergeViewerSide.LEFT);
318 fLeft.addSelectionChangedListener(this);
320 fRight = createMergeViewer(composite, MergeViewerSide.RIGHT);
321 fRight.addSelectionChangedListener(this);
323 final ITheme currentTheme = getCurrentTheme();
325 boolean leftIsLocal = getCompareConfiguration().getBooleanProperty("LEFT_IS_LOCAL", false);
326 fColors = new EMFCompareColor(composite.getDisplay(), leftIsLocal, currentTheme,
327 getCompareConfiguration().getEventBus());
329 composite.addControlListener(new ControlListener() {
330 public void controlResized(ControlEvent e) {
331 redrawCenterControl();
334 public void controlMoved(ControlEvent e) {
335 // Do nothing.
341 * Determines the current used theme.
343 * @return The currently used theme if available, {@code null} otherwise.
345 private ITheme getCurrentTheme() {
346 if (PlatformUI.isWorkbenchRunning()) {
347 final IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
348 if (themeManager != null) {
349 return themeManager.getCurrentTheme();
352 return null;
356 * {@inheritDoc}
358 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createToolItems(org.eclipse.jface.action.ToolBarManager)
360 @Override
361 protected void createToolItems(final ToolBarManager toolBarManager) {
362 getHandlerService().setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction);
363 getHandlerService().setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction);
365 // switch left and right view action, may be null -> set the initial toggle state of the button
366 Action switchLeftAndRightAction = MirrorUtil.getAction(this);
367 if (switchLeftAndRightAction != null) {
368 switchLeftAndRightAction.setChecked(isMirrored());
371 IContributionItem[] items = toolBarManager.getItems();
372 for (IContributionItem iContributionItem : items) {
373 if (iContributionItem instanceof ActionContributionItem) {
374 IAction action = ((ActionContributionItem)iContributionItem).getAction();
375 String id = action.getActionDefinitionId();
376 if ("org.eclipse.compare.copyAllLeftToRight".equals(id)) {
377 toolBarManager.remove(iContributionItem);
378 } else if ("org.eclipse.compare.copyAllRightToLeft".equals(id)) {
379 toolBarManager.remove(iContributionItem);
384 // Add extension point contributions to the content merge viewer toolbar
385 if (PlatformUI.isWorkbenchRunning()) {
386 IServiceLocator workbench = PlatformUI.getWorkbench();
387 final IMenuService menuService = (IMenuService)workbench.getService(IMenuService.class);
388 if (menuService != null) {
389 menuService.populateContributionManager(toolBarManager,
390 "toolbar:org.eclipse.emf.compare.contentmergeviewer.toolbar"); //$NON-NLS-1$
391 toolBarManager.getControl().addDisposeListener(new DisposeListener() {
392 public void widgetDisposed(DisposeEvent e) {
393 menuService.releaseContributions(toolBarManager);
394 // re-populate and release menu contributions to fix memory leak (see bug 516645)
395 menuService.populateContributionManager(toolBarManager, "nothing"); //$NON-NLS-1$
396 menuService.releaseContributions(toolBarManager);
403 public void commandStackChanged(EventObject event) {
404 undoAction.update();
405 redoAction.update();
407 if (getCompareConfiguration().getEditingDomain() != null) {
408 ICompareCommandStack commandStack = getCompareConfiguration().getEditingDomain()
409 .getCommandStack();
410 setLeftDirty(commandStack.isLeftSaveNeeded());
411 setRightDirty(commandStack.isRightSaveNeeded());
414 final Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand();
415 if (mostRecentCommand instanceof ICompareCopyCommand) {
416 SWTUtil.safeRefresh(this, true, false);
417 } else if (mostRecentCommand != null) {
418 // Model has changed, but not by EMFCompare. Typical case is update from properties view.
419 // In this case, we don't want to refresh all viewers and lost selected element, just refresh
420 // appropriate side and keep selected element.
421 IMergeViewer affectedMergeViewer = getAffectedMergeViewer(mostRecentCommand);
422 if (affectedMergeViewer instanceof Viewer) {
423 SWTUtil.safeRefresh(((Viewer)affectedMergeViewer), true, false);
429 * Get the merge viewer affected by this command.
431 * @param command
432 * the command.
433 * @return the merge viewer affected by this command if found, null otherwise.
435 private IMergeViewer getAffectedMergeViewer(Command command) {
436 final IMergeViewer viewer;
437 final IMergeViewer leftMergeViewer = this.getLeftMergeViewer();
438 final ISelection leftSelection = leftMergeViewer.getSelection();
439 final Collection<?> affectedObjects = command.getAffectedObjects();
440 if (affectedObjects != null && !affectedObjects.isEmpty()) {
441 Object firstAffectedObject = affectedObjects.iterator().next();
442 if (firstAffectedObject.equals(getElement(leftSelection, MergeViewerSide.LEFT))) {
443 viewer = leftMergeViewer;
444 } else if (firstAffectedObject.equals(getElement(leftSelection, MergeViewerSide.RIGHT))) {
445 viewer = this.getRightMergeViewer();
446 } else if (firstAffectedObject.equals(getElement(leftSelection, MergeViewerSide.ANCESTOR))) {
447 viewer = this.getAncestorMergeViewer();
448 } else {
449 viewer = null;
451 } else {
452 viewer = null;
454 return viewer;
458 * From the given selection, get the model element from the given side.
460 * @param selection
461 * the given selection.
462 * @param side
463 * the given side.
464 * @return the model element from the given side if it exists, null otherwise.
466 private Object getElement(ISelection selection, MergeViewerSide side) {
467 final Object element;
468 if (selection instanceof TreeSelection) {
469 Object firstElement = ((TreeSelection)selection).getFirstElement();
470 if (firstElement instanceof IMergeViewerItem) {
471 if (MergeViewerSide.LEFT == side) {
472 element = ((IMergeViewerItem)firstElement).getLeft();
473 } else if (MergeViewerSide.RIGHT == side) {
474 element = ((IMergeViewerItem)firstElement).getRight();
475 } else if (MergeViewerSide.ANCESTOR == side) {
476 element = ((IMergeViewerItem)firstElement).getAncestor();
477 } else {
478 element = null;
480 } else {
481 element = null;
483 } else {
484 element = null;
486 return element;
490 * {@inheritDoc}
492 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#copy(boolean)
494 @Override
495 protected void copy(final boolean leftToRight) {
496 // do nothing, merge is done through merge actions in structure merge viewer.
500 * {@inheritDoc}
502 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeAncestor(int, int, int, int)
504 @Override
505 protected void handleResizeAncestor(int x, int y, int width, int height) {
506 if (width > 0) {
507 getAncestorMergeViewer().getControl().setVisible(true);
508 getAncestorMergeViewer().getControl().setBounds(x, y, width, height);
509 } else {
510 getAncestorMergeViewer().getControl().setVisible(false);
515 * {@inheritDoc}
517 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeLeftRight(int, int, int,
518 * int, int, int)
520 @Override
521 protected void handleResizeLeftRight(int x, int y, int width1, int centerWidth, int width2, int height) {
522 fLeft.getControl().setBounds(x, y, width1, height);
523 fRight.getControl().setBounds(x + width1 + centerWidth, y, width2, height);
526 protected abstract IMergeViewer createMergeViewer(Composite parent, MergeViewerSide side);
528 @Override
529 protected final int getCenterWidth() {
530 return CENTER_WIDTH;
533 protected final CompareHandlerService getHandlerService() {
534 return (CompareHandlerService)fDynamicObject.get(HANDLER_SERVICE);
538 * {@inheritDoc}
540 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getControl()
542 @Override
543 public Composite getControl() {
544 return (Composite)super.getControl();
548 * {@inheritDoc}
550 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createCenterControl(org.eclipse.swt.widgets.Composite)
552 @Override
553 protected Control createCenterControl(final Composite parent) {
554 final Sash ret = (Sash)super.createCenterControl(parent);
556 final SelectionAdapter selectionListener = new SelectionAdapter() {
557 @Override
558 public void widgetSelected(SelectionEvent e) {
559 SWTUtil.safeAsyncExec(new Runnable() {
560 public void run() {
561 parent.layout();
567 ret.addSelectionListener(selectionListener);
569 final PaintListener paintListener = new PaintListener() {
570 public void paintControl(PaintEvent e) {
571 paintCenter(e.gc);
574 ret.addPaintListener(paintListener);
576 ret.addDisposeListener(new DisposeListener() {
577 public void widgetDisposed(DisposeEvent e) {
578 ret.removePaintListener(paintListener);
579 ret.removeSelectionListener(selectionListener);
583 return ret;
586 protected abstract void paintCenter(GC g);
588 public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
589 if (adapter == CompareHandlerService.class) {
590 return getHandlerService();
592 if (adapter == CompareHandlerService[].class) {
593 return new CompareHandlerService[] {getHandlerService(), };
595 return null;
599 * @return the fAncestor
601 protected IMergeViewer getAncestorMergeViewer() {
602 return fAncestor;
606 * @return the fLeft
608 protected IMergeViewer getLeftMergeViewer() {
609 return fLeft;
613 * @return the fRight
615 protected IMergeViewer getRightMergeViewer() {
616 return fRight;
620 * {@inheritDoc}
622 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
624 public void selectionChanged(SelectionChangedEvent event) {
625 synchronizeSelection(event);
626 updateToolItems();
629 private void synchronizeSelection(SelectionChangedEvent event) {
630 if (fSyncingSelections.compareAndSet(false, true)) { // prevents stack overflow :)
631 try {
632 ISelection selection = event.getSelection();
633 updatePropertiesView(selection);
634 fLeft.setSelection(selection, true);
635 fRight.setSelection(selection, true);
636 fAncestor.setSelection(selection, true);
637 } finally {
638 fSyncingSelections.set(false);
645 * Update the properties view with the given selection.
647 * @param selection
648 * the given selection.
650 private void updatePropertiesView(ISelection selection) {
651 if (!PlatformUI.isWorkbenchRunning()) {
652 // no update of property view outside of workbench
653 return;
656 if (selection instanceof StructuredSelection) {
657 StructuredSelection structuredSelection = (StructuredSelection)selection;
658 IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
659 final ExtendedPropertySheetPage propertySheetPage = getExtendedPropertySheetPage(page);
660 if (propertySheetPage != null) {
661 StructuredSelection selectionForPropertySheet = null;
662 final IWorkbenchPart activePart = page.getActivePart();
663 Object firstElement = structuredSelection.getFirstElement();
664 if (firstElement instanceof MergeViewerItem) {
665 MergeViewerItem mergeViewerItem = (MergeViewerItem)firstElement;
666 MergeViewerSide side = mergeViewerItem.getSide();
667 Object newSelectedObject = mergeViewerItem.getSideValue(side);
668 propertySheetPage.setPropertySourceProvider(fAdapterFactoryContentProvider);
669 getControl().addDisposeListener(new DisposeListener() {
670 public void widgetDisposed(DisposeEvent e) {
671 propertySheetPage.selectionChanged(activePart, null);
672 propertySheetPage.setPropertySourceProvider(null);
675 if (newSelectedObject != null) {
676 if (newSelectedObject instanceof EObject) {
677 manageReadOnly((EObject)newSelectedObject, side);
679 selectionForPropertySheet = new StructuredSelection(newSelectedObject);
680 propertySheetPage.selectionChanged(activePart, selectionForPropertySheet);
683 if (selectionForPropertySheet == null) {
684 selectionForPropertySheet = new StructuredSelection(new Object());
685 propertySheetPage.selectionChanged(activePart, selectionForPropertySheet);
692 * Returns the extended property sheet page.
694 * @return the extended property sheet page.
696 private ExtendedPropertySheetPage getExtendedPropertySheetPage(IWorkbenchPage activePage) {
697 ExtendedPropertySheetPage propertyPage = null;
698 if (activePage != null) {
699 IViewPart view = activePage.findView("org.eclipse.ui.views.PropertySheet"); //$NON-NLS-1$
700 if (view != null) {
701 if (view instanceof PropertySheet) {
702 PropertySheet propertySheet = (PropertySheet)view;
703 IPage currentPage = propertySheet.getCurrentPage();
704 if (currentPage instanceof ExtendedPropertySheetPage) {
705 propertyPage = (ExtendedPropertySheetPage)currentPage;
706 } else {
707 IEditorPart activeEditor = activePage.getActiveEditor();
708 if (activeEditor != null && Platform.getAdapterManager().hasAdapter(activeEditor,
709 "org.eclipse.ui.views.properties.IPropertySheetPage")) { //$NON-NLS-1$
710 propertySheet.partActivated(activePage.getActivePart());
717 return propertyPage;
721 * Manages the read-only state of the properties sheet page for the given selected object.
723 * @param selectedObject
724 * the given selected object.
725 * @param side
726 * the side of the selected object.
728 private void manageReadOnly(EObject selectedObject, MergeViewerSide side) {
729 if (MergeViewerSide.LEFT == side) {
730 if (!getCompareConfiguration().isLeftEditable()) {
731 setToReadOnly(selectedObject);
733 } else if (MergeViewerSide.RIGHT == side) {
734 if (!getCompareConfiguration().isRightEditable()) {
735 setToReadOnly(selectedObject);
737 } else if (MergeViewerSide.ANCESTOR == side) {
738 setToReadOnly(selectedObject);
743 * Sets the resource of the selected object to read-only in the appropriate editing domain.
745 * @param selectedObject
746 * the given selected object.
748 private void setToReadOnly(EObject selectedObject) {
749 EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(selectedObject);
750 if (editingDomain instanceof AdapterFactoryEditingDomain) {
751 Resource r = selectedObject.eResource();
752 Map<Resource, Boolean> resourceToReadOnlyMap = ((AdapterFactoryEditingDomain)editingDomain)
753 .getResourceToReadOnlyMap();
754 if (!resourceToReadOnlyMap.containsKey(r)) {
755 resourceToReadOnlyMap.put(r, Boolean.TRUE);
761 * Checks the element selected in the given viewer in order to determine whether it can be adapted into a
762 * Diff.
764 * @param viewer
765 * The viewer which selection is to be checked.
766 * @return The first of the Diffs selected in the given viewer, if any.
768 protected Diff getDiffFrom(IMergeViewer viewer) {
769 Diff diff = null;
770 final ISelection selection = viewer.getSelection();
771 if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
772 final Iterator<?> selectedElements = ((IStructuredSelection)selection).iterator();
773 while (diff == null && selectedElements.hasNext()) {
774 final Object element = selectedElements.next();
775 if (element instanceof IMergeViewerItem) {
776 diff = ((IMergeViewerItem)element).getDiff();
780 return diff;
784 * {@inheritDoc}
786 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
788 @Override
789 protected void handleDispose(DisposeEvent event) {
790 editingDomainChange(getCompareConfiguration().getEditingDomain(), null);
791 getCompareConfiguration().getEventBus().unregister(this);
792 differenceGroupProvider = null;
793 undoAction = null;
794 redoAction = null;
795 if (fAdapterFactoryContentProvider != null) {
796 fAdapterFactoryContentProvider.setAdapterFactory(null);
798 if (fColors != null) {
799 fColors.dispose();
801 super.handleDispose(event);
804 protected final void redrawCenterControl() {
805 if (getCenterControl() != null) {
806 SWTUtil.safeRedraw(getCenterControl(), false);
811 * {@inheritDoc}
813 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getCompareConfiguration()
815 @Override
816 protected EMFCompareConfiguration getCompareConfiguration() {
817 return (EMFCompareConfiguration)super.getCompareConfiguration();
820 @Override
821 protected void flushContent(Object input, IProgressMonitor monitor) {
822 super.flushContent(input, monitor);
823 mergeResolutionManager.handleFlush(input);
827 * Queries the compare configuration whether the left and right side of the viewer should be mirrored.
829 * @return true if the left and right side of the viewer should be mirrored, false otherwise
831 protected boolean isMirrored() {
832 return MirrorUtil.isMirrored(getCompareConfiguration());
836 * Returns the correctly mirrored side for this viewer based on the current {@link #isMirrored() mirrored
837 * state}. If this viewer is not mirrored, the side is returned as is, otherwise its opposite site is
838 * returned.
840 * @param side
841 * merge viewer side
842 * @return side to be used based on the current mirror state.
844 protected MergeViewerSide computeSide(MergeViewerSide side) {
845 if (isMirrored()) {
846 return side.opposite();
848 return side;
852 * Returns the content provider that should be used when this viewer is NOT {@link #isMirrored()
853 * mirrored}.
855 * @return unmirrored content provider
857 protected abstract IContentProvider getUnmirroredContentProvider();
860 * Returns the content provider that should be used when this viewer is {@link #isMirrored() mirrored}.
862 * @return mirrored content provider
864 protected abstract IContentProvider getMirroredContentProvider();
867 * Sets the viewers {@link #isMirrored() mirrored} state and triggers an {@link #updateMirrored(boolean)
868 * update}, if necessary.
870 protected void setMirrored(boolean isMirrored) {
871 if (fIsMirrored == null || fIsMirrored.booleanValue() != isMirrored) {
872 fIsMirrored = Boolean.valueOf(isMirrored);
873 updateMirrored(isMirrored);
878 * Updates the viewer based on its {@link #isMirrored() mirrored} state.
880 protected void updateMirrored(boolean isMirrored) {
881 if (isMirrored) {
882 setContentProvider(getMirroredContentProvider());
883 } else {
884 setContentProvider(getUnmirroredContentProvider());