/** * <copyright> * * Copyright (c) 2010-2016 Thales Global Services S.A.S. * 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: * Thales Global Services S.A.S. - initial API and implementation * Stephane Bouchet (Intel Corporation) - Bug #489142 : use the delegate label provider to display text * * </copyright> */ package org.eclipse.emf.diffmerge.ui.viewers; import java.util.ArrayList; import java.util.List; import org.eclipse.emf.diffmerge.api.IMatch; import org.eclipse.emf.diffmerge.api.Role; import org.eclipse.emf.diffmerge.diffdata.EMatch; import org.eclipse.emf.diffmerge.ui.EMFDiffMergeUIPlugin; import org.eclipse.emf.diffmerge.ui.EMFDiffMergeUIPlugin.DifferenceColorKind; import org.eclipse.emf.diffmerge.ui.EMFDiffMergeUIPlugin.ImageID; import org.eclipse.emf.diffmerge.ui.diffuidata.MatchAndFeature; import org.eclipse.emf.diffmerge.ui.diffuidata.impl.MatchAndFeatureImpl; import org.eclipse.emf.diffmerge.ui.util.DelegatingLabelProvider; import org.eclipse.emf.diffmerge.ui.util.DiffMergeLabelProvider; import org.eclipse.emf.diffmerge.ui.util.DifferenceKind; import org.eclipse.emf.diffmerge.ui.util.UIUtil; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; /** * A viewer which provides a representation of the features of a match. * Input: FeaturesViewer.FeaturesInput ; Elements: EStructuralFeature. * @author Olivier Constant */ public class FeaturesViewer extends TableViewer implements IDifferenceRelatedViewer { /** * A simple structure for defining inputs for this viewer. */ public static class FeaturesInput { /** The non-null comparison context */ private final EMFDiffNode _context; /** The non-null specific part */ private final IMatch _match; /** * Constructor * @param context_p a non-null object * @param match_p a non-null object */ public FeaturesInput(EMFDiffNode context_p, IMatch match_p) { _context = context_p; _match = match_p; } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object object_p) { boolean result = false; if (object_p instanceof FeaturesInput) { FeaturesInput peer = (FeaturesInput)object_p; result = _context == peer.getContext() && _match.equals(peer.getMatch()); } return result; } /** * Return the comparison context * @return a non-null object */ public EMFDiffNode getContext() { return _context; } /** * Return the match * @return a non-null object */ public IMatch getMatch() { return _match; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return _context.hashCode() + _match.hashCode(); } } /** Whether all features must be shown, including those with no difference */ private boolean _showAllFeatures; /** Whether a technical, more precise but less user-friendly representation must be used */ private boolean _useTechnicalRepresentation; /** * Constructor * @param parent_p a non-null composite */ public FeaturesViewer(Composite parent_p) { this(parent_p, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); } /** * Constructor * @param parent_p a non-null composite * @param style_p a style for the tree */ public FeaturesViewer(Composite parent_p, int style_p) { super(parent_p, style_p); setContentProvider(new ContentProvider()); setLabelProvider(new LabelProvider()); _showAllFeatures = false; _useTechnicalRepresentation = false; getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); setSorter(new ViewerSorter()); } /** * Return the first feature to show for the given input, if any * @param input_p a potentially null input object * @return the first feature to show, or null if none */ public EStructuralFeature getFirstIn(FeaturesInput input_p) { EStructuralFeature result = null; if (input_p != null) { Object[] elements = getSortedChildren(input_p); if (elements != null && elements.length > 0) { Object firstElement = elements[0]; if (firstElement instanceof EStructuralFeature) result = (EStructuralFeature)firstElement; } } return result; } /** * @see org.eclipse.jface.viewers.ContentViewer#getInput() */ @Override public FeaturesInput getInput() { return (FeaturesInput)super.getInput(); } /** * Return the resource manager for this viewer * @return a resource manager which is non-null iff input is not null */ protected ComparisonResourceManager getResourceManager() { return getInput() == null? null: getInput().getContext().getResourceManager(); } /** * @see org.eclipse.emf.diffmerge.ui.viewers.IDifferenceRelatedViewer#isDifferenceAgnostic() */ public boolean isDifferenceAgnostic() { return _showAllFeatures; } /** * Return whether the given object represents the virtual ownership feature * @param object_p a potentially null object */ protected boolean isOwnershipFeature(Object object_p) { return EMFDiffMergeUIPlugin.getDefault().getOwnershipFeature().equals(object_p); } /** * Return whether a technical, more precise but less user-friendly representation is being used */ public boolean isTechnical() { return _useTechnicalRepresentation; } /** * @see org.eclipse.emf.diffmerge.ui.viewers.IDifferenceRelatedViewer#setDifferenceAgnostic(boolean) */ public void setDifferenceAgnostic(boolean agnostic_p) { if (agnostic_p != isDifferenceAgnostic()) { _showAllFeatures = agnostic_p; refresh(false); } } /** * Set whether a technical, more precise but less user-friendly representation must be used */ public void setTechnical(boolean technical_p) { if (technical_p != isTechnical()) { _useTechnicalRepresentation = technical_p; refresh(true); } } /** * The content provider for this viewer */ protected class ContentProvider implements IStructuredContentProvider { /** * Return a list of all the relevant features for the given match * @param match_p a non-null match * @return a non-null, potentially empty, modifiable list */ private List<EStructuralFeature> getAllFeatures(IMatch match_p) { Role drivingRole = getInput().getContext().getDrivingRole(); EObject element = match_p.get(drivingRole); if (element == null) element = match_p.get(drivingRole.opposite()); assert element != null; // An IMatch may not have null elements for both roles EClass eClass = element.eClass(); List<EStructuralFeature> result = new ArrayList<EStructuralFeature>(); result.addAll(eClass.getEAllAttributes()); for (EReference ref : eClass.getEAllReferences()) { if (qualifies(ref) || match_p.getOrderDifference(ref, drivingRole) != null) result.add(ref); } return result; } /** * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object inputElement_p) { Role drivingRole = getInput().getContext().getDrivingRole(); IMatch match = ((FeaturesInput)inputElement_p).getMatch(); List<EStructuralFeature> result; if (isDifferenceAgnostic()) result = getAllFeatures(match); else { result = new ArrayList<EStructuralFeature>(match.getAttributesWithDifferences()); for (EReference ref : match.getReferencesWithDifferences()) { if (!ref.isContainment() || match.getOrderDifference(ref, drivingRole) != null) result.add(ref); } } if (getInput().getContext().getCategoryManager().representAsMove(match)) result.add(EMFDiffMergeUIPlugin.getDefault().getOwnershipFeature()); return result.toArray(); } /** * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ public void dispose() { // Nothing needed } /** * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ public void inputChanged(Viewer viewer_p, Object oldInput_p, Object newInput_p) { // Nothing needed } /** * Return whether the given reference may be shown * @param reference_p a non-null reference */ private boolean qualifies(EReference reference_p) { return isOwnershipFeature(reference_p) || !reference_p.isContainment() && !reference_p.isContainer() && reference_p.isChangeable() && !reference_p.isDerived(); } } /** * The label provider for this viewer */ protected class LabelProvider extends DelegatingLabelProvider { /** * Constructor */ public LabelProvider() { super(DiffMergeLabelProvider.getInstance()); } /** * Return the difference kind that corresponds to the given feature for the current input * @param feature_p a non-null feature * @return a non-null kind */ protected DifferenceKind getDifferenceKind(EStructuralFeature feature_p) { DifferenceKind result = DifferenceKind.NONE; if (getInput() != null) { EMatch match = (EMatch)getInput().getMatch(); MatchAndFeature maf = new MatchAndFeatureImpl(match, feature_p); result = getInput().getContext().getCategoryManager().getDifferenceKind(maf); } return result; } /** * @see org.eclipse.emf.diffmerge.ui.util.DelegatingLabelProvider#getFont(java.lang.Object) */ @Override public Font getFont(Object element_p) { Font result = getControl().getFont(); EStructuralFeature feature = (EStructuralFeature)element_p; DifferenceKind kind = getDifferenceKind(feature); if (!kind.isNeutral()) result = UIUtil.getBold(result); return result; } /** * @see org.eclipse.emf.diffmerge.ui.util.DelegatingLabelProvider#getForeground(java.lang.Object) */ @Override public Color getForeground(Object element_p) { EStructuralFeature feature = (EStructuralFeature)element_p; DifferenceKind kind = getDifferenceKind(feature); DifferenceColorKind colorKind = EMFDiffMergeUIPlugin.getDefault().getDifferenceColorKind(kind); if (colorKind == DifferenceColorKind.NONE) colorKind = DifferenceColorKind.DEFAULT; Color result = getInput().getContext().getDifferenceColor(colorKind); return result; } /** * @see org.eclipse.emf.diffmerge.ui.util.DelegatingLabelProvider#getImage(java.lang.Object) */ @Override public Image getImage(Object element_p) { Image result = null; if (isOwnershipFeature(element_p)) { result = EMFDiffMergeUIPlugin.getDefault().getImage(ImageID.TREE); } else { result = getDelegate().getImage(element_p); } if (getInput().getContext().usesCustomIcons() && element_p instanceof EStructuralFeature) { EStructuralFeature feature = (EStructuralFeature)element_p; DifferenceKind kind = getDifferenceKind(feature); result = getResourceManager().adaptImage(result, kind); } return result; } /** * @see org.eclipse.emf.diffmerge.ui.util.DelegatingLabelProvider#getText(java.lang.Object) */ @Override public String getText(Object element_p) { EStructuralFeature feature = (EStructuralFeature)element_p; String result; if (isTechnical()) { result = getDelegate().getText(feature); } else { result = UIUtil.getFormattedFeatureText(feature); } if (getInput().getContext().usesCustomLabels()) { DifferenceKind kind = getDifferenceKind(feature); String prefix = EMFDiffMergeUIPlugin.getDefault().getDifferencePrefix(kind); result = prefix + result; } return result; } } }