diff options
author | Mathieu Cartaud | 2015-07-17 07:35:01 +0000 |
---|---|---|
committer | Axel RICHARD | 2015-09-03 07:49:14 +0000 |
commit | 54f662646eb4ab26ab9db705353e208d86dddcc9 (patch) | |
tree | 8eb2360074e24f2c2a2317c14c51dbc2fcc01d7f /plugins/org.eclipse.emf.compare.ide.ui | |
parent | cbcf4cee26550619875225a30418aaa186627fdf (diff) | |
download | org.eclipse.emf.compare-54f662646eb4ab26ab9db705353e208d86dddcc9.tar.gz org.eclipse.emf.compare-54f662646eb4ab26ab9db705353e208d86dddcc9.tar.xz org.eclipse.emf.compare-54f662646eb4ab26ab9db705353e208d86dddcc9.zip |
Implementation of contextual tooltips
1) add tooltips for CHANGE, ADD, DELETE, MOVE actions
2) add adapter for semantic object to compute labels
3) add unit tests
Change-Id: I808c8931e79fc4e10ea0778272b8478e6b1340e0
Signed-off-by: Mathieu Cartaud <mathieu.cartaud@obeo.fr>
Diffstat (limited to 'plugins/org.eclipse.emf.compare.ide.ui')
9 files changed, 1584 insertions, 7 deletions
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties index a15124569..461acec4e 100644 --- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/ide_ui_messages.properties @@ -30,15 +30,19 @@ save.model.tooltip = Save Comparison Model next.diff.tooltip = Next Difference previous.diff.tooltip = Previous Difference accept.change.tooltip = Accept Change -accept.all.changes.tooltip = Accept All Non-Conflicting Changes +accept.multiple.changes.tooltip = Accept non-conflicting changes from the current selection +accept.all.changes.tooltip = Accept All Non-Conflicting Changes. The left changes will be accepted and the right changes will be merged into the left-hand side accept.contained.changes.tooltip = Accept Contained Non-Conflicting Changes reject.change.tooltip = Reject Change -reject.all.changes.tooltip = Reject All Non-Conflicting Changes +reject.multiple.changes.tooltip = Reject non-conflicting changes from the current selection +reject.all.changes.tooltip = Reject All Non-Conflicting Changes. The left changes will be rejected and the right changes will not be used reject.contained.changes.tooltip = Reject Contained Non-Conflicting Changes merged.to.left.tooltip = Copy Current Change From Right To Left +merged.multiple.to.left.tooltip = Apply on the left-hand side all non-conflicting changes from the current selection merged.to.right.tooltip = Copy Current Change From Left To Right -merged.all.to.left.tooltip = Copy All Non-Conflicting Changes From Right To Left -merged.all.to.right.tooltip = Copy All Non-Conflicting Changes From Left To Right +merged.multiple.to.right.tooltip = Apply on the right-hand side all non-conflicting changes from the current selection +merged.all.to.left.tooltip = Apply all right changes on the left-hand side. The right-hand side will remain unchanged +merged.all.to.right.tooltip = Apply all left changes on the right-hand side. The left-hand side will remain unchanged merged.contained.to.left.tooltip = Apply Contained Non-conflicting Right Changes on the Left-hand Side merged.contained.to.right.tooltip = Apply Contained Non-conflicting Left Changes on the Right-hand Side dropdown.left.to.right.text = Show consequences of merging from left to right @@ -116,3 +120,100 @@ LogicalModelView.listPresentation.title = List LogicalModelView.treePresentation.title = Tree LogicalModelView.errorDialog.title = EMF Compare - Logical Model View LogicalModelView.errorDialog.message = Error while computing logical models. See error log for more details. + +ContextualTooltip.acceptChange = Accept the change. +ContextualTooltip.rejectChange = Reject the change. +ContextualTooltip.readonly.leftUnchanged = The left-hand side will remain unchanged. +ContextualTooltip.readonly.leftChanged = The left-hand side will be modified. +ContextualTooltip.editable.rightChanged = The left-hand side will remain unchanged.\nThe right-hand side will be modified. +ContextualTooltip.editable.rightUnchanged = The left-hand side will be modified.\nThe right-hand side will remain unchanged. + +# Accept contextual tooltips +ContextualTooltip.set.left.accept = Keep ''{0}'' in ''{1}'' of this ''{2}'' on the left-hand side. +ContextualTooltip.set.right.accept = Set the ''{0}'' of this ''{1}'' to ''{2}'' (instead of ''{3}'') on the left-hand side. +ContextualTooltip.set.right.accept.empty = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side. +ContextualTooltip.unset.left.accept = Keep the ''{0}'' of this ''{1}'' unset on the left-hand side. +ContextualTooltip.unset.right.accept = Unset the ''{0}'' of this ''{1}'' (currently ''{2}'') on the left-hand side. +ContextualTooltip.move.container.left.accept = Keep ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.move.position.left.container.accept = Keep ''{0}'' at its current position in ''{1}'' on the left-hand side. +ContextualTooltip.move.position.left.accept = Keep ''{0}'' at its current position on the left-hand side. +ContextualTooltip.move.container.right.accept = Move ''{0}'' in ''{1}'' (currently in ''{2}'') on the left-hand side. +ContextualTooltip.move.position.right.container.accept = Move the position of ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.move.position.right.accept = Move the position of ''{0}'' on the left-hand side. +ContextualTooltip.add.containment.left.accept = Keep ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.left.accept = Keep ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.left.accept = Keep ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.containment.right.accept = Add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.right.accept = Add ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.right.accept = Add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.containment.left.accept = Keep the deletion of ''{0}'' from ''{1}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.left.accept = Keep the deletion of ''{0}'' on the left-hand side. +ContextualTooltip.delete.containment.right.accept = Delete ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.right.accept = Delete ''{0}'' on the left-hand side. + +# Reject contextual tooltips +ContextualTooltip.set.left.reject = Restore the ''{0}'' of this ''{1}'' to ''{2}'' (instead of ''{3}'') on the left-hand side. +ContextualTooltip.set.left.reject.empty = Clear the ''{0}'' of this ''{1}'' (currently ''{2}'') on the left-hand side. +ContextualTooltip.set.right.reject = Keep ''{0}'' in ''{1}'' of this ''{2}'' on the left-hand side. +ContextualTooltip.set.right.reject.empty = Keep the ''{0}'' of this ''{1}'' empty on the left-hand side. +ContextualTooltip.unset.left.reject = Restore the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side. +ContextualTooltip.unset.right.reject = Keep the ''{0}'' of this ''{1}'' set to ''{2}'' on the left-hand side. +ContextualTooltip.move.container.left.reject = Restore ''{0}'' in ''{1}'' (currently in ''{2}'') on the left-hand side. +ContextualTooltip.move.position.left.reject = Restore the original position of ''{0}'' on the left-hand side. +ContextualTooltip.move.container.right.reject = Keep ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.move.position.right.reject = Keep ''{0}'' at its current position on the left-hand side. +ContextualTooltip.move.position.right.container.reject = Keep ''{0}'' at its current position under ''{1}'' on the left-hand side. +ContextualTooltip.add.containment.left.reject = Delete ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.left.reject = Delete ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.left.reject = Delete ''{0}'' from ''{1}'' on the left-hand side. +ContextualTooltip.add.containment.right.reject = Do not add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.right.reject = Do not add ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.right.reject = Do not add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.containment.left.reject = Restore ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.left.reject = Restore ''{0}'' on the left-hand side. +ContextualTooltip.delete.containment.right.reject = Keep ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.right.reject = Keep ''{0}'' on the left-hand side. + +# Copy from left to right contextual tooltips +ContextualTooltip.set.left.leftToRight = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the right-hand side (currently ''{3}''). +ContextualTooltip.set.left.leftToRight.empty = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the right-hand side. +ContextualTooltip.set.right.leftToRight = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the right-hand side (instead of ''{3}''). +ContextualTooltip.set.right.leftToRight.empty = Unset the ''{0}'' of this ''{1}'' (currently ''{2}'') on the right-hand side. +ContextualTooltip.unset.left.leftToRight = Unset the ''{0}'' of this ''{1}'' on the right-hand side (currently ''{2}''). +ContextualTooltip.unset.right.leftToRight = Restore the ''{0}'' of this ''{1}'' to ''{2}'' on the right-hand side. +ContextualTooltip.move.container.left.leftToRight = Move ''{0}'' in ''{1}'' (currently in ''{2}'') on the right-hand side. +ContextualTooltip.move.container.right.leftToRight = Move ''{0}'' in ''{1}'' (currently in ''{2}'') on the right-hand side. +ContextualTooltip.move.position.left.leftToRight = Move ''{0}'' on the right-hand side to match its left-hand side position. +ContextualTooltip.move.position.right.leftToRight = Move ''{0}'' on the right-hand side to match its left-hand side position. +ContextualTooltip.add.containment.left.leftToRight = Add ''{0}'' in ''{1}'' on the right-hand side. +ContextualTooltip.add.nonContainment.left.leftToRight = Add ''{0}'' on the right-hand side. +ContextualTooltip.add.attribute.left.leftToRight = Add ''{0}'' in ''{1}'' on the right-hand side. +ContextualTooltip.add.containment.right.leftToRight = Delete ''{0}'' in ''{1}'' on the right-hand side. +ContextualTooltip.add.nonContainment.right.leftToRight = Remove ''{0}'' on the right-hand side. +ContextualTooltip.add.attribute.right.leftToRight = Delete ''{0}'' in ''{1}'' on the right-hand side. +ContextualTooltip.delete.containment.left.leftToRight = Delete ''{0}'' from ''{1}'' on the right-hand side. +ContextualTooltip.delete.nonContainment.left.leftToRight = Delete ''{0}'' on the right-hand side. +ContextualTooltip.delete.containment.right.leftToRight = Undo the deletion of ''{0}'' from ''{1}'' on the right-hand side. +ContextualTooltip.delete.nonContainment.right.leftToRight = Undo the deletion of ''{0}'' on the right-hand side. + +# Copy from right to left contextual tooltips +ContextualTooltip.set.right.rightToLeft = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side (instead of ''{3}''). +ContextualTooltip.set.right.rightToLeft.empty = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side. +ContextualTooltip.set.left.rightToLeft = Set the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side (instead of ''{3}''). +ContextualTooltip.set.left.rightToLeft.empty = Clear the ''{0}'' of this ''{1}'' on the left-hand side (currently ''{2}''). +ContextualTooltip.unset.right.rightToLeft = Unset the ''{0}'' of this ''{1}'' on the left-hand side (currently ''{2}''). +ContextualTooltip.unset.left.rightToLeft = Restore the ''{0}'' of this ''{1}'' to ''{2}'' on the left-hand side. +ContextualTooltip.move.container.right.rightToLeft = Move ''{0}'' in ''{1}'' (currently in ''{2}'') on the left-hand side. +ContextualTooltip.move.position.right.rightToLeft = Move ''{0}'' on the left-hand side to match its right-hand side position. +ContextualTooltip.move.container.left.rightToLeft = Move ''{0}'' in ''{1}'' (currently in ''{2}'') on the left-hand side. +ContextualTooltip.move.position.left.rightToLeft = Move ''{0}'' on the left-hand side to match its right-hand side position. +ContextualTooltip.add.containment.right.rightToLeft = Add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.right.rightToLeft = Add ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.left.rightToLeft = Delete ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.containment.left.rightToLeft = Delete ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.add.nonContainment.left.rightToLeft = Remove ''{0}'' on the left-hand side. +ContextualTooltip.add.attribute.right.rightToLeft = Add ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.containment.right.rightToLeft = Delete ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.containment.left.rightToLeft = Undo the deletion of ''{0}'' in ''{1}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.right.rightToLeft = Delete ''{0}'' on the left-hand side. +ContextualTooltip.delete.nonContainment.left.rightToLeft = Undo the deletion of ''{0}'' on the left-hand side.
\ No newline at end of file diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java index 539e8a4bd..7020a3877 100644 --- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java @@ -1130,8 +1130,6 @@ public class EMFCompareStructureMergeViewer extends AbstractStructuredViewerWrap ((NotLoadingResourceSet)originResourceSet).setAllowResourceLoad(true); } - initToolbar(); - IStorage leftStorage = PlatformElementUtil.findFile(left); if (leftStorage == null) { leftStorage = StreamAccessorStorage.fromTypedElement(left); @@ -1144,6 +1142,7 @@ public class EMFCompareStructureMergeViewer extends AbstractStructuredViewerWrap EMFCompareRCPUIPlugin.getDefault().setEMFCompareConfiguration(compareConfiguration); } + initToolbar(); compareInputChanged(scope, compareResult); } // Protect compare actions from over-enthusiast users diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AbstractTooltipManager.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AbstractTooltipManager.java new file mode 100644 index 000000000..093c35ac2 --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AbstractTooltipManager.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import static org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages.getString; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.ReferenceChange; +import org.eclipse.emf.compare.provider.ISemanticObjectLabelProvider; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; + +/** + * This class defines usual methods for contextual tooltips. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public abstract class AbstractTooltipManager { + + /** + * The line separator used to compute tooltips. + */ + private static final String LINE_SEPARATOR = "\n"; //$NON-NLS-1$ + + /** + * The adapter factory. + */ + protected AdapterFactory adapterFactory; + + /** + * The label provider. + */ + protected AdapterFactoryLabelProvider labelProvider; + + /** + * Check if the given diff is a reference change. + * + * @param diff + * The given diff + * @return <code>true</code> if the diff is a containment reference change <code>false</code> otherwise + */ + protected boolean isContainmentReferenceChange(Diff diff) { + boolean isContainmentReference = false; + if (diff instanceof ReferenceChange) { + if (((ReferenceChange)diff).getReference().isContainment()) { + isContainmentReference = true; + } + } + return isContainmentReference; + } + + /** + * Create the final tooltip for an accepted change which lead to a modification of the left side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String acceptAndChanged(String value) { + String accept = getString("ContextualTooltip.acceptChange"); //$NON-NLS-1$ + String modify = getString("ContextualTooltip.readonly.leftChanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(accept).append(LINE_SEPARATOR).append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Create the final tooltip for an accepted change which don't lead to a modification of the left side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String acceptAndUnchanged(String value) { + String accept = getString("ContextualTooltip.acceptChange"); //$NON-NLS-1$ + String modify = getString("ContextualTooltip.readonly.leftUnchanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(accept).append(LINE_SEPARATOR).append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Create the final tooltip for a rejected change which lead to a modification of the left side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String rejectAndChanged(String value) { + String accept = getString("ContextualTooltip.rejectChange"); //$NON-NLS-1$ + String modify = getString("ContextualTooltip.readonly.leftChanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(accept).append(LINE_SEPARATOR).append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Create the final tooltip for a rejected change which don't lead to a modification of the left side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String rejectAndUnchanged(String value) { + String accept = getString("ContextualTooltip.rejectChange"); //$NON-NLS-1$ + String modify = getString("ContextualTooltip.readonly.leftUnchanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(accept).append(LINE_SEPARATOR).append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Create the final tooltip for a change with two editable files which don't lead to a modification of the + * right side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String rightUnchanged(String value) { + String modify = getString("ContextualTooltip.editable.rightUnchanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Create the final tooltip for a change with two editable files which lead to a modification of the right + * side. + * + * @param value + * The body of the tooltip + * @return the complete tooltip + */ + protected String rightChanged(String value) { + String modify = getString("ContextualTooltip.editable.rightChanged"); //$NON-NLS-1$ + + StringBuilder builder = new StringBuilder(); + builder.append(value).append(LINE_SEPARATOR).append(modify); + return builder.toString(); + } + + /** + * Returns the label of the given <code>object</code> by adapting it to + * {@link ISemanticObjectLabelProvider} and asking for its + * {@link ISemanticObjectLabelProvider#getSemanticObjectLabel(Object) text}. Returns null if + * <code>object</code> is null. + * + * @param eObject + * The object + * @return the label of the object + */ + protected String getLabel(EObject eObject) { + if (eObject != null) { + Object adapter = adapterFactory.adapt(eObject, ISemanticObjectLabelProvider.class); + if (adapter instanceof ISemanticObjectLabelProvider) { + return ((ISemanticObjectLabelProvider)adapter).getSemanticObjectLabel(eObject); + } + } + return null; + } + + /** + * Returns the label of the given <code>object</code> by using the label provider. + * + * @param eObject + * The object + * @return the label of the object + */ + protected String getLabelFromObject(EObject eObject) { + return this.labelProvider.getText(eObject); + } +} diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AddTooltipManager.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AddTooltipManager.java new file mode 100644 index 000000000..6fc5b8c9f --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/AddTooltipManager.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import static org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages.getString; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.AttributeChange; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.internal.merge.MergeMode; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; + +/** + * This class is used to handle creation tooltips for ADD modifications. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public class AddTooltipManager extends AbstractTooltipManager { + + /** + * The constructor. + * + * @param adapterFactory + * The given adapter factory. + */ + public AddTooltipManager(AdapterFactory adapterFactory) { + this.adapterFactory = adapterFactory; + this.labelProvider = new AdapterFactoryLabelProvider(adapterFactory); + } + + /** + * Entry point for the computation of ADD tooltips. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + public String setAddTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String tooltip; + + boolean isContainmentReference = isContainmentReferenceChange(diff); + + // Three different case are handled : add in a non-containment reference, add in a containment + // reference, add of an attribute + if (diff instanceof AttributeChange) { + tooltip = setAddAttributeTooltip(mode, diff, isFromLeft); + } else if (isContainmentReference) { + tooltip = setAddContainmentTooltip(mode, diff, isFromLeft); + } else { + tooltip = setAddNonContainmentTooltip(mode, diff, isFromLeft); + } + + return tooltip; + } + + /** + * Compute the tooltip for an addition in a non-containment reference. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setAddNonContainmentTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String tooltip; + String body; + + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.nonContainment.left.leftToRight", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.add.nonContainment.right.leftToRight", value); //$NON-NLS-1$ + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.nonContainment.left.rightToLeft", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.add.nonContainment.right.rightToLeft", value); //$NON-NLS-1$ + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.nonContainment.left.accept", value); //$NON-NLS-1$ + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.add.nonContainment.right.accept", value); //$NON-NLS-1$ + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.nonContainment.left.reject", value); //$NON-NLS-1$ + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.add.nonContainment.right.reject", value); //$NON-NLS-1$ + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + + /** + * Compute the tooltip for an addition in a containment reference. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setAddContainmentTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String containerValue = getLabel(diff.getMatch()); + + String tooltip; + String body; + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.containment.left.leftToRight", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.add.containment.right.leftToRight", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.containment.left.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.add.containment.right.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.containment.left.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.add.containment.right.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.containment.left.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.add.containment.right.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + + /** + * Compute the tooltip for an attribute addition. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setAddAttributeTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String containerValue = getLabel(diff.getMatch()); + + String tooltip; + String body; + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.attribute.left.leftToRight", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.add.attribute.right.leftToRight", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.attribute.left.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.add.attribute.right.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.attribute.left.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.add.attribute.right.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.add.attribute.left.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.add.attribute.right.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + +} diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/ChangeTooltipManager.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/ChangeTooltipManager.java new file mode 100644 index 000000000..0abc193dc --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/ChangeTooltipManager.java @@ -0,0 +1,383 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import static org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages.getString; +import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEGet; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.AttributeChange; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.DifferenceSource; +import org.eclipse.emf.compare.Match; +import org.eclipse.emf.compare.ReferenceChange; +import org.eclipse.emf.compare.internal.merge.MergeMode; +import org.eclipse.emf.compare.utils.MatchUtil; +import org.eclipse.emf.compare.utils.ReferenceUtil; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; + +/** + * This class is used to handle creation tooltips for CHANGE (SET and UNSET) modifications. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public class ChangeTooltipManager extends AbstractTooltipManager { + + /** + * The constructor. + * + * @param adapterFactory + * The given adapter factory + */ + public ChangeTooltipManager(AdapterFactory adapterFactory) { + this.adapterFactory = adapterFactory; + this.labelProvider = new AdapterFactoryLabelProvider(adapterFactory); + } + + /** + * Entry point for the computation of CHANGE tooltips. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + public String setChangeTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + boolean isUnset = isUnset(diff); + String tooltip; + + // Two case are handled : set and unset + if (isUnset) { + tooltip = setUnsetTooltip(mode, diff, isFromLeft); + } else { + tooltip = setSetTooltip(mode, diff, isFromLeft); + } + return tooltip; + } + + /** + * Returns the changed value, as it is right now stored in the model, of the attribute that is affected by + * the given {@code diff}. + * + * @param diff + * The diff to get the changed value for. + * @return The changed value. + */ + private String getChangedValueFromModel(AttributeChange diff) { + final EAttribute attribute = diff.getAttribute(); + final EObject changedContainer; + switch (diff.getSource()) { + case LEFT: + changedContainer = diff.getMatch().getLeft(); + break; + case RIGHT: + changedContainer = diff.getMatch().getRight(); + break; + default: + throw new IllegalArgumentException(); + } + return (String)safeEGet(changedContainer, attribute); + } + + /** + * Check if the change in a given diff is a set or an unset. + * + * @param diff + * The given diff + * @return <code>true</code> if the diff is an unset, <code>false</code> otherwise + */ + private boolean isUnset(Diff diff) { + boolean isUnset = false; + if (diff instanceof ReferenceChange) { + if (isUnset((ReferenceChange)diff)) { + isUnset = true; + } + } else if (diff instanceof AttributeChange) { + AttributeChange change = (AttributeChange)diff; + if (isUnset(change, getChangedValueFromModel(change))) { + isUnset = true; + } + } + return isUnset; + } + + /** + * Specifies whether the given {@code diff} unsets the reference value. + * + * @param diff + * The difference to check + * @return <code>true</code> if setting {@code targetValue} is an unset, <code>false</code> otherwise. + */ + private boolean isUnset(ReferenceChange diff) { + boolean isUnset = false; + final Match match = diff.getMatch(); + final EObject container; + if (diff.getSource() == DifferenceSource.LEFT) { + container = match.getLeft(); + } else { + container = match.getRight(); + } + + if (container == null) { + isUnset = true; + } else { + if (!ReferenceUtil.safeEIsSet(container, diff.getReference())) { + isUnset = true; + } + } + + return isUnset; + } + + /** + * Specifies whether the given {@code diff} unsets the attribute value when updating the attribute with + * the given {@code targetValue}. + * + * @param diff + * The difference to check. + * @param targetValue + * The value to be set. + * @return <code>true</code> if setting {@code targetValue} is an unset, <code>false</code> otherwise. + */ + private boolean isUnset(AttributeChange diff, Object targetValue) { + final Object defaultValue = diff.getAttribute().getDefaultValue(); + return targetValue == null || targetValue.equals(defaultValue) + || (defaultValue == null && "".equals(targetValue)); //$NON-NLS-1$ + } + + /** + * Get the label for the structuralFeature of the given eObject. + * + * @param eStructuralFeature + * The eStructuralFeature + * @param eObject + * The eObject + * @return the label of the eStructuralFeature + */ + private String getPreviousValue(EStructuralFeature eStructuralFeature, EObject eObject) { + Object ancestor = eObject.eGet(eStructuralFeature); + String value = ""; //$NON-NLS-1$ + if (ancestor instanceof EObject) { + value = getLabelFromObject((EObject)ancestor); + } else if (ancestor != null) { + value = ancestor.toString(); + } + return value; + } + + /** + * Compute the tooltip for the set of a value. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setSetTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + // compute the name of the structural feature modified + EStructuralFeature eStructuralFeature = MatchUtil.getStructuralFeature(diff); + String structuralFeatureName = eStructuralFeature.getName(); + + // The name of the container of the structural feature + String containerName = diff.getMatch().getLeft().eClass().getName(); + + String rightValue = getPreviousValue(eStructuralFeature, diff.getMatch().getRight()); + String leftValue = getPreviousValue(eStructuralFeature, diff.getMatch().getLeft()); + String tooltip; + String body; + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + if ("".equals(rightValue)) { //$NON-NLS-1$ + body = getString( + "ContextualTooltip.set.left.leftToRight.empty", structuralFeatureName, //$NON-NLS-1$ + containerName, leftValue); + + } else { + body = getString("ContextualTooltip.set.left.leftToRight", structuralFeatureName, //$NON-NLS-1$ + containerName, leftValue, rightValue); + } + } else { + // if previous value cannot be displayed + if ("".equals(leftValue)) { //$NON-NLS-1$ + body = getString("ContextualTooltip.set.right.leftToRight.empty", //$NON-NLS-1$ + structuralFeatureName, containerName, rightValue); + } else { + body = getString("ContextualTooltip.set.right.leftToRight", structuralFeatureName, //$NON-NLS-1$ + containerName, leftValue, rightValue); + } + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + // if previous value cannot be displayed + if ("".equals(rightValue)) { //$NON-NLS-1$ + body = getString("ContextualTooltip.set.left.rightToLeft.empty", //$NON-NLS-1$ + structuralFeatureName, containerName, leftValue); + } else { + body = getString("ContextualTooltip.set.left.rightToLeft", structuralFeatureName, //$NON-NLS-1$ + containerName, rightValue, leftValue); + } + } else { + if ("".equals(leftValue)) { //$NON-NLS-1$ + body = getString( + "ContextualTooltip.set.right.rightToLeft.empty", structuralFeatureName, //$NON-NLS-1$ + containerName, rightValue); + } else { + body = getString("ContextualTooltip.set.right.rightToLeft", structuralFeatureName, //$NON-NLS-1$ + containerName, rightValue, leftValue); + } + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.set.left.accept", leftValue, structuralFeatureName, //$NON-NLS-1$ + containerName); + tooltip = acceptAndUnchanged(body); + } else { + if ("".equals(leftValue)) { //$NON-NLS-1$ + body = getString("ContextualTooltip.set.right.accept.empty", structuralFeatureName, //$NON-NLS-1$ + containerName, rightValue); + } else { + body = getString("ContextualTooltip.set.right.accept", structuralFeatureName, //$NON-NLS-1$ + containerName, rightValue, leftValue); + } + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + // get the value of the structural feature in the origin side if it is a three way comparison, + // get the value of the left side otherwise + String previousValue; + if (diff.getMatch().getComparison().isThreeWay()) { + previousValue = getPreviousValue(eStructuralFeature, diff.getMatch().getOrigin()); + } else { + previousValue = rightValue; + } + + if (isFromLeft) { + // if previous value cannot be displayed + if ("".equals(previousValue)) { //$NON-NLS-1$ + body = getString("ContextualTooltip.set.left.reject.empty", structuralFeatureName, //$NON-NLS-1$ + containerName, leftValue); + } else { + body = getString("ContextualTooltip.set.left.reject", structuralFeatureName, //$NON-NLS-1$ + containerName, previousValue, leftValue); + } + tooltip = rejectAndChanged(body); + } else { + if (diff.getMatch().getComparison().isThreeWay()) { + previousValue = getPreviousValue(eStructuralFeature, diff.getMatch().getOrigin()); + } else { + previousValue = leftValue; + } + // if previous value cannot be displayed + if ("".equals(previousValue)) { //$NON-NLS-1$ + body = getString("ContextualTooltip.set.right.reject.empty", structuralFeatureName, //$NON-NLS-1$ + containerName); + } else { + body = getString( + "ContextualTooltip.set.right.reject", previousValue, structuralFeatureName, //$NON-NLS-1$ + containerName); + } + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + + /** + * Compute the tooltip for the unset of a value. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setUnsetTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + + // compute the name of the structural feature modified + EStructuralFeature structuralFeature = MatchUtil.getStructuralFeature(diff); + String structuralFeatureName = structuralFeature.getName(); + + // The name of the container of the structural feature + String containerName = diff.getMatch().getLeft().eClass().getName(); + + String tooltip; + String body; + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.unset.left.leftToRight", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + } else { + body = getString("ContextualTooltip.unset.right.leftToRight", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.unset.left.rightToLeft", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + } else { + body = getString("ContextualTooltip.unset.right.rightToLeft", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.unset.left.accept", structuralFeatureName, //$NON-NLS-1$ + containerName); + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.unset.right.accept", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.unset.left.reject", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.unset.right.reject", structuralFeatureName, //$NON-NLS-1$ + containerName, value); + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + +} diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/DeleteTooltipManager.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/DeleteTooltipManager.java new file mode 100644 index 000000000..8f83f9593 --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/DeleteTooltipManager.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import static org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages.getString; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.ReferenceChange; +import org.eclipse.emf.compare.internal.merge.MergeMode; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; + +/** + * This class is used to compute tooltips for DELETE modifications. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public class DeleteTooltipManager extends AbstractTooltipManager { + + /** + * The constructor. + * + * @param adapterFactory + * The given adapter factory + */ + public DeleteTooltipManager(AdapterFactory adapterFactory) { + this.adapterFactory = adapterFactory; + this.labelProvider = new AdapterFactoryLabelProvider(adapterFactory); + } + + /** + * This method is the entry point of tooltip creation for a DELETE mode difference. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + public String setDeleteTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String tooltip; + + boolean isContainmentReference = false; + if (diff instanceof ReferenceChange) { + if (((ReferenceChange)diff).getReference().isContainment()) { + isContainmentReference = true; + } + } + + // Two different case are handled : deletion on an element referenced by a non-containment reference, + // deletion of an element referenced by a containment reference + if (isContainmentReference) { + tooltip = setDeleteContainmentTooltip(mode, diff, isFromLeft); + } else { + tooltip = setDeleteNonContainmentTooltip(mode, diff, isFromLeft); + } + + return tooltip; + } + + /** + * Compute the tooltip for an deletion in a non-containment reference. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setDeleteNonContainmentTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String tooltip; + String body; + + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.nonContainment.left.leftToRight", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.delete.nonContainment.right.leftToRight", value); //$NON-NLS-1$ + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.nonContainment.left.rightToLeft", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.delete.nonContainment.right.rightToLeft", value); //$NON-NLS-1$ + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.nonContainment.left.accept", value); //$NON-NLS-1$ + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.delete.nonContainment.right.accept", value); //$NON-NLS-1$ + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.nonContainment.left.reject", value); //$NON-NLS-1$ + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.delete.nonContainment.right.reject", value); //$NON-NLS-1$ + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + + /** + * Compute the tooltip for an deletion in a containment reference. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setDeleteContainmentTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String containerValue = getLabel(diff.getMatch()); + String tooltip; + String body; + + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.containment.left.leftToRight", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.delete.containment.right.leftToRight", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.containment.left.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } else { + body = getString("ContextualTooltip.delete.containment.right.rightToLeft", value, //$NON-NLS-1$ + containerValue); + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.containment.left.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.delete.containment.right.accept", value, //$NON-NLS-1$ + containerValue); + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.delete.containment.left.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.delete.containment.right.reject", value, //$NON-NLS-1$ + containerValue); + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + +} diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MergeAction.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MergeAction.java index 0734373da..457e2c807 100644 --- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MergeAction.java +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MergeAction.java @@ -26,8 +26,10 @@ import java.util.Set; import org.eclipse.compare.INavigatable; import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.DifferenceSource; import org.eclipse.emf.compare.command.ICompareCopyCommand; import org.eclipse.emf.compare.domain.ICompareEditingDomain; import org.eclipse.emf.compare.domain.IMergeRunnable; @@ -39,6 +41,8 @@ import org.eclipse.emf.compare.internal.utils.ComparisonUtil; import org.eclipse.emf.compare.merge.IMerger; import org.eclipse.emf.compare.merge.IMerger.Registry; import org.eclipse.emf.compare.merge.IMerger2; +import org.eclipse.emf.compare.rcp.ui.EMFCompareRCPUIPlugin; +import org.eclipse.emf.compare.rcp.ui.internal.configuration.IEMFCompareConfiguration; import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroup; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.tree.TreeNode; @@ -75,6 +79,16 @@ public class MergeAction extends BaseSelectionListenerAction { private final INavigatable navigatable; /** + * The merge mode used for the comparison. + */ + private MergeMode selectedMode; + + /** + * The adapter factory for the comparison. + */ + private AdapterFactory adapterFactory; + + /** * Constructor. * * @param configuration @@ -83,8 +97,13 @@ public class MergeAction extends BaseSelectionListenerAction { public MergeAction(ICompareEditingDomain editingDomain, IMerger.Registry mergerRegistry, MergeMode mode, boolean isLeftEditable, boolean isRightEditable, INavigatable navigatable) { super(""); //$NON-NLS-1$ - this.navigatable = navigatable; + IEMFCompareConfiguration emfCompareConfiguration = EMFCompareRCPUIPlugin.getDefault() + .getEMFCompareConfiguration(); + if (emfCompareConfiguration != null) { + adapterFactory = emfCompareConfiguration.getAdapterFactory(); + } + this.navigatable = navigatable; Preconditions.checkNotNull(mode); // at least should be editable Preconditions.checkState(isLeftEditable || isRightEditable); @@ -103,6 +122,7 @@ public class MergeAction extends BaseSelectionListenerAction { this.leftToRight = mode.isLeftToRight(isLeftEditable, isRightEditable); this.mergeRunnable = createMergeRunnable(mode, isLeftEditable, isRightEditable); this.selectedDifferences = newArrayList(); + this.selectedMode = mode; initToolTipAndImage(mode); } @@ -151,6 +171,74 @@ public class MergeAction extends BaseSelectionListenerAction { } /** + * This method is used to created contextual tooltips. + */ + protected void contextualizeTooltip() { + + if (this.selectedDifferences.size() > 1) { + // multiple selection + setMultipleTooltip(this.selectedMode); + } else if (this.selectedDifferences.isEmpty()) { + // no selection + initToolTipAndImage(this.selectedMode); + } else { + String tooltip; + Diff diff = this.selectedDifferences.get(0); + boolean isFromLeft = diff.getSource().equals(DifferenceSource.LEFT); + switch (diff.getKind()) { + case ADD: + AddTooltipManager addTooltipManager = (AddTooltipManager)TooltipFactory + .getTooltipManager(this.adapterFactory, diff); + tooltip = addTooltipManager.setAddTooltip(this.selectedMode, diff, isFromLeft); + break; + case CHANGE: + ChangeTooltipManager changeTooltipManager = (ChangeTooltipManager)TooltipFactory + .getTooltipManager(this.adapterFactory, diff); + tooltip = changeTooltipManager.setChangeTooltip(this.selectedMode, diff, isFromLeft); + break; + case DELETE: + DeleteTooltipManager deleteTooltipManager = (DeleteTooltipManager)TooltipFactory + .getTooltipManager(this.adapterFactory, diff); + tooltip = deleteTooltipManager.setDeleteTooltip(this.selectedMode, diff, isFromLeft); + break; + case MOVE: + MoveTooltipManager moveTooltipManager = (MoveTooltipManager)TooltipFactory + .getTooltipManager(this.adapterFactory, diff); + tooltip = moveTooltipManager.setMoveTooltip(this.selectedMode, diff, isFromLeft); + break; + default: + throw new IllegalStateException(); + } + setToolTipText(tooltip); + } + } + + /** + * Set the tooltips for multiple selection. + * + * @param mode + * The comparison mode + */ + private void setMultipleTooltip(MergeMode mode) { + switch (mode) { + case LEFT_TO_RIGHT: + setToolTipText(EMFCompareIDEUIMessages.getString("merged.multiple.to.right.tooltip")); //$NON-NLS-1$ + break; + case RIGHT_TO_LEFT: + setToolTipText(EMFCompareIDEUIMessages.getString("merged.multiple.to.left.tooltip")); //$NON-NLS-1$ + break; + case ACCEPT: + setToolTipText(EMFCompareIDEUIMessages.getString("accept.multiple.changes.tooltip")); //$NON-NLS-1$ + break; + case REJECT: + setToolTipText(EMFCompareIDEUIMessages.getString("reject.multiple.changes.tooltip")); //$NON-NLS-1$ + break; + default: + throw new IllegalStateException(); + } + } + + /** * {@inheritDoc} * * @see org.eclipse.jface.action.Action#run() @@ -200,6 +288,9 @@ public class MergeAction extends BaseSelectionListenerAction { @Override protected boolean updateSelection(IStructuredSelection selection) { addAll(selectedDifferences, getSelectedDifferences(selection)); + if (this.adapterFactory != null) { + contextualizeTooltip(); + } return selection.toList().size() == selectedDifferences.size(); } diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MoveTooltipManager.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MoveTooltipManager.java new file mode 100644 index 000000000..8e8ae37e6 --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/MoveTooltipManager.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import static org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages.getString; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.Match; +import org.eclipse.emf.compare.ReferenceChange; +import org.eclipse.emf.compare.internal.merge.MergeMode; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; + +/** + * This class is used to handle creation tooltips for MOVE modifications. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public class MoveTooltipManager extends AbstractTooltipManager { + + /** + * The constructor. + * + * @param adapterFactory + * The given adapter factory. + */ + public MoveTooltipManager(AdapterFactory adapterFactory) { + this.adapterFactory = adapterFactory; + this.labelProvider = new AdapterFactoryLabelProvider(adapterFactory); + } + + /** + * Entry point for the computation of MOVE tooltips. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + public String setMoveTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + EObject right = null; + EObject left = null; + EObject ancestor = null; + String tooltip; + + boolean isContainmentReference = isContainmentReferenceChange(diff); + if (isContainmentReference) { + Match valueMatch = diff.getMatch().getComparison().getMatch(((ReferenceChange)diff).getValue()); + left = valueMatch.getLeft(); + right = valueMatch.getRight(); + ancestor = valueMatch.getOrigin(); + } + + // Two case are handled : move of an element in another container, position move of an element inside + // the same container + if (isContainmentReference && isContainerMove(isFromLeft, ancestor, right, left)) { + tooltip = setMoveContainerTooltip(mode, diff, isFromLeft, left, right, ancestor); + } else { + tooltip = setMovePositionTooltip(mode, diff, isFromLeft); + } + return tooltip; + } + + /** + * This method verify if the container (left and right) of an element are the same in order to detect move + * from a container to another. + * + * @param isFromLeft + * True if the change comes from the left side, false otherwise + * @param origin + * The origin container + * @param right + * The right container + * @param left + * The left container + * @return true if the two containers are different + */ + private boolean isContainerMove(boolean isFromLeft, EObject origin, EObject right, EObject left) { + boolean isContainerMove = false; + if (isFromLeft) { + if (left != null && origin != null) { + // if the label of the container of an element is different of the label of it ancestor + // or if the containing feature between an element and its container are different + // We consider that it is a container move + if (!getLabelFromObject(left.eContainer()).equals(getLabelFromObject(origin.eContainer())) + || left.eContainingFeature() != origin.eContainingFeature()) { + isContainerMove = true; + } + } + } else { + if (right != null && origin != null) { + if (!getLabelFromObject(right.eContainer()).equals(getLabelFromObject(origin.eContainer())) + || right.eContainingFeature() != origin.eContainingFeature()) { + isContainerMove = true; + } + } + } + return isContainerMove; + } + + /** + * Compute the tooltip for the move (position) of an element inside the same container. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @return the tooltip + */ + private String setMovePositionTooltip(MergeMode mode, Diff diff, boolean isFromLeft) { + String value = getLabel(diff); + String containerValue = getLabel(diff.getMatch()); + String tooltip; + String body; + + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.position.left.leftToRight", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.move.position.right.leftToRight", value); //$NON-NLS-1$ + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.position.left.rightToLeft", value); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.move.position.right.rightToLeft", value); //$NON-NLS-1$ + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + // display container label only if the element is inside a container + if (diff instanceof ReferenceChange + && ((ReferenceChange)diff).getReference().isContainment()) { + body = getString( + "ContextualTooltip.move.position.left.container.accept", value, containerValue); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.move.position.left.accept", value); //$NON-NLS-1$ + } + tooltip = acceptAndUnchanged(body); + } else { + if (diff instanceof ReferenceChange + && ((ReferenceChange)diff).getReference().isContainment()) { + body = getString( + "ContextualTooltip.move.position.right.container.accept", value, containerValue); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.move.position.right.accept", value); //$NON-NLS-1$ + } + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.position.left.reject", value); //$NON-NLS-1$ + tooltip = rejectAndChanged(body); + } else { + // display container label only if the element is inside a container + if (diff instanceof ReferenceChange + && ((ReferenceChange)diff).getReference().isContainment()) { + body = getString( + "ContextualTooltip.move.position.right.container.reject", value, containerValue); //$NON-NLS-1$ + } else { + body = getString("ContextualTooltip.move.position.right.reject", value); //$NON-NLS-1$ + } + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + + /** + * Compute the tooltip for the move of an element from a container to another. + * + * @param mode + * The comparison mode + * @param diff + * The diff + * @param isFromLeft + * True if the modification come from the left side + * @param left + * The modified element in the left model + * @param right + * The modified element in the right model + * @param ancestor + * The modified element in the left model + * @return the tooltip + */ + private String setMoveContainerTooltip(MergeMode mode, Diff diff, boolean isFromLeft, EObject left, + EObject right, EObject ancestor) { + String value = getLabel(diff); + String leftContainerValue = getLabelFromObject(left.eContainer()); + String rightContainerValue = getLabelFromObject(right.eContainer()); + String ancestorContainerValue; + if (diff.getMatch().getComparison().isThreeWay() && ancestor != null) { + ancestorContainerValue = getLabelFromObject(ancestor.eContainer()); + } else { + ancestorContainerValue = rightContainerValue; + } + String tooltip; + String body; + + switch (mode) { + case LEFT_TO_RIGHT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.container.left.leftToRight", value, //$NON-NLS-1$ + leftContainerValue, rightContainerValue); + } else { + body = getString("ContextualTooltip.move.container.right.leftToRight", value, //$NON-NLS-1$ + leftContainerValue, rightContainerValue); + } + tooltip = rightChanged(body); + break; + case RIGHT_TO_LEFT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.container.left.rightToLeft", value, //$NON-NLS-1$ + rightContainerValue, leftContainerValue); + } else { + body = getString("ContextualTooltip.move.container.right.rightToLeft", value, //$NON-NLS-1$ + rightContainerValue, leftContainerValue); + } + tooltip = rightUnchanged(body); + break; + case ACCEPT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.container.left.accept", value, //$NON-NLS-1$ + leftContainerValue); + tooltip = acceptAndUnchanged(body); + } else { + body = getString("ContextualTooltip.move.container.right.accept", value, //$NON-NLS-1$ + rightContainerValue, leftContainerValue); + tooltip = acceptAndChanged(body); + } + break; + case REJECT: + if (isFromLeft) { + body = getString("ContextualTooltip.move.container.left.reject", value, //$NON-NLS-1$ + ancestorContainerValue, leftContainerValue); + tooltip = rejectAndChanged(body); + } else { + body = getString("ContextualTooltip.move.container.right.reject", value, //$NON-NLS-1$ + leftContainerValue); + tooltip = rejectAndUnchanged(body); + } + break; + default: + throw new IllegalStateException(); + } + return tooltip; + } + +} diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/TooltipFactory.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/TooltipFactory.java new file mode 100644 index 000000000..6d0f719a6 --- /dev/null +++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/actions/TooltipFactory.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2015 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 + *******************************************************************************/ +package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.compare.Diff; + +/** + * Factory for the tooltip managers. + * + * @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a> + */ +public final class TooltipFactory { + + /** + * The AddTooltipManager instance. + */ + private static AddTooltipManager addTooltipManager; + + /** + * The ChangeTooltipManager instance. + */ + private static ChangeTooltipManager changeTooltipManager; + + /** + * The DeleteTooltipManager instance. + */ + private static DeleteTooltipManager deleteTooltipManager; + + /** + * The MoveTooltipManager instance. + */ + private static MoveTooltipManager moveTooltipManager; + + /** + * The constructor. + */ + private TooltipFactory() { + // Prevent instanciation. + } + + /** + * Create a new instance of the right type or return the existing one for the given diff. + * + * @param adapterFactory + * The given adapter factory + * @param diff + * The diff which which the tooltip will be computed + * @return an instance of the good AbstractTooltipManager + */ + public static AbstractTooltipManager getTooltipManager(AdapterFactory adapterFactory, Diff diff) { + AbstractTooltipManager manager = null; + + switch (diff.getKind()) { + case ADD: + if (addTooltipManager == null) { + addTooltipManager = new AddTooltipManager(adapterFactory); + } + manager = addTooltipManager; + break; + case CHANGE: + if (changeTooltipManager == null) { + changeTooltipManager = new ChangeTooltipManager(adapterFactory); + } + manager = changeTooltipManager; + break; + case DELETE: + if (deleteTooltipManager == null) { + deleteTooltipManager = new DeleteTooltipManager(adapterFactory); + } + manager = deleteTooltipManager; + break; + case MOVE: + if (moveTooltipManager == null) { + moveTooltipManager = new MoveTooltipManager(adapterFactory); + } + manager = moveTooltipManager; + break; + default: + // Do nothing + } + + return manager; + } + +} |