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
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
;
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
;
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());
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
);
180 public void colorChanged(
181 @SuppressWarnings("unused") /* necessary for @Subscribe */IColorChangeEvent changeColorEvent
) {
182 getControl().redraw();
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)
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
);
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
;
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()
246 return differenceGroupProvider
;
252 * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.ICompareColorProvider#getCompareColor()
254 public ICompareColor
getCompareColor() {
261 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#updateContent(java.lang.Object,
262 * java.lang.Object, java.lang.Object)
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);
283 fRight
.setSelection(new StructuredSelection(rightInitialItem
), true);
286 // Strange case: left is an ICompareAccessor but right is not?
287 fLeft
.setSelection(StructuredSelection
.EMPTY
, true);
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,
303 protected boolean doSave(Object newInput
, Object oldInput
) {
310 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createControls(org.eclipse.swt.widgets.Composite)
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
) {
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();
358 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createToolItems(org.eclipse.jface.action.ToolBarManager)
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
) {
407 if (getCompareConfiguration().getEditingDomain() != null) {
408 ICompareCommandStack commandStack
= getCompareConfiguration().getEditingDomain()
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.
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();
458 * From the given selection, get the model element from the given side.
461 * the given selection.
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();
492 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#copy(boolean)
495 protected void copy(final boolean leftToRight
) {
496 // do nothing, merge is done through merge actions in structure merge viewer.
502 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeAncestor(int, int, int, int)
505 protected void handleResizeAncestor(int x
, int y
, int width
, int height
) {
507 getAncestorMergeViewer().getControl().setVisible(true);
508 getAncestorMergeViewer().getControl().setBounds(x
, y
, width
, height
);
510 getAncestorMergeViewer().getControl().setVisible(false);
517 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeLeftRight(int, int, int,
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
);
529 protected final int getCenterWidth() {
533 protected final CompareHandlerService
getHandlerService() {
534 return (CompareHandlerService
)fDynamicObject
.get(HANDLER_SERVICE
);
540 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getControl()
543 public Composite
getControl() {
544 return (Composite
)super.getControl();
550 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#createCenterControl(org.eclipse.swt.widgets.Composite)
553 protected Control
createCenterControl(final Composite parent
) {
554 final Sash ret
= (Sash
)super.createCenterControl(parent
);
556 final SelectionAdapter selectionListener
= new SelectionAdapter() {
558 public void widgetSelected(SelectionEvent e
) {
559 SWTUtil
.safeAsyncExec(new Runnable() {
567 ret
.addSelectionListener(selectionListener
);
569 final PaintListener paintListener
= new PaintListener() {
570 public void paintControl(PaintEvent e
) {
574 ret
.addPaintListener(paintListener
);
576 ret
.addDisposeListener(new DisposeListener() {
577 public void widgetDisposed(DisposeEvent e
) {
578 ret
.removePaintListener(paintListener
);
579 ret
.removeSelectionListener(selectionListener
);
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(), };
599 * @return the fAncestor
601 protected IMergeViewer
getAncestorMergeViewer() {
608 protected IMergeViewer
getLeftMergeViewer() {
615 protected IMergeViewer
getRightMergeViewer() {
622 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
624 public void selectionChanged(SelectionChangedEvent event
) {
625 synchronizeSelection(event
);
629 private void synchronizeSelection(SelectionChangedEvent event
) {
630 if (fSyncingSelections
.compareAndSet(false, true)) { // prevents stack overflow :)
632 ISelection selection
= event
.getSelection();
633 updatePropertiesView(selection
);
634 fLeft
.setSelection(selection
, true);
635 fRight
.setSelection(selection
, true);
636 fAncestor
.setSelection(selection
, true);
638 fSyncingSelections
.set(false);
645 * Update the properties view with the given selection.
648 * the given selection.
650 private void updatePropertiesView(ISelection selection
) {
651 if (!PlatformUI
.isWorkbenchRunning()) {
652 // no update of property view outside of workbench
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$
701 if (view
instanceof PropertySheet
) {
702 PropertySheet propertySheet
= (PropertySheet
)view
;
703 IPage currentPage
= propertySheet
.getCurrentPage();
704 if (currentPage
instanceof ExtendedPropertySheetPage
) {
705 propertyPage
= (ExtendedPropertySheetPage
)currentPage
;
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());
721 * Manages the read-only state of the properties sheet page for the given selected object.
723 * @param selectedObject
724 * the given selected object.
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
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
) {
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();
786 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
789 protected void handleDispose(DisposeEvent event
) {
790 editingDomainChange(getCompareConfiguration().getEditingDomain(), null);
791 getCompareConfiguration().getEventBus().unregister(this);
792 differenceGroupProvider
= null;
795 if (fAdapterFactoryContentProvider
!= null) {
796 fAdapterFactoryContentProvider
.setAdapterFactory(null);
798 if (fColors
!= null) {
801 super.handleDispose(event
);
804 protected final void redrawCenterControl() {
805 if (getCenterControl() != null) {
806 SWTUtil
.safeRedraw(getCenterControl(), false);
813 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getCompareConfiguration()
816 protected EMFCompareConfiguration
getCompareConfiguration() {
817 return (EMFCompareConfiguration
)super.getCompareConfiguration();
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
842 * @return side to be used based on the current mirror state.
844 protected MergeViewerSide
computeSide(MergeViewerSide side
) {
846 return side
.opposite();
852 * Returns the content provider that should be used when this viewer is NOT {@link #isMirrored()
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
) {
882 setContentProvider(getMirroredContentProvider());
884 setContentProvider(getUnmirroredContentProvider());