/**
* Copyright (c) 2015-2016 Intel Corporation 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:
* Stephane Bouchet (Intel Corporation) - initial API and implementation
* Olivier Constant (Thales Global Services) - tight integration
*/
package org.eclipse.emf.diffmerge.connector.core.ext;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.HashSet;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.ICompareContainer;
import org.eclipse.compare.INavigatable;
import org.eclipse.compare.IPropertyChangeNotifier;
import org.eclipse.compare.contentmergeviewer.IFlushable;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.diffmerge.api.Role;
import org.eclipse.emf.diffmerge.connector.core.EMFDiffMergeCoreConnectorPlugin;
import org.eclipse.emf.diffmerge.connector.core.Messages;
import org.eclipse.emf.diffmerge.ui.EMFDiffMergeUIPlugin;
import org.eclipse.emf.diffmerge.ui.setup.ComparisonSetup;
import org.eclipse.emf.diffmerge.ui.setup.ComparisonSetupManager;
import org.eclipse.emf.diffmerge.ui.setup.EMFDiffMergeEditorInput;
import org.eclipse.emf.diffmerge.ui.viewers.AbstractComparisonViewer;
import org.eclipse.emf.diffmerge.ui.viewers.EMFDiffNode;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
/**
* A viewer that can convert an ICompareInput to a model comparison input in Team usage scenarios.
* It wraps the usual comparison viewer.
*/
public class TeamComparisonViewer extends Viewer implements IFlushable, IPropertyChangeNotifier {
/** The non-null control of the viewer */
protected final Composite _control;
/** The optional compare configuration */
protected CompareConfiguration _configuration;
/** The non-null set of listeners that are still to be registered */
protected final Collection<IPropertyChangeListener> _pendingListeners;
/** The initially null actual comparison viewer */
protected AbstractComparisonViewer _innerViewer;
/** The potentially null input of this viewer */
protected Object _input;
/**
* Constructor
* @param parent_p a non-null composite
* @param configuration_p an optional compare configuration
*/
public TeamComparisonViewer(Composite parent_p, CompareConfiguration configuration_p) {
_configuration = configuration_p;
_control = createControl(parent_p);
_pendingListeners = new HashSet<IPropertyChangeListener>();
_innerViewer = null;
_input = null;
}
/**
* @see org.eclipse.compare.IPropertyChangeNotifier#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
*/
public void addPropertyChangeListener(IPropertyChangeListener listener_p) {
if (_innerViewer == null && !_control.isDisposed()) {
// Inner viewer not created yet: register listener later
_pendingListeners.add(listener_p);
} else {
_innerViewer.addPropertyChangeListener(listener_p);
}
}
/**
* Close the active editor without saving
*/
protected void closeEditor() {
IWorkbenchWindow activeWorkbenchWindow =
EMFDiffMergeUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null) {
IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
if (page != null) {
IEditorPart editor = page.getActiveEditor();
if (editor != null)
page.closeEditor(editor, false);
}
}
}
/**
* Create and return the control of this viewer in the context of the given parent composite
* @param parent_p a non-null composite
* @return a non-null control
*/
protected Composite createControl(Composite parent_p) {
Composite result = new Composite(parent_p, SWT.NONE);
// For switching pane combo label, see CompareContentViewerSwitchingPane#setText(String)
result.setData(CompareUI.COMPARE_VIEWER_TITLE,
EMFDiffMergeCoreConnectorPlugin.getDefault().getViewerLabel());
GridLayout layout = new GridLayout(1, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
result.setLayout(layout);
result.addDisposeListener(new DisposeListener() {
/**
* @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
*/
public void widgetDisposed(DisposeEvent e_p) {
handleDispose();
}
});
registerNavigatable(result);
return result;
}
/**
* Create and return a compare editor input from the given setup manager and
* the given entry points
* @param manager_p a non null comparison manager
* @param left_p the left side model
* @param right_p the right side model
* @param ancestor_p the ancestor side model
* @return a compare input or null
*/
protected EMFDiffMergeEditorInput createEditorInput(
ComparisonSetupManager manager_p, Object left_p, Object right_p,
Object ancestor_p) {
// Prompt user for comparison method
ComparisonSetup setup = manager_p.createComparisonSetup(left_p, right_p,
ancestor_p);
if (setup != null) {
setup.setTwoWayReferenceRole(Role.REFERENCE);
setup.setCanChangeTwoWayReferenceRole(false);
setup.setCanSwapScopeDefinitions(false);
}
return manager_p.createEditorInputWithUI(getShell(), setup);
}
/**
* @see org.eclipse.compare.contentmergeviewer.IFlushable#flush(org.eclipse.core.runtime.IProgressMonitor)
*/
public void flush(IProgressMonitor monitor_p) {
if (_innerViewer != null)
_innerViewer.flush(monitor_p);
}
/**
* @see org.eclipse.jface.viewers.Viewer#getControl()
*/
@Override
public Control getControl() {
return _control;
}
/**
* @see org.eclipse.jface.viewers.Viewer#getInput()
*/
@Override
public Object getInput() {
return _input;
}
/**
* @see org.eclipse.jface.viewers.Viewer#getSelection()
*/
@Override
public ISelection getSelection() {
return (_innerViewer == null)? null: _innerViewer.getSelection();
}
/**
* Return the shell of the graphical context
* @return a non-null shell
*/
protected Shell getShell() {
return _control.getShell();
}
/**
* Dispose this viewer as a reaction to the disposal of its control
*/
protected void handleDispose() {
_configuration = null; // Disposed by editor input if needed
_pendingListeners.clear();
_innerViewer = null;
_input = null;
}
/**
* @see org.eclipse.jface.viewers.Viewer#refresh()
*/
@Override
public void refresh() {
if (_innerViewer != null)
_innerViewer.refresh();
}
/**
* Register a navigatable for navigation from the workbench toolbar buttons
* @param control_p the non-null control of this viewer
*/
protected void registerNavigatable(Composite control_p) {
INavigatable navigatable = new INavigatable() {
/**
* Return the delegate navigatable, if any
* @return a potentially null object
*/
protected INavigatable getDelegate() {
INavigatable navResult = null;
if (_innerViewer != null)
navResult = _innerViewer.getNavigatable();
return navResult;
}
/**
* @see org.eclipse.compare.INavigatable#getInput()
*/
public Object getInput() {
return TeamComparisonViewer.this.getInput();
}
/**
* @see org.eclipse.compare.INavigatable#hasChange(int)
*/
public boolean hasChange(int changeFlag_p) {
boolean result = false;
INavigatable delegate = getDelegate();
if (delegate != null)
result = delegate.hasChange(changeFlag_p);
return result;
}
/**
* @see org.eclipse.compare.INavigatable#openSelectedChange()
*/
public boolean openSelectedChange() {
boolean result = false;
INavigatable delegate = getDelegate();
if (delegate != null)
result = delegate.openSelectedChange();
return result;
}
/**
* @see org.eclipse.compare.INavigatable#selectChange(int)
*/
public boolean selectChange(int changeFlag_p) {
boolean result = false;
INavigatable delegate = getDelegate();
if (delegate != null)
result = delegate.selectChange(changeFlag_p);
return result;
}
};
control_p.setData(INavigatable.NAVIGATOR_PROPERTY, navigatable);
}
/**
* @see org.eclipse.compare.IPropertyChangeNotifier#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
*/
public void removePropertyChangeListener(IPropertyChangeListener listener_p) {
if (_innerViewer != null) {
_innerViewer.removePropertyChangeListener(listener_p);
} else {
// In case inner viewer has not been created yet
_pendingListeners.remove(listener_p);
// Otherwise, listener list of inner viewer is automatically cleared at disposal time
}
}
/**
* @see org.eclipse.jface.viewers.Viewer#setInput(java.lang.Object)
*/
@Override
public void setInput(Object input_p) {
if (input_p == _input)
return;
_input = input_p;
if (input_p instanceof EMFDiffNode || input_p == null) {
// Can be directly handled by inner viewer
if (_innerViewer != null)
_innerViewer.setInput(input_p);
} else if (input_p instanceof ICompareInput) {
// Requires preliminary work
Object left = ((ICompareInput) input_p).getLeft();
Object right = ((ICompareInput) input_p).getRight();
Object ancestor = ((ICompareInput) input_p).getAncestor();
if (right != null && right.equals(ancestor))
ancestor = null; // Just use REFERENCE as two-way reference role
// Prompt user for comparison method
ComparisonSetupManager manager = EMFDiffMergeUIPlugin.getDefault().getSetupManager();
try {
EMFDiffMergeEditorInput editorInput = createEditorInput(manager, left, right, ancestor);
if (editorInput != null) {
// Not failed/cancelled
if (_configuration != null) {
// Register container for action bars
ICompareContainer compareContainer = _configuration.getContainer();
if (compareContainer != null)
editorInput.setContainer(compareContainer);
}
try {
// Compute comparison
ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
dialog.run(true, true, editorInput);
} catch (InvocationTargetException e) {
EMFDiffMergeCoreConnectorPlugin.getDefault().logError(e);
} catch (InterruptedException e) {
EMFDiffMergeCoreConnectorPlugin.getDefault().logError(e);
}
EMFDiffNode compareResult = editorInput.getCompareResult();
if (compareResult != null) {
// Success: create the viewer and set the input
Control contents = editorInput.createContents(_control);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
contents.setLayoutData(layoutData);
_innerViewer = editorInput.getViewer();
_control.pack();
_control.getParent().layout();
// Register pending listeners
for (IPropertyChangeListener listener : _pendingListeners) {
_innerViewer.addPropertyChangeListener(listener);
}
_pendingListeners.clear();
} else {
// Failure (no diff): close the viewer and open a dialog
_innerViewer = null;
String message = editorInput.getMessage();
if (message == null || message.length() == 0) {
MessageDialog.openInformation(getShell(),
Messages.TeamComparisonViewer_NoDiff_Title,
Messages.TeamComparisonViewer_NoDiff_Message);
} else {
MessageDialog.openError(
getShell(), Messages.TeamComparisonViewer_NoDiff_Title, message);
}
closeEditor();
}
}
} catch (IllegalArgumentException e) {
manager.handleSetupError(getShell(), e.getLocalizedMessage());
}
}
}
/**
* @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
*/
@Override
public void setSelection(ISelection selection_p, boolean reveal_p) {
if (_innerViewer != null)
_innerViewer.setSelection(selection_p, reveal_p);
}
}