Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 160252 Details for
Bug 303976
Provide option to choose between resource and resourceSet based comparison, introduce match scope, fixed wrong positives related to not existing scoping
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
Combined revised patch, subsuming the patches applied to blocked bugs before.
EMF_COMPARE_COMPLETE_PATCH_25022010.txt (text/plain), 132.63 KB, created by
Alexander Nyßen
on 2010-02-25 17:06:42 EST
(
hide
)
Description:
Combined revised patch, subsuming the patches applied to blocked bugs before.
Filename:
MIME Type:
Creator:
Alexander Nyßen
Created:
2010-02-25 17:06:42 EST
Size:
132.63 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.emf.compare.match >Index: src/org/eclipse/emf/compare/match/service/MatchService.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/service/MatchService.java,v >retrieving revision 1.43 >diff -u -r1.43 MatchService.java >--- src/org/eclipse/emf/compare/match/service/MatchService.java 24 Nov 2009 09:35:39 -0000 1.43 >+++ src/org/eclipse/emf/compare/match/service/MatchService.java 25 Feb 2010 22:04:51 -0000 >@@ -11,15 +11,16 @@ > package org.eclipse.emf.compare.match.service; > > import java.util.ArrayList; >-import java.util.HashSet; > import java.util.Iterator; > import java.util.List; > import java.util.Map; >-import java.util.Set; > > import org.eclipse.emf.common.EMFPlugin; > import org.eclipse.emf.compare.EMFComparePlugin; > import org.eclipse.emf.compare.match.engine.IMatchEngine; >+import org.eclipse.emf.compare.match.engine.IMatchScope; >+import org.eclipse.emf.compare.match.engine.IMatchScopeProvider; >+import org.eclipse.emf.compare.match.engine.MatchScopeProviderUtil; > import org.eclipse.emf.compare.match.filter.IResourceFilter; > import org.eclipse.emf.compare.match.filter.ResourceFilterRegistry; > import org.eclipse.emf.compare.match.internal.service.DefaultMatchEngineSelector; >@@ -43,8 +44,6 @@ > * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> > */ > public final class MatchService { >- /** Keeps track of those resources that are loaded as fragments of others. */ >- private static final Set<Resource> FRAGMENT_RESOURCES = new HashSet<Resource>(); > > /** Currently set match engine selector. */ > private static IMatchEngineSelector matchEngineSelector = new DefaultMatchEngineSelector(); >@@ -226,21 +225,27 @@ > * @see org.eclipse.emf.compare.match.MatchOptions > * @since 1.0 > */ >- @SuppressWarnings("unchecked") > public static MatchResourceSet doResourceSetMatch(ResourceSet leftResourceSet, > ResourceSet rightResourceSet, Map<String, Object> options) throws InterruptedException { >+ > // Resolve all proxies so that all resources get loaded > resolveAll(leftResourceSet); > resolveAll(rightResourceSet); > >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(options, >+ leftResourceSet, rightResourceSet); >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ >+ applyExternalFilter(scopeProvider); >+ > final List<Resource> remainingLeftResources = new ArrayList<Resource>(leftResourceSet.getResources()); > final List<Resource> remainingRightResources = new ArrayList<Resource>(rightResourceSet > .getResources()); > >- // Removes fragments from the resources to match >- removeFragments(remainingLeftResources, remainingRightResources); >- // filters out resources if any client extends the filtering extension point >- filterResources(remainingLeftResources, remainingRightResources); >+ applyScopeFilter(leftScope, remainingLeftResources); >+ applyScopeFilter(rightScope, remainingRightResources); > > final MatchResourceSet match = MatchFactory.eINSTANCE.createMatchResourceSet(); > for (final Resource res : new ArrayList<Resource>(remainingLeftResources)) { >@@ -309,25 +314,28 @@ > * @see org.eclipse.emf.compare.match.MatchOptions > * @since 1.0 > */ >- @SuppressWarnings("unchecked") > public static MatchResourceSet doResourceSetMatch(ResourceSet leftResourceSet, > ResourceSet rightResourceSet, ResourceSet ancestorResourceSet, Map<String, Object> options) > throws InterruptedException { >- // Resolve all proxies so that all resources get loaded > resolveAll(leftResourceSet); > resolveAll(rightResourceSet); > resolveAll(ancestorResourceSet); > >+ // apply filter to scope provider, then filter resources with provided scopes >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(options, >+ leftResourceSet, rightResourceSet, ancestorResourceSet); >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ final IMatchScope ancestorScope = scopeProvider.getAncestorScope(); >+ applyExternalFilter(scopeProvider); > final List<Resource> remainingLeftResources = new ArrayList<Resource>(leftResourceSet.getResources()); > final List<Resource> remainingRightResources = new ArrayList<Resource>(rightResourceSet > .getResources()); > final List<Resource> remainingAncestorResources = new ArrayList<Resource>(ancestorResourceSet > .getResources()); >- >- // Removes fragments from the resources to match >- removeFragments(remainingLeftResources, remainingRightResources, remainingAncestorResources); >- // filters out resources if any client extends the filtering extension point >- filterResources(remainingLeftResources, remainingRightResources, remainingAncestorResources); >+ applyScopeFilter(leftScope, remainingLeftResources); >+ applyScopeFilter(rightScope, remainingRightResources); >+ applyScopeFilter(ancestorScope, remainingAncestorResources); > > final MatchResourceSet match = MatchFactory.eINSTANCE.createMatchResourceSet(); > for (final Resource res : new ArrayList<Resource>(remainingLeftResources)) { >@@ -408,7 +416,6 @@ > } > } > } >- > return match; > } > >@@ -488,17 +495,30 @@ > } > > /** >- * Remove all fragment resources from the given resources lists. >+ * Apply external filters to the {@link IMatchScopeProvider}. > * >- * @param resources >- * Lists that are to be cleared off fragments. >+ * @param scopeProvider >+ * The {@link IMatchScopeProvider} the external filters are to be applied to > */ >- private static void filterResources(List<Resource>... resources) { >+ private static void applyExternalFilter(IMatchScopeProvider scopeProvider) { > for (final IResourceFilter filter : ResourceFilterRegistry.INSTANCE.getRegisteredResourceFilters()) { >- if (resources.length == 2) { >- filter.filter(resources[0], resources[1]); >- } else { >- filter.filter(resources[0], resources[1], resources[2]); >+ scopeProvider.applyResourceFilter(filter); >+ } >+ } >+ >+ /** >+ * Removes all resources from the given list, which are not covered by the provided scope. >+ * >+ * @param scope >+ * the {@link IMatchScope} used to determine with resources to retain in the list >+ * @param resources >+ * the list of {@link Resource}s that has to be filtered >+ */ >+ private static void applyScopeFilter(IMatchScope scope, List<Resource> resources) { >+ final Iterator<Resource> iterator = resources.iterator(); >+ while (iterator.hasNext()) { >+ if (!scope.isInScope(iterator.next())) { >+ iterator.remove(); > } > } > } >@@ -546,26 +566,8 @@ > } > > /** >- * Remove all fragment resources from the given resources lists. >- * >- * @param resources >- * Lists that are to be cleared off fragments. >- */ >- private static void removeFragments(List<Resource>... resources) { >- for (final Resource resource : FRAGMENT_RESOURCES) { >- for (final List<Resource> res : resources) { >- res.remove(resource); >- } >- } >- FRAGMENT_RESOURCES.clear(); >- } >- >- /** > * This will allow us to resolve all references from resources contained within <code>resourceSet</code>, >- * loading referenced resources along the way as would >- * {@link org.eclipse.emf.ecore.util.EcoreUtil#resolveAll(ResourceSet)}. The difference lies in the fact >- * we will populate {@link #FRAGMENT_RESOURCES} so as to keep track of the resources loaded as fragments >- * of others. >+ * loading referenced resources along the way. > * > * @param resourceSet > * The resourceSet we wish all references of resolved. >@@ -573,13 +575,10 @@ > private static void resolveAll(ResourceSet resourceSet) { > final List<Resource> resources = resourceSet.getResources(); > for (int i = 0; i < resources.size(); ++i) { >- final Iterator<EObject> resourceContent = resources.get(i).getAllContents(); >+ final Resource currentResource = resources.get(i); >+ final Iterator<EObject> resourceContent = currentResource.getAllContents(); > while (resourceContent.hasNext()) { > final EObject eObject = resourceContent.next(); >- final Resource childResource = eObject.eResource(); >- if (childResource != null && childResource != resources.get(i)) { >- FRAGMENT_RESOURCES.add(childResource); >- } > final Iterator<EObject> objectChildren = eObject.eCrossReferences().iterator(); > while (objectChildren.hasNext()) { > // Resolves cross references by simply visiting them. >Index: src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java,v >retrieving revision 1.41 >diff -u -r1.41 GenericMatchEngine.java >--- src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java 19 Nov 2009 14:07:27 -0000 1.41 >+++ src/org/eclipse/emf/compare/match/engine/GenericMatchEngine.java 25 Feb 2010 22:04:50 -0000 >@@ -139,6 +139,12 @@ > private final List<EObject> stillToFindFromModel2 = new ArrayList<EObject>(); > > /** >+ * This list is used while matching elements to keep track of matched reference targets, being outside the >+ * provided match scope. >+ */ >+ private List<Match2Elements> externalRefMappings = new ArrayList<Match2Elements>(); >+ >+ /** > * The options map must be initialized to avoid potential NPEs. This initializer will take care of this > * issue. > */ >@@ -158,96 +164,162 @@ > loadOptionMap(optionMap); > } > >- final MatchModel root = MatchFactory.eINSTANCE.createMatchModel(); >- setModelRoots(root, leftObject, rightObject, ancestor); >- >- final Monitor monitor = createProgressMonitor(); >- final MatchModel leftObjectAncestorMatch = contentMatch(leftObject, ancestor, optionMap); >- final MatchModel rightObjectAncestorMatch = contentMatch(rightObject, ancestor, optionMap); >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, >+ leftObject, rightObject, ancestor); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ final IMatchScope ancestorScope = scopeProvider.getAncestorScope(); > >- final List<MatchElement> leftObjectMatchedElements = new ArrayList<MatchElement>( >- leftObjectAncestorMatch.getMatchedElements()); >- final List<MatchElement> rightObjectMatchedElements = new ArrayList<MatchElement>( >- rightObjectAncestorMatch.getMatchedElements()); >- // populates the unmatched elements list for later use >- for (final Object unmatch : leftObjectAncestorMatch.getUnmatchedElements()) { >- remainingUnmatchedElements.add(((UnmatchElement)unmatch).getElement()); >- } >- for (final Object unmatch : rightObjectAncestorMatch.getUnmatchedElements()) { >- remainingUnmatchedElements.add(((UnmatchElement)unmatch).getElement()); >+ MatchModel result = null; >+ if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject) >+ && ancestorScope.isInScope(ancestor)) { >+ result = doContentMatch(leftObject, leftScope, rightObject, rightScope, ancestor, ancestorScope); > } >- try { >- Match3Elements subMatchRoot = null; >- if (leftObjectMatchedElements.size() > 0 && rightObjectMatchedElements.size() > 0) { >- final Match2Elements leftObjectMatchRoot = (Match2Elements)leftObjectMatchedElements.get(0); >- final Match2Elements rightObjectMatchRoot = (Match2Elements)rightObjectMatchedElements.get(0); >- subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements(); >- >- subMatchRoot.setSimilarity(absoluteMetric(leftObjectMatchRoot.getLeftElement(), >- rightObjectMatchRoot.getLeftElement(), rightObjectMatchRoot.getRightElement())); >- subMatchRoot.setLeftElement(leftObjectMatchRoot.getLeftElement()); >- subMatchRoot.setRightElement(rightObjectMatchRoot.getLeftElement()); >- subMatchRoot.setOriginElement(rightObjectMatchRoot.getRightElement()); >- redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot); >- createSub3Match(root, subMatchRoot, leftObjectMatchRoot, rightObjectMatchRoot); >- } else { >- for (final EObject left : leftObjectMatchedElements) { >- stillToFindFromModel1.add(left); >- } >- for (final EObject right : rightObjectMatchedElements) { >- stillToFindFromModel2.add(right); >- } >- } >- // We will now check through the unmatched object for matches. >- processNotFoundElements(root, subMatchRoot); >- // #createSub3Match(MatchModel, Match3Element, Match2Elements, >- // Match2Elements) will have updated "remainingUnmatchedElements" >- final Set<EObject> remainingLeft = new HashSet<EObject>(); >- final Set<EObject> remainingRight = new HashSet<EObject>(); >- for (final EObject unmatched : remainingUnmatchedElements) { >- if (unmatched.eResource() == leftObject.eResource()) { >- remainingLeft.add(unmatched); >- final TreeIterator<EObject> iterator = unmatched.eAllContents(); >- while (iterator.hasNext()) { >- remainingLeft.add(iterator.next()); >+ return result; >+ } >+ >+ /** >+ * This method will compare three {@link EObject}s and their direct content, ignoring the given objects' >+ * siblings and parents, as well as all objects not being part of the scope (indeed the given ones will >+ * also not be compared, if they are not included in the scope), for the match. It will however compute >+ * external mappings for all those objects outside the scope, being referenced from those that are >+ * processed. >+ * >+ * @param leftObject >+ * Left of the two objects to get compared. >+ * @param leftScope >+ * The scope to restrict which content of the left object is processed. >+ * @param rightObject >+ * Right of the two objects to compare. >+ * @param rightScope >+ * The scope to restrict which content of the left object is processed. >+ * @param ancestor >+ * Common ancestor of the two others. >+ * @param ancestorScope >+ * The scope to restrict which content of the ancestor is processed. >+ * @return {@link MatchModel} for these two objects' comparison. >+ */ >+ private MatchModel doContentMatch(EObject leftObject, IMatchScope leftScope, EObject rightObject, >+ IMatchScope rightScope, EObject ancestor, IMatchScope ancestorScope) { >+ MatchModel root = null; >+ >+ // proceed if input elements are within scope >+ if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject) >+ && ancestorScope.isInScope(ancestor)) { >+ root = MatchFactory.eINSTANCE.createMatchModel(); >+ >+ setModelRoots(root, leftObject, rightObject, ancestor); >+ >+ final Monitor monitor = createProgressMonitor(); >+ >+ // perform content match >+ final MatchModel leftObjectAncestorMatch = doContentMatch(leftObject, leftScope, ancestor, >+ ancestorScope); >+ // remove those external mappings added by call to contentMatch >+ leftObjectAncestorMatch.getMatchedElements().removeAll(externalRefMappings); >+ final List<Match2Elements> leftExternal2WayMappings = new ArrayList<Match2Elements>( >+ externalRefMappings); >+ >+ // perform content match >+ final MatchModel rightObjectAncestorMatch = doContentMatch(rightObject, rightScope, ancestor, >+ ancestorScope); >+ // remove those external mappings added by call to contentMatch >+ rightObjectAncestorMatch.getMatchedElements().removeAll(externalRefMappings); >+ final List<Match2Elements> rightExternal2WayMappings = new ArrayList<Match2Elements>( >+ externalRefMappings); >+ >+ final List<MatchElement> leftObjectMatchedElements = new ArrayList<MatchElement>( >+ leftObjectAncestorMatch.getMatchedElements()); >+ final List<MatchElement> rightObjectMatchedElements = new ArrayList<MatchElement>( >+ rightObjectAncestorMatch.getMatchedElements()); >+ >+ // populates the unmatched elements list for later use >+ for (final Object unmatch : leftObjectAncestorMatch.getUnmatchedElements()) { >+ remainingUnmatchedElements.add(((UnmatchElement)unmatch).getElement()); >+ } >+ for (final Object unmatch : rightObjectAncestorMatch.getUnmatchedElements()) { >+ remainingUnmatchedElements.add(((UnmatchElement)unmatch).getElement()); >+ } >+ try { >+ Match3Elements subMatchRoot = null; >+ if (leftObjectMatchedElements.size() > 0 && rightObjectMatchedElements.size() > 0) { >+ final Match2Elements leftObjectMatchRoot = (Match2Elements)leftObjectMatchedElements >+ .get(0); >+ final Match2Elements rightObjectMatchRoot = (Match2Elements)rightObjectMatchedElements >+ .get(0); >+ subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements(); >+ >+ subMatchRoot.setSimilarity(absoluteMetric(leftObjectMatchRoot.getLeftElement(), >+ rightObjectMatchRoot.getLeftElement(), rightObjectMatchRoot.getRightElement())); >+ subMatchRoot.setLeftElement(leftObjectMatchRoot.getLeftElement()); >+ subMatchRoot.setRightElement(rightObjectMatchRoot.getLeftElement()); >+ subMatchRoot.setOriginElement(rightObjectMatchRoot.getRightElement()); >+ redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot); >+ createSub3Match(root, subMatchRoot, leftObjectMatchRoot, rightObjectMatchRoot); >+ } else { >+ for (final EObject left : leftObjectMatchedElements) { >+ stillToFindFromModel1.add(left); > } >- } else if (unmatched.eResource() == rightObject.eResource()) { >- remainingRight.add(unmatched); >- final TreeIterator<EObject> iterator = unmatched.eAllContents(); >- while (iterator.hasNext()) { >- remainingRight.add(iterator.next()); >+ for (final EObject right : rightObjectMatchedElements) { >+ stillToFindFromModel2.add(right); > } > } >- } >- stillToFindFromModel1.clear(); >- stillToFindFromModel2.clear(); >- final List<Match2Elements> mappings = mapLists(new ArrayList<EObject>(remainingLeft), >- new ArrayList<EObject>(remainingRight), this >- .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); >- for (final Match2Elements map : mappings) { >- final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements(); >- subMatch.setLeftElement(map.getLeftElement()); >- subMatch.setRightElement(map.getRightElement()); >- if (subMatchRoot == null) { >- redirectedAdd(root, MATCH_ELEMENT_NAME, subMatch); >- } else { >- redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch); >+ // We will now check through the unmatched object for matches. >+ processNotFoundElements(root, subMatchRoot); >+ // #createSub3Match(MatchModel, Match3Element, Match2Elements, >+ // Match2Elements) will have updated "remainingUnmatchedElements" >+ final Set<EObject> remainingLeft = new HashSet<EObject>(); >+ final Set<EObject> remainingRight = new HashSet<EObject>(); >+ for (final EObject unmatched : remainingUnmatchedElements) { >+ if (unmatched.eResource() == leftObject.eResource()) { >+ remainingLeft.add(unmatched); >+ final TreeIterator<EObject> iterator = unmatched.eAllContents(); >+ while (iterator.hasNext()) { >+ remainingLeft.add(iterator.next()); >+ } >+ } else if (unmatched.eResource() == rightObject.eResource()) { >+ remainingRight.add(unmatched); >+ final TreeIterator<EObject> iterator = unmatched.eAllContents(); >+ while (iterator.hasNext()) { >+ remainingRight.add(iterator.next()); >+ } >+ } > } >+ stillToFindFromModel1.clear(); >+ stillToFindFromModel2.clear(); >+ final List<Match2Elements> mappings = mapLists(new ArrayList<EObject>(remainingLeft), >+ new ArrayList<EObject>(remainingRight), this >+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); >+ for (final Match2Elements map : mappings) { >+ final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements(); >+ subMatch.setLeftElement(map.getLeftElement()); >+ subMatch.setRightElement(map.getRightElement()); >+ if (subMatchRoot == null) { >+ redirectedAdd(root, MATCH_ELEMENT_NAME, subMatch); >+ } else { >+ redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch); >+ } >+ } >+ final Map<EObject, Boolean> unmatchedElements = new EMFCompareMap<EObject, Boolean>(); >+ for (final EObject unmatch : stillToFindFromModel1) { >+ unmatchedElements.put(unmatch, false); >+ createThreeWayUnmatchElements(root, unmatchedElements, true); >+ } >+ unmatchedElements.clear(); >+ for (final EObject remoteUnmatch : stillToFindFromModel2) { >+ unmatchedElements.put(remoteUnmatch, true); >+ createThreeWayUnmatchElements(root, unmatchedElements, false); >+ } >+ } catch (final FactoryException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final InterruptedException e) { >+ // Cannot be thrown since we have no monitor > } >- final Map<EObject, Boolean> unmatchedElements = new EMFCompareMap<EObject, Boolean>(); >- for (final EObject unmatch : stillToFindFromModel1) { >- unmatchedElements.put(unmatch, false); >- createThreeWayUnmatchElements(root, unmatchedElements, true); >- } >- unmatchedElements.clear(); >- for (final EObject remoteUnmatch : stillToFindFromModel2) { >- unmatchedElements.put(remoteUnmatch, true); >- createThreeWayUnmatchElements(root, unmatchedElements, false); >- } >- } catch (final FactoryException e) { >- EMFComparePlugin.log(e, false); >- } catch (final InterruptedException e) { >- // Cannot be thrown since we have no monitor >+ >+ // create mappings for external references >+ create3WayMatches(leftExternal2WayMappings, rightExternal2WayMappings); > } > return root; > } >@@ -259,54 +331,94 @@ > * org.eclipse.emf.ecore.EObject, java.util.Map) > */ > public MatchModel contentMatch(EObject leftObject, EObject rightObject, Map<String, Object> optionMap) { >+ externalRefMappings.clear(); > if (optionMap != null && optionMap.size() > 0) { > loadOptionMap(optionMap); > } > >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, >+ leftObject, rightObject); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ >+ MatchModel result = null; >+ if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)) { >+ result = doContentMatch(leftObject, leftScope, rightObject, rightScope); >+ } >+ return result; >+ } >+ >+ /** >+ * This method will compare two {@link EObject}s and their direct content, ignoring the given objects' >+ * siblings and parents, as well as all objects not being part of the scope (indeed the given ones will >+ * also not be compared, if they are not included in the scope), for the match. It will however compute >+ * external mappings for all those objects outside the scope, being referenced from those that are >+ * processed. >+ * >+ * @param leftObject >+ * Left of the two objects to get compared. >+ * @param leftScope >+ * The scope to restrict which content of the left object is processed. >+ * @param rightObject >+ * Right of the two objects to compare. >+ *@param rightScope >+ * The scope to restrict which content of the left object is processed. >+ * @return {@link MatchModel} for these two objects' comparison. >+ */ >+ private MatchModel doContentMatch(EObject leftObject, IMatchScope leftScope, EObject rightObject, >+ IMatchScope rightScope) { > final Monitor monitor = createProgressMonitor(); > >- final MatchModel root = MatchFactory.eINSTANCE.createMatchModel(); >- setModelRoots(root, leftObject, rightObject); >+ MatchModel root = null; >+ if (leftScope.isInScope(leftObject) && rightScope.isInScope(rightObject)) { >+ root = MatchFactory.eINSTANCE.createMatchModel(); > >- /* >- * As we could very well be passed two EClasses (as opposed to modelMatch which compares all roots of >- * a resource), we cannot filter the model. >- */ >+ setModelRoots(root, leftObject, rightObject); >+ /* >+ * As we could very well be passed two EClasses (as opposed to modelMatch which compares all roots >+ * of a resource), we cannot filter the model. >+ */ > >- final Set<EObject> still1 = new HashSet<EObject>(); >- final Set<EObject> still2 = new HashSet<EObject>(); >+ final Set<EObject> still1 = new HashSet<EObject>(); >+ final Set<EObject> still2 = new HashSet<EObject>(); > >- // navigate through both objects at the same time and realize mappings.. >- try { >- if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_XMI_ID)) { >- matchByXMIID(leftObject, rightObject); >- } >- if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_ID)) { >- matchByID(leftObject, rightObject); >- } >- if (isSimilar(leftObject, rightObject)) { >- stillToFindFromModel1.clear(); >- stillToFindFromModel2.clear(); >- final Match2Elements matchModelRoot = recursiveMappings(leftObject, rightObject, monitor); >- redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot); >- createSubMatchElements(matchModelRoot, new ArrayList<EObject>(stillToFindFromModel1), >- new ArrayList<EObject>(stillToFindFromModel2), monitor); >- still1.addAll(stillToFindFromModel1); >- still2.addAll(stillToFindFromModel2); >- createUnmatchElements(root, still1, true, false); >- createUnmatchElements(root, still2, false, false); >- } else { >- // The two objects passed as this method's parameters are not >- // similar. Creates unmatch root. >- still1.add(leftObject); >- still2.add(rightObject); >- createUnmatchElements(root, still1, true, false); >- createUnmatchElements(root, still2, false, false); >+ // navigate through both objects at the same time and realize mappings.. >+ try { >+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_XMI_ID)) { >+ matchByXMIID(leftObject, rightObject); >+ } >+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_ID)) { >+ matchByID(leftObject, rightObject); >+ } >+ if (isSimilar(leftObject, rightObject)) { >+ stillToFindFromModel1.clear(); >+ stillToFindFromModel2.clear(); >+ final Match2Elements matchModelRoot = recursiveMappings(leftObject, leftScope, >+ rightObject, rightScope, monitor); >+ redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot); >+ createSubMatchElements(matchModelRoot, new ArrayList<EObject>(stillToFindFromModel1), >+ leftScope, new ArrayList<EObject>(stillToFindFromModel2), rightScope, monitor); >+ still1.addAll(stillToFindFromModel1); >+ still2.addAll(stillToFindFromModel2); >+ createUnmatchElements(root, still1, true, false); >+ createUnmatchElements(root, still2, false, false); >+ } else { >+ // The two objects passed as this method's parameters are not >+ // similar. Creates unmatch root. >+ still1.add(leftObject); >+ still2.add(rightObject); >+ createUnmatchElements(root, still1, true, false); >+ createUnmatchElements(root, still2, false, false); >+ } >+ } catch (final FactoryException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final InterruptedException e) { >+ // Cannot be thrown since we have no monitor > } >- } catch (final FactoryException e) { >- EMFComparePlugin.log(e, false); >- } catch (final InterruptedException e) { >- // Cannot be thrown since we have no monitor >+ >+ root.getMatchedElements().addAll(externalRefMappings); > } > return root; > } >@@ -336,7 +448,19 @@ > } > startMonitor(monitor, size << 1); > >- result = doMatch(leftRoot.eResource(), rightRoot.eResource(), ancestor.eResource(), monitor); >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, leftRoot >+ .eResource(), rightRoot.eResource(), ancestor.eResource()); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ final IMatchScope ancestorScope = scopeProvider.getAncestorScope(); >+ >+ if (leftScope.isInScope(leftRoot.eResource()) && rightScope.isInScope(rightRoot.eResource()) >+ && ancestorScope.isInScope(ancestor.eResource())) { >+ result = doMatch(leftRoot.eResource(), leftScope, rightRoot.eResource(), rightScope, ancestor >+ .eResource(), ancestorScope, monitor); >+ } > > return result; > } >@@ -366,7 +490,17 @@ > } > startMonitor(monitor, size); > >- result = doMatch(leftRoot.eResource(), rightRoot.eResource(), monitor); >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, leftRoot >+ .eResource(), rightRoot.eResource()); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ >+ if (leftScope.isInScope(leftRoot.eResource()) && rightScope.isInScope(rightRoot.eResource())) { >+ result = doMatch(leftRoot.eResource(), leftScope, rightRoot.eResource(), rightScope, monitor); >+ } >+ > return result; > } > >@@ -385,6 +519,7 @@ > remainingUnmatchedElements.clear(); > stillToFindFromModel1.clear(); > stillToFindFromModel2.clear(); >+ externalRefMappings.clear(); > uriFragmentCache.clear(); > options.putAll(loadPreferenceOptionMap()); > } >@@ -412,9 +547,19 @@ > size++; > } > } >+ >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, >+ leftResource, rightResource); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ > startMonitor(monitor, size); > >- result = doMatch(leftResource, rightResource, monitor); >+ if (leftScope.isInScope(leftResource) && rightScope.isInScope(rightResource)) { >+ result = doMatch(leftResource, leftScope, rightResource, rightScope, monitor); >+ } > return result; > } > >@@ -443,7 +588,19 @@ > } > startMonitor(monitor, size << 1); > >- result = doMatch(leftResource, rightResource, ancestorResource, monitor); >+ // see if scope provider was passed in via option, otherwise create default one >+ final IMatchScopeProvider scopeProvider = MatchScopeProviderUtil.getScopeProvider(optionMap, >+ leftResource, rightResource, ancestorResource); >+ >+ final IMatchScope leftScope = scopeProvider.getLeftScope(); >+ final IMatchScope rightScope = scopeProvider.getRightScope(); >+ final IMatchScope ancestorScope = scopeProvider.getAncestorScope(); >+ >+ if (leftScope.isInScope(leftResource) && rightScope.isInScope(rightResource) >+ && ancestorScope.isInScope(ancestorResource)) { >+ result = doMatch(leftResource, leftScope, rightResource, rightScope, ancestorResource, >+ ancestorScope, monitor); >+ } > return result; > } > >@@ -869,8 +1026,12 @@ > * Root of the {@link MatchModel} where to insert all these mappings. > * @param list1 > * First of the lists used to compute mapping. >+ * @param list1Scope >+ * The scope to restrict the matching of sub elements in list1. > * @param list2 > * Second of the lists used to compute mapping. >+ * @param list2Scope >+ * The scope to restrict the matching of sub elements in list2. > * @param monitor > * {@link CompareProgressMonitor progress monitor} to display while the comparison lasts. Might > * be <code>null</code>, in which case we won't monitor progress. >@@ -880,8 +1041,9 @@ > * @throws InterruptedException > * Thrown if the operation is cancelled or fails somehow. > */ >- private void createSubMatchElements(EObject root, List<EObject> list1, List<EObject> list2, >- Monitor monitor) throws FactoryException, InterruptedException { >+ private void createSubMatchElements(EObject root, List<EObject> list1, IMatchScope list1Scope, >+ List<EObject> list2, IMatchScope list2Scope, Monitor monitor) throws FactoryException, >+ InterruptedException { > stillToFindFromModel1.clear(); > stillToFindFromModel2.clear(); > final List<Match2Elements> mappings = mapLists(list1, list2, this >@@ -890,8 +1052,8 @@ > final Iterator<Match2Elements> it = mappings.iterator(); > while (it.hasNext()) { > final Match2Elements map = it.next(); >- final Match2Elements match = recursiveMappings(map.getLeftElement(), map.getRightElement(), >- monitor); >+ final Match2Elements match = recursiveMappings(map.getLeftElement(), list1Scope, map >+ .getRightElement(), list2Scope, monitor); > redirectedAdd(root, SUBMATCH_ELEMENT_NAME, match); > } > } >@@ -966,26 +1128,38 @@ > * > * @param leftResource > * Left model for the comparison. >+ * @param leftScope >+ * The {@link IMatchScope} restricting the left side of comparison. > * @param rightResource > * Right model for the comparison. >+ * @param rightScope >+ * The {@link IMatchScope} restricting the right side of comparison. > * @param monitor > * Progress monitor to display while the comparison lasts. > * @return The corresponding {@link MatchModel}. > * @throws InterruptedException > * Thrown if the comparison is interrupted somehow. > */ >- private MatchModel doMatch(Resource leftResource, Resource rightResource, Monitor monitor) >- throws InterruptedException { >+ private MatchModel doMatch(Resource leftResource, IMatchScope leftScope, Resource rightResource, >+ IMatchScope rightScope, Monitor monitor) throws InterruptedException { >+ externalRefMappings.clear(); > final MatchModel root = MatchFactory.eINSTANCE.createMatchModel(); > EObject leftRoot = null; > EObject rightRoot = null; >- if (leftResource.getContents().size() > 0) { >- leftRoot = leftResource.getContents().get(0); >+ >+ final List<EObject> leftContents = getScopeInternalContents(leftResource, leftScope); >+ final List<EObject> rightContents = getScopeInternalContents(rightResource, rightScope); >+ >+ if (leftContents.size() > 0) { >+ leftRoot = leftContents.get(0); > } >- if (rightResource.getContents().size() > 0) { >- rightRoot = rightResource.getContents().get(0); >+ >+ if (rightContents.size() > 0) { >+ rightRoot = rightContents.get(0); > } >+ > setModelRoots(root, leftRoot, rightRoot); >+ > // filters unused features > filterUnused(leftResource); > filterUnused(rightResource); >@@ -1001,27 +1175,26 @@ > } > > monitor.subTask(EMFCompareMatchMessages.getString("DifferencesServices.monitor.roots")); //$NON-NLS-1$ >- final List<Match2Elements> matchedRoots = mapLists(leftResource.getContents(), rightResource >- .getContents(), this.<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); >+ final List<Match2Elements> matchedRoots = mapLists(leftContents, rightContents, this >+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); > stillToFindFromModel1.clear(); > stillToFindFromModel2.clear(); >- final List<EObject> unmatchedLeftRoots = new ArrayList<EObject>(leftResource.getContents()); >- final List<EObject> unmatchedRightRoots = new ArrayList<EObject>(rightResource.getContents()); >+ final List<EObject> unmatchedLeftRoots = new ArrayList<EObject>(leftContents); >+ final List<EObject> unmatchedRightRoots = new ArrayList<EObject>(rightContents); > // These sets will help us in keeping track of the yet to be found > // elements > final Set<EObject> still1 = new HashSet<EObject>(); > final Set<EObject> still2 = new HashSet<EObject>(); > > // If one of the resources has no roots, considers it as deleted >- if (leftResource.getContents().size() > 0 && rightResource.getContents().size() > 0) { >+ if (leftContents.size() > 0 && rightContents.size() > 0) { > Match2Elements matchModelRoot = MatchFactory.eINSTANCE.createMatch2Elements(); > // We haven't found any similar roots, we then consider the > // firsts to be similar. > if (matchedRoots.size() == 0) { > final Match2Elements rootMapping = MatchFactory.eINSTANCE.createMatch2Elements(); >- rootMapping.setLeftElement(leftResource.getContents().get(0)); >- EObject rightElement = findMostSimilar(leftResource.getContents().get(0), >- unmatchedRightRoots); >+ rootMapping.setLeftElement(leftContents.get(0)); >+ EObject rightElement = findMostSimilar(leftContents.get(0), unmatchedRightRoots); > if (rightElement == null) { > rightElement = unmatchedRightRoots.get(0); > } >@@ -1032,7 +1205,7 @@ > .getString("DifferencesServices.monitor.rootsContents")); //$NON-NLS-1$ > for (final Match2Elements matchedRoot : matchedRoots) { > final Match2Elements rootMapping = recursiveMappings(matchedRoot.getLeftElement(), >- matchedRoot.getRightElement(), monitor); >+ leftScope, matchedRoot.getRightElement(), rightScope, monitor); > // this is the first time we're here > if (matchModelRoot.getLeftElement() == null) { > matchModelRoot = rootMapping; >@@ -1046,7 +1219,7 @@ > still2.removeAll(stillToFindFromModel2); > // checks for matches within the yet to found elements lists > createSubMatchElements(rootMapping, new ArrayList<EObject>(stillToFindFromModel1), >- new ArrayList<EObject>(stillToFindFromModel2), monitor); >+ leftScope, new ArrayList<EObject>(stillToFindFromModel2), rightScope, monitor); > // Adds all unfound elements to the sets > still1.addAll(stillToFindFromModel1); > still2.addAll(stillToFindFromModel2); >@@ -1057,7 +1230,8 @@ > // We'll iterate through the unmatchedRoots all contents > monitor.subTask(EMFCompareMatchMessages > .getString("DifferencesServices.monitor.unmatchedRoots")); //$NON-NLS-1$ >- createSubMatchElements(matchModelRoot, unmatchedLeftRoots, unmatchedRightRoots, monitor); >+ createSubMatchElements(matchModelRoot, unmatchedLeftRoots, leftScope, unmatchedRightRoots, >+ rightScope, monitor); > } else { > // Roots are unmatched, this is either a file addition or > // deletion >@@ -1073,6 +1247,8 @@ > } catch (final FactoryException e) { > EMFComparePlugin.log(e, false); > } >+ >+ root.getMatchedElements().addAll(externalRefMappings); > return root; > } > >@@ -1081,34 +1257,58 @@ > * > * @param leftResource > * Left model for the comparison. >+ * @param leftScope >+ * The {@link IMatchScope} restricting the left side of comparison. > * @param rightResource > * Right model for the comparison. >+ * @param rightScope >+ * The {@link IMatchScope} restricting the right side of comparison. > * @param ancestorResource > * Common ancestor of the right and left models. >+ * @param ancestorScope >+ * The {@link IMatchScope} restricting the ancestor side of comparison. > * @param monitor > * Progress monitor to display while the comparison lasts. > * @return The corresponding {@link MatchModel}. > * @throws InterruptedException > * Thrown if the comparison is interrupted somehow. > */ >- private MatchModel doMatch(Resource leftResource, Resource rightResource, Resource ancestorResource, >- Monitor monitor) throws InterruptedException { >+ private MatchModel doMatch(Resource leftResource, IMatchScope leftScope, Resource rightResource, >+ IMatchScope rightScope, Resource ancestorResource, IMatchScope ancestorScope, Monitor monitor) >+ throws InterruptedException { > final MatchModel root = MatchFactory.eINSTANCE.createMatchModel(); > EObject leftRoot = null; > EObject rightRoot = null; > EObject ancestorRoot = null; >- if (leftResource.getContents().size() > 0) { >- leftRoot = leftResource.getContents().get(0); >+ >+ final List<EObject> leftContents = getScopeInternalContents(leftResource, leftScope); >+ final List<EObject> rightContents = getScopeInternalContents(rightResource, rightScope); >+ final List<EObject> ancestorContents = getScopeInternalContents(ancestorResource, ancestorScope); >+ >+ if (leftContents.size() > 0) { >+ leftRoot = leftContents.get(0); > } >- if (rightResource.getContents().size() > 0) { >- rightRoot = rightResource.getContents().get(0); >+ if (rightContents.size() > 0) { >+ rightRoot = rightContents.get(0); > } >- if (ancestorResource.getContents().size() > 0) { >- ancestorRoot = ancestorResource.getContents().get(0); >+ if (ancestorContents.size() > 0) { >+ ancestorRoot = ancestorContents.get(0); > } > setModelRoots(root, leftRoot, rightRoot, ancestorRoot); >- final MatchModel root1AncestorMatch = doMatch(leftResource, ancestorResource, monitor); >- final MatchModel root2AncestorMatch = doMatch(rightResource, ancestorResource, monitor); >+ >+ final MatchModel root1AncestorMatch = doMatch(leftResource, leftScope, ancestorResource, >+ ancestorScope, monitor); >+ // remove those external mappings added by call to doMatch >+ root1AncestorMatch.getMatchedElements().removeAll(externalRefMappings); >+ final List<Match2Elements> leftExternal2WayMappings = new ArrayList<Match2Elements>( >+ externalRefMappings); >+ >+ final MatchModel root2AncestorMatch = doMatch(rightResource, rightScope, ancestorResource, >+ ancestorScope, monitor); >+ // remove those external mappings added by call to doMatch >+ root2AncestorMatch.getMatchedElements().removeAll(externalRefMappings); >+ final List<Match2Elements> rightExternal2WayMappings = new ArrayList<Match2Elements>( >+ externalRefMappings); > > final List<MatchElement> root1MatchedElements = new ArrayList<MatchElement>(root1AncestorMatch > .getMatchedElements()); >@@ -1159,10 +1359,47 @@ > EMFComparePlugin.log(e, false); > } > >+ // create three way mappings for external references >+ root.getMatchedElements().addAll( >+ create3WayMatches(leftExternal2WayMappings, rightExternal2WayMappings)); > return root; > } > > /** >+ * Creates {@link Match3Elements} by merging those {@link Match2Elements}, having the same ancestor. >+ * >+ * @param leftToAncestor >+ * matches between a left elements and their ancestors. >+ * @param rightToAncestor >+ * matches between right elements and their ancestors. >+ * @return A list of newly created {@link Match3Elements}, each created for a pair of >+ * {@link Match2Elements} from the leftToAncestor and rightToAncestor lists, sharing the same >+ * ancestor. >+ */ >+ private List<Match3Elements> create3WayMatches(List<Match2Elements> leftToAncestor, >+ List<Match2Elements> rightToAncestor) { >+ // create three way mappings for external references >+ final List<Match3Elements> threeWayMappings = new ArrayList<Match3Elements>(); >+ for (Match2Elements leftExternalMapping : leftToAncestor) { >+ final Match2Elements rightExternalMapping = rightToAncestor.get(leftToAncestor >+ .indexOf(leftExternalMapping)); >+ >+ final Match3Elements mapping = MatchFactory.eINSTANCE.createMatch3Elements(); >+ mapping.setLeftElement(leftExternalMapping.getLeftElement()); >+ mapping.setRightElement(rightExternalMapping.getLeftElement()); >+ mapping.setOriginElement(rightExternalMapping.getRightElement()); >+ try { >+ mapping.setSimilarity(absoluteMetric(mapping.getLeftElement(), mapping.getRightElement(), >+ mapping.getOriginElement())); >+ } catch (FactoryException e) { >+ mapping.setSimilarity(1.0d); >+ } >+ threeWayMappings.add(mapping); >+ } >+ return threeWayMappings; >+ } >+ >+ /** > * Filters unused features of the resource. > * > * @param resource >@@ -1181,21 +1418,43 @@ > * > * @param eObject > * The EObject we seek the content of. >+ * @param scope >+ * The scope to restrict the contents. > * @return The list of all the content of a given EObject, derived containmnent references included. > */ > @SuppressWarnings("unchecked") >- private List<EObject> getContents(EObject eObject) { >- final List<EObject> result = new ArrayList<EObject>(eObject.eContents()); >+ private List<EObject> getScopeInternalContents(EObject eObject, IMatchScope scope) { >+ // filter out those contained objects belonging to a fragment resource >+ final List<EObject> result = new ArrayList<EObject>(); >+ // add contents within scope >+ for (EObject contents : eObject.eContents()) { >+ // only add direct "non-fragment" contents >+ if (!result.contains(contents) && scope.isInScope(contents) >+ && (contents.eResource() == null || eObject.eResource() == contents.eResource())) { >+ result.add(contents); >+ } >+ } >+ // add derived containment references in scope (do not objects contained in fragments) > for (final EReference reference : eObject.eClass().getEAllReferences()) { > if (reference.isContainment() && reference.isDerived()) { > final Object value = eObject.eGet(reference); > if (value instanceof Collection) { >- for (Object newValue : (Collection)value) { >- if (!result.contains(newValue) && newValue instanceof EObject) >- result.add((EObject)newValue); >+ for (Object contents : (Collection)value) { >+ if (!result.contains(contents) && contents instanceof EObject) { >+ final EObject object = (EObject)contents; >+ if (scope.isInScope(object) >+ && (object.eResource() == null || eObject.eResource() == object >+ .eResource())) { >+ result.add(object); >+ } >+ } > } > } else if (!result.contains(value) && value instanceof EObject) { >- result.add((EObject)value); >+ final EObject object = (EObject)value; >+ if (scope.isInScope(object) >+ && (object.eResource() == null || eObject.eResource() == object.eResource())) { >+ result.add(object); >+ } > } > } > } >@@ -1203,6 +1462,27 @@ > } > > /** >+ * Returns all objects contained in the given resource (via {@link Resource#getContents()}), covered by >+ * the provided scope. >+ * >+ * @param resource >+ * The resource, whose contents is to be regarded. >+ * @param scope >+ * The scope to restrict, which of the contents' objects is included in the returned list. >+ * @return The list of conents' objects, covered within the given scope. >+ */ >+ private List<EObject> getScopeInternalContents(Resource resource, IMatchScope scope) { >+ final List<EObject> result = new ArrayList<EObject>(); >+ for (EObject contents : resource.getContents()) { >+ if (!result.contains(contents) && scope.isInScope(contents) >+ && (contents.eResource() == null || resource == contents.eResource())) { >+ result.add(contents); >+ } >+ } >+ return result; >+ } >+ >+ /** > * Returns whether we should assume the metamodels of the compared models are distinct. > * > * @return <code>true</code> if the metamodels are to be assumed distinct, <code>false</code> otherwise. >@@ -1824,8 +2104,12 @@ > * > * @param current1 > * First element of the two elements mapping. >+ * @param current1Scope >+ * The {@link IMatchScope} to restrict the contents of current1. > * @param current2 > * Second of the two elements mapping. >+ * @param current2Scope >+ * The {@link IMatchScope} to restrict the contents of current2. > * @param monitor > * {@link CompareProgressMonitor Progress monitor} to display while the comparison lasts. Might > * be <code>null</code>, in which case we won't monitor progress. >@@ -1836,15 +2120,16 @@ > * @throws InterruptedException > * Thrown if the matching process is interrupted somehow. > */ >- private Match2Elements recursiveMappings(EObject current1, EObject current2, Monitor monitor) >- throws FactoryException, InterruptedException { >+ private Match2Elements recursiveMappings(EObject current1, IMatchScope current1Scope, EObject current2, >+ IMatchScope current2Scope, Monitor monitor) throws FactoryException, InterruptedException { > Match2Elements mapping = null; > mapping = MatchFactory.eINSTANCE.createMatch2Elements(); > mapping.setLeftElement(current1); > mapping.setRightElement(current2); > mapping.setSimilarity(absoluteMetric(current1, current2)); >- final List<Match2Elements> mapList = mapLists(getContents(current1), getContents(current2), this >- .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); >+ final List<Match2Elements> mapList = mapLists(getScopeInternalContents(current1, current1Scope), >+ getScopeInternalContents(current2, current2Scope), this >+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor); > // We can map other elements with mapLists; we iterate through them. > final Iterator<Match2Elements> it = mapList.iterator(); > while (it.hasNext()) { >@@ -1852,12 +2137,63 @@ > // As we know source and target are similars, we call recursive > // mappings onto these objects > EFactory.eAdd(mapping, SUBMATCH_ELEMENT_NAME, recursiveMappings(subMapping.getLeftElement(), >- subMapping.getRightElement(), monitor)); >+ current1Scope, subMapping.getRightElement(), current2Scope, monitor)); > } >+ >+ // we also have to match those elements, which are directly referenced but not contained in the >+ // specified match scope. Otherwise the diff engine will detect reference changes also in case >+ // there is no change >+ final List<EObject> current1ScopeExternalReferences = getScopeExternalReferences(current1, >+ current1Scope); >+ final List<EObject> current2ScopeExternalReferences = getScopeExternalReferences(current2, >+ current2Scope); >+ for (EObject leftRef : current1ScopeExternalReferences) { >+ final EObject rightRef = findMostSimilar(leftRef, current2ScopeExternalReferences); >+ if (rightRef != null && findMostSimilar(rightRef, current1ScopeExternalReferences) == leftRef) { >+ // create a mapping to indicate an exact match (as this is out of scope) >+ final Match2Elements externalRefMapping = MatchFactory.eINSTANCE.createMatch2Elements(); >+ externalRefMapping.setLeftElement(leftRef); >+ externalRefMapping.setRightElement(rightRef); >+ externalRefMapping.setSimilarity(absoluteMetric(leftRef, rightRef)); >+ externalRefMappings.add(externalRefMapping); >+ } >+ } >+ > return mapping; > } > > /** >+ * Obtain all EObjets, which are referenced by the given eObject ({@link EObject#getEAllReferences()}), >+ * but are not part of the match scope. >+ * >+ * @param eObject >+ * the eObject, whose references are to be regarded >+ * @param scope >+ * the scope to decide whether the target of a given reference has to be included in the list >+ * of referenced objects or not >+ * @return the list of all objects, referenced by the given one, which are not part of the scope >+ */ >+ @SuppressWarnings("unchecked") >+ private List<EObject> getScopeExternalReferences(EObject eObject, IMatchScope scope) { >+ final List<EObject> result = new ArrayList<EObject>(); >+ // process all references to outside the scope >+ for (final EReference reference : eObject.eClass().getEAllReferences()) { >+ final Object value = eObject.eGet(reference); >+ if (value instanceof Collection) { >+ for (Object newValue : (Collection)value) { >+ if (!result.contains(newValue) && newValue instanceof EObject >+ && !scope.isInScope((EObject)newValue)) >+ result.add((EObject)newValue); >+ } >+ } else if (!result.contains(value) && value instanceof EObject >+ && !scope.isInScope((EObject)value)) { >+ result.add((EObject)value); >+ } >+ } >+ return result; >+ } >+ >+ /** > * This method is an indirection for adding Mappings in the current MappingGroup. > * > * @param object >Index: src/org/eclipse/emf/compare/match/engine/IMatchEngine.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/engine/IMatchEngine.java,v >retrieving revision 1.3 >diff -u -r1.3 IMatchEngine.java >--- src/org/eclipse/emf/compare/match/engine/IMatchEngine.java 24 Nov 2009 09:35:39 -0000 1.3 >+++ src/org/eclipse/emf/compare/match/engine/IMatchEngine.java 25 Feb 2010 22:04:50 -0000 >@@ -156,4 +156,5 @@ > */ > MatchModel resourceMatch(Resource leftResource, Resource rightResource, Resource ancestorResource, > Map<String, Object> optionMap) throws InterruptedException; >+ > } >Index: src/org/eclipse/emf/compare/match/MatchOptions.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.match/src/org/eclipse/emf/compare/match/MatchOptions.java,v >retrieving revision 1.1 >diff -u -r1.1 MatchOptions.java >--- src/org/eclipse/emf/compare/match/MatchOptions.java 13 Feb 2009 13:31:18 -0000 1.1 >+++ src/org/eclipse/emf/compare/match/MatchOptions.java 25 Feb 2010 22:04:46 -0000 >@@ -47,6 +47,14 @@ > * values increase comparison time, lower values decrease comparison accuracy.</td> > * <td>Positive integer, defaults to <code>100</code>. A negative value will be reset to the default.</td> > * </tr> >+ * <tr> >+ * <td>{@link #OPTION_MATCH_SCOPE_PROVIDER}</td> >+ * <td>Allows to pass an {@link org.eclipse.emf.compare.match.engine.IMatchScopeProvider} instance to the >+ * {@link org.eclipse.emf.compare.match.engine.IMatchEngine} to restrict the scope of comparison.</td> >+ * <td>The specified {@link org.eclipse.emf.compare.match.engine.IMatchScopeProvider} may be evaluated by the >+ * {@link org.eclipse.emf.compare.match.engine.IMatchEngine} to restrict the scope of objects/resources to be >+ * compared.</td> >+ * </tr> > * </table> > * </p> > * >@@ -79,4 +87,10 @@ > > /** Key for the option defining the search window. */ > String OPTION_SEARCH_WINDOW = "match.search.window"; //$NON-NLS-1$ >+ >+ /** >+ * Key for an {@link org.eclipse.emf.compare.match.engine.IMatchScopeProvider} to limit the scope >+ * processed by the match engine. >+ */ >+ String OPTION_MATCH_SCOPE_PROVIDER = "match.scope.provider"; //$NON-NLS-1$ > } >Index: src/org/eclipse/emf/compare/match/engine/IMatchScope.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/match/engine/IMatchScope.java >diff -N src/org/eclipse/emf/compare/match/engine/IMatchScope.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/match/engine/IMatchScope.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,45 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 itemis AG (http://www.itemis.de) >+ * 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: >+ * itemis AG - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.emf.compare.match.engine; >+ >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.resource.Resource; >+ >+/** >+ * A Match Scope is used by the match engine to limit the range of comparison. Only objects/resources within >+ * scope, as well as referenced objects directly outside (but not their contents or any of their external >+ * referces) may be compared. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public interface IMatchScope { >+ >+ /** >+ * Specifies whether the given {@link EObject} should be regarded as part of the match scope or not. If >+ * the passed in {@link EObject} is contained in a {@link Resource}, it may only be regarded to be within >+ * scope, if its {@link Resource} is also specified to be in scope via {@link #isInScope(Resource)}. >+ * >+ * @param eObject >+ * the {@link EObject} of interest >+ * @return <code>true</code> if eObject is part of the scope, <code>false</code> otherwise >+ */ >+ boolean isInScope(EObject eObject); >+ >+ /** >+ * Specifies whether the given {@link Resource} should be regarded as part of the match scope or not. >+ * >+ * @param resource >+ * the {@link resource} of interest >+ * @return <code>true</code> if resource is part of the scope, <code>false</code> otherwise >+ */ >+ boolean isInScope(Resource resource); >+} >Index: src/org/eclipse/emf/compare/match/engine/MatchScopeProviderUtil.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/match/engine/MatchScopeProviderUtil.java >diff -N src/org/eclipse/emf/compare/match/engine/MatchScopeProviderUtil.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/match/engine/MatchScopeProviderUtil.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,131 @@ >+/******************************************************************************* >+ * Copyright (c) 2006, 2009 Obeo. >+ * 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.match.engine; >+ >+import java.util.Map; >+ >+import org.eclipse.emf.compare.match.MatchOptions; >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.resource.Resource; >+import org.eclipse.emf.ecore.resource.ResourceSet; >+ >+/** >+ * Utility class to support work with {@link IMatchScope}s. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public final class MatchScopeProviderUtil { >+ >+ /** >+ * Private constructor (to prevent instantiation). >+ */ >+ private MatchScopeProviderUtil() { >+ // private constructor to prevent instantiation. >+ } >+ >+ /** >+ * Used to obtain the {@link IMatchScopeProvider} to be used for matching. If one is specified within the >+ * provided options via {@link MatchOptions#OPTION_MATCH_SCOPE_PROVIDER}, this one is used, otherwise a >+ * new {@link GenericMatchScopeProvider} will be instantiated and returned. >+ * >+ * @param options >+ * the options to search for any preset {@link IMatchScopeProvider}. >+ * @param resourceSets >+ * the list of resources sets to be used for constructing a new >+ * {@link GenericMatchScopeProvider}, in case none is specified via the options. Has to be >+ * either of size 2 (left and right) or 3 (left, right, and ancestor). >+ * @return the {@link IMatchScopeProvider} specified via the given options or a new >+ * {@link GenericMatchScopeProvider} instance if none is specified in the options. >+ */ >+ public static IMatchScopeProvider getScopeProvider(Map<String, Object> options, >+ ResourceSet... resourceSets) { >+ IMatchScopeProvider scopeProvider = getScopeProvider(options); >+ if (scopeProvider == null) { >+ if (resourceSets.length == 2) { >+ scopeProvider = new GenericMatchScopeProvider(resourceSets[0], resourceSets[1]); >+ } else { >+ scopeProvider = new GenericMatchScopeProvider(resourceSets[0], resourceSets[1], >+ resourceSets[2]); >+ } >+ } >+ return scopeProvider; >+ } >+ >+ /** >+ * Used to obtain the {@link IMatchScopeProvider} to be used for matching. If one is specified within the >+ * provided options via {@link MatchOptions#OPTION_MATCH_SCOPE_PROVIDER}, this one is used, otherwise a >+ * new {@link GenericMatchScopeProvider} will be instantiated and returned. >+ * >+ * @param options >+ * the options to search for any preset {@link IMatchScopeProvider}. >+ * @param resources >+ * the list of resources to be used for constructing a new {@link GenericMatchScopeProvider}, >+ * in case none is specified via the options. Has to be either of size 2 (left and right) or 3 >+ * (left, right, and ancestor). >+ * @return the {@link IMatchScopeProvider} specified via the given options or a new >+ * {@link GenericMatchScopeProvider} instance if none is specified in the options. >+ */ >+ public static IMatchScopeProvider getScopeProvider(Map<String, Object> options, Resource... resources) { >+ IMatchScopeProvider scopeProvider = getScopeProvider(options); >+ if (scopeProvider == null) { >+ if (resources.length == 2) { >+ scopeProvider = new GenericMatchScopeProvider(resources[0], resources[1]); >+ } else { >+ scopeProvider = new GenericMatchScopeProvider(resources[0], resources[1], resources[2]); >+ } >+ } >+ return scopeProvider; >+ } >+ >+ /** >+ * Used to obtain the {@link IMatchScopeProvider} to be used for matching. If one is specified within the >+ * provided options via {@link MatchOptions#OPTION_MATCH_SCOPE_PROVIDER}, this one is used, otherwise a >+ * new {@link GenericMatchScopeProvider} will be instantiated and returned. >+ * >+ * @param options >+ * the options to search for any preset {@link IMatchScopeProvider}. >+ * @param eObjects >+ * the list of objects to be used for constructing a new {@link GenericMatchScopeProvider}, in >+ * case none is specified via the options. Has to be either of size 2 (left and right) or 3 >+ * (left, right, and ancestor). >+ * @return the {@link IMatchScopeProvider} specified via the given options or a new >+ * {@link GenericMatchScopeProvider} instance if none is specified in the options. >+ */ >+ public static IMatchScopeProvider getScopeProvider(Map<String, Object> options, EObject... eObjects) { >+ IMatchScopeProvider scopeProvider = getScopeProvider(options); >+ if (scopeProvider == null) { >+ if (eObjects.length == 2) { >+ scopeProvider = new GenericMatchScopeProvider(eObjects[0], eObjects[1]); >+ } else { >+ scopeProvider = new GenericMatchScopeProvider(eObjects[0], eObjects[1], eObjects[2]); >+ } >+ } >+ return scopeProvider; >+ } >+ >+ /** >+ * Checks whether an {@link IMatchScopeProvider} instance is specified within the options via >+ * {@link MatchOptions#OPTION_MATCH_SCOPE_PROVIDER} and returns it. >+ * >+ * @param options >+ * the options to process. >+ * @return the {@link IMatchScopeProvider} specified within the given options, <code>null</code> if no >+ * provider is specified. >+ */ >+ private static IMatchScopeProvider getScopeProvider(Map<String, Object> options) { >+ IMatchScopeProvider scopeProvider = null; >+ if (options != null) { >+ scopeProvider = (IMatchScopeProvider)options.get(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER); >+ } >+ return scopeProvider; >+ } >+} >Index: src/org/eclipse/emf/compare/match/engine/GenericMatchScope.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/match/engine/GenericMatchScope.java >diff -N src/org/eclipse/emf/compare/match/engine/GenericMatchScope.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/match/engine/GenericMatchScope.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,173 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 itemis AG (http://www.itemis.de) >+ * 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: >+ * itemis AG - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.emf.compare.match.engine; >+ >+import java.util.ArrayList; >+import java.util.Iterator; >+import java.util.List; >+ >+import org.eclipse.emf.compare.util.ModelUtils; >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.resource.Resource; >+import org.eclipse.emf.ecore.resource.ResourceSet; >+ >+/** >+ * The default {@link IMatchScope} implementation, which can be constructed with a single {@link Resource} or >+ * {@link ResourceSet}, or a single {@link EObject}. In case an instance is constructed by passing in a >+ * {@link Resource}, it will regard this resource and all its direct and indirect contents (fragments) to be >+ * in scope. If being instantiated with a {@link ResourceSet}, all resources within the set (as well as their >+ * direct and indirect content) are included in the scope. In case an instance is constructed with an >+ * {@link EObject}, its direct and indirect contents ({@link EObject#eAllContents()}) as well as its resource >+ * ({@link EObject#eResource}), if specified, will be regarded to be within scope. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public class GenericMatchScope implements IMatchScope { >+ >+ /** the list of resources to be included in the scope. */ >+ private final List<Resource> resourcesInScope = new ArrayList<Resource>(); >+ >+ /** the list of objects to be included in the scope. */ >+ private final List<EObject> eObjectsInScope = new ArrayList<EObject>(); >+ >+ /** >+ * Allows to construct a scope based on a single {@link EObject}. The constructed scope will include the >+ * provided {@link EObject}, its direct and indirect contents ({@link EObject#eAllContents()}) as well as >+ * its resource ({@link EObject#eResource}) in case one is specified. >+ * >+ * @param eObject >+ * the {@link EObject} used to construct the scope. >+ */ >+ public GenericMatchScope(EObject eObject) { >+ eObjectsInScope.add(eObject); >+ final Iterator<EObject> iterator = eObject.eAllContents(); >+ while (iterator.hasNext()) { >+ final EObject next = iterator.next(); >+ eObjectsInScope.add(next); >+ if (next.eResource() != null && !resourcesInScope.contains(next.eResource())) { >+ resolveAll(next.eResource().getResourceSet()); >+ resourcesInScope.add(next.eResource()); >+ } >+ } >+ } >+ >+ /** >+ * Allows to construct a scope based on a single {@link Resource}. The constructed scope will include the >+ * {@link Resource} as well as its direct and indirect contents {@link Resource#getAllContents()} of the >+ * provided resource. >+ * >+ * @param scope >+ * the {@link Resource} used to construct the scope. >+ */ >+ public GenericMatchScope(Resource scope) { >+ resolveAll(scope.getResourceSet()); >+ this.resourcesInScope.add(scope); >+ } >+ >+ /** >+ * Allow to construct a scope based on a single {@link ResourceSet}. The constructed scope will include >+ * all resources of the resource set (@link {@link ResourceSet#getResources()}) as well as their content ( >+ * {@link Resource#getAllContents()}). >+ * >+ * @param scope >+ * the {@link ResourceSet} used to construct the scope. >+ */ >+ public GenericMatchScope(ResourceSet scope) { >+ resolveAll(scope); >+ this.resourcesInScope.addAll(scope.getResources()); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see IMatchScope#isInScope(org.eclipse.emf.ecore.EObject) >+ */ >+ public boolean isInScope(EObject eObject) { >+ // if eObject is directly contained in the list, we do not have to search resources >+ if (eObjectsInScope.contains(eObject)) { >+ return true; >+ } >+ // check its containing resource >+ final Resource resource = getContainingResource(eObject); >+ if (resource == null) { >+ return false; >+ } >+ return isInScope(resource); >+ } >+ >+ /** >+ * Determines the containing resource for the given eObject. >+ * >+ * @param eObject >+ * the {@link EObject} whose containing resource has to be found >+ * @return the resource of the containing eObject or <code>null</code> in case the eObject does not >+ * specify a containing resource and none containing the eObject could be found in the internal >+ * list of resources in scope either. >+ */ >+ private Resource getContainingResource(EObject eObject) { >+ // stereotype applications may e.g. not specify an eResource but be contained within one. >+ if (eObject.eResource() != null) { >+ return eObject.eResource(); >+ } >+ for (Resource resourceInScope : getResourcesInScope()) { >+ if (ModelUtils.contains(resourceInScope, eObject)) { >+ return resourceInScope; >+ } >+ } >+ return null; >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.compare.match.engine.IMatchScope#isInScope(org.eclipse.emf.ecore.resource.Resource) >+ */ >+ public boolean isInScope(Resource resource) { >+ if (getResourcesInScope().contains(resource)) { >+ return true; >+ } >+ return false; >+ } >+ >+ /** >+ * Returns the list of {@link Resource}s to be included in the scope. This should only be used to allow >+ * the application of {@link org.eclipse.emf.compare.match.filter.IResourceFilter} to restrict the scope >+ * after its construction. >+ * >+ * @return the list of {@link Resource}s by references. >+ */ >+ public List<Resource> getResourcesInScope() { >+ return resourcesInScope; >+ } >+ >+ /** >+ * Resolved all proxies within the given resource set. >+ * >+ * @param resourceSet >+ * the resource set to resolve. >+ */ >+ private static void resolveAll(ResourceSet resourceSet) { >+ final List<Resource> resources = resourceSet.getResources(); >+ for (int i = 0; i < resources.size(); ++i) { >+ final Iterator<EObject> resourceContent = resources.get(i).getAllContents(); >+ while (resourceContent.hasNext()) { >+ final EObject eObject = resourceContent.next(); >+ final Iterator<EObject> objectChildren = eObject.eCrossReferences().iterator(); >+ while (objectChildren.hasNext()) { >+ // Resolves cross references by simply visiting them. >+ objectChildren.next(); >+ } >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/emf/compare/match/engine/GenericMatchScopeProvider.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/match/engine/GenericMatchScopeProvider.java >diff -N src/org/eclipse/emf/compare/match/engine/GenericMatchScopeProvider.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/match/engine/GenericMatchScopeProvider.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,189 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 itemis AG (http://www.itemis.de) >+ * 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: >+ * itemis AG - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.emf.compare.match.engine; >+ >+import java.util.List; >+ >+import org.eclipse.emf.compare.match.filter.IResourceFilter; >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.resource.Resource; >+import org.eclipse.emf.ecore.resource.ResourceSet; >+ >+/** >+ * The default implementation of an {@link IMatchScopeProvider}. It will use {@link GenericMatchScope} >+ * implementations for all its scopes. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public class GenericMatchScopeProvider implements IMatchScopeProvider { >+ >+ /** The match scope used for the left side of comparison. */ >+ private IMatchScope leftScope; >+ >+ /** The match scope used for the right side of comparison. */ >+ private IMatchScope rightScope; >+ >+ /** The match scope used for the ancestor side of comparison. */ >+ private IMatchScope ancestorScope; >+ >+ /** >+ * Constructs a left and right {@link GenericMatchScope} with the given {@link EObject}s. No ancestor >+ * scope will be created, so calls to {@link #getAncestorScope()} will return <code>null</code>. >+ * >+ * @param leftObject >+ * the {@link EObject}, which will be used to construct the left scope >+ * @param rightObject >+ * the {@link EObject}, which will be used to construct the right scope >+ */ >+ public GenericMatchScopeProvider(EObject leftObject, EObject rightObject) { >+ this.leftScope = new GenericMatchScope(leftObject); >+ this.rightScope = new GenericMatchScope(rightObject); >+ } >+ >+ /** >+ * Constructs a left, right, and ancestor {@link GenericMatchScope} with the given {@link EObject}s. >+ * >+ * @param leftObject >+ * the {@link EObject}, which will be used to construct the left scope >+ * @param rightObject >+ * the {@link EObject}, which will be used to construct the right scope >+ * @param ancestorObject >+ * the {@link EObject}, which will be used to construct the ancestor scope >+ */ >+ public GenericMatchScopeProvider(EObject leftObject, EObject rightObject, EObject ancestorObject) { >+ this(leftObject, rightObject); >+ this.ancestorScope = new GenericMatchScope(ancestorObject); >+ } >+ >+ /** >+ * Constructs a left and right {@link GenericMatchScope} with the given {@link Resource}s. No ancestor >+ * scope will be created, so calls to {@link #getAncestorScope()} will return <code>null</code>. >+ * >+ * @param leftResource >+ * the {@link Resource}, which will be used to construct the left scope >+ * @param rightResource >+ * the {@link Resource}, which will be used to construct the right scope >+ */ >+ public GenericMatchScopeProvider(Resource leftResource, Resource rightResource) { >+ this.leftScope = new GenericMatchScope(leftResource); >+ this.rightScope = new GenericMatchScope(rightResource); >+ } >+ >+ /** >+ * Constructs a left, right, and ancestor {@link GenericMatchScope} with the given {@link Resource}s. >+ * >+ * @param leftResource >+ * the {@link Resource}, which will be used to construct the left scope >+ * @param rightResource >+ * the {@link Resource}, which will be used to construct the right scope >+ * @param ancestorResource >+ * the {@link Resource}, which will be used to construct the ancestor scope >+ */ >+ public GenericMatchScopeProvider(Resource leftResource, Resource rightResource, Resource ancestorResource) { >+ this(leftResource, rightResource); >+ this.ancestorScope = new GenericMatchScope(ancestorResource); >+ } >+ >+ /** >+ * Constructs a left and right {@link GenericMatchScope} with the given {@link ResourceSet}s. No ancestor >+ * scope will be created, so calls to {@link #getAncestorScope()} will return <code>null</code>. >+ * >+ * @param leftResourceSet >+ * the {@link ResourceSet}, which will be used to construct the left scope >+ * @param rightResourceSet >+ * the {@link ResourceSet}, which will be used to construct the right scope >+ */ >+ public GenericMatchScopeProvider(ResourceSet leftResourceSet, ResourceSet rightResourceSet) { >+ this.leftScope = new GenericMatchScope(leftResourceSet); >+ this.rightScope = new GenericMatchScope(rightResourceSet); >+ } >+ >+ /** >+ * Constructs a left, right, and ancestor {@link GenericMatchScope} with the given {@link ResourceSet}s. >+ * >+ * @param leftResourceSet >+ * the {@link ResourceSet}, which will be used to construct the left scope >+ * @param rightResourceSet >+ * the {@link ResourceSet}, which will be used to construct the right scope >+ * @param ancestorResourceSet >+ * the {@link ResourceSet}, which will be used to construct the ancestor scope >+ */ >+ public GenericMatchScopeProvider(ResourceSet leftResourceSet, ResourceSet rightResourceSet, >+ ResourceSet ancestorResourceSet) { >+ this(leftResourceSet, rightResourceSet); >+ this.ancestorScope = new GenericMatchScope(ancestorResourceSet); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.compare.match.engine.IMatchScopeProvider#getAncestorScope() >+ */ >+ public IMatchScope getAncestorScope() { >+ return ancestorScope; >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.compare.match.engine.IMatchScopeProvider#getLeftScope() >+ */ >+ public IMatchScope getLeftScope() { >+ return leftScope; >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.compare.match.engine.IMatchScopeProvider#getRightScope() >+ */ >+ public IMatchScope getRightScope() { >+ return rightScope; >+ } >+ >+ /** >+ * Allows to apply an {@link IResourceFilter} to the contained scopes, to reduce them respectively. This >+ * will only have an effect, if this scope provider was instantiated using either a {@link Resource} or a >+ * {@link ResourceSet}, but not in case an {@link EObject} was used. >+ * >+ * @param filter >+ * the filter to apply to the resources of the left, right and (if provided) ancestor scope. >+ */ >+ @SuppressWarnings("unchecked") >+ public void applyResourceFilter(IResourceFilter filter) { >+ if (ancestorScope != null) { >+ applyExternalFilter(filter, ((GenericMatchScope)leftScope).getResourcesInScope(), >+ ((GenericMatchScope)rightScope).getResourcesInScope(), ((GenericMatchScope)ancestorScope) >+ .getResourcesInScope()); >+ } else { >+ applyExternalFilter(filter, ((GenericMatchScope)leftScope).getResourcesInScope(), >+ ((GenericMatchScope)rightScope).getResourcesInScope()); >+ } >+ } >+ >+ /** >+ * Applies the given filter to the list of resources. >+ * >+ * @param filter >+ * the filter to apply. >+ * @param resources >+ * the list of resources to be filtered (in place). >+ */ >+ private static void applyExternalFilter(IResourceFilter filter, List<Resource>... resources) { >+ if (resources.length == 2) { >+ filter.filter(resources[0], resources[1]); >+ } else { >+ filter.filter(resources[0], resources[1], resources[2]); >+ } >+ } >+ >+} >Index: src/org/eclipse/emf/compare/match/engine/IMatchScopeProvider.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/match/engine/IMatchScopeProvider.java >diff -N src/org/eclipse/emf/compare/match/engine/IMatchScopeProvider.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/match/engine/IMatchScopeProvider.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,60 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 itemis AG (http://www.itemis.de) >+ * 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: >+ * itemis AG - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.emf.compare.match.engine; >+ >+import org.eclipse.emf.compare.match.filter.IResourceFilter; >+ >+/** >+ * A scope provider that can be passed to a {@link IMatchEngine} via the >+ * {@link org.eclipse.emf.compare.match.MatchOptions#OPTION_MATCH_SCOPE_PROVIDER} option. The >+ * {@link IMatchEngine} can evaluate the scope to restrict the set of >+ * {@link org.eclipse.emf.ecore.resource.Resource}s and {@link org.eclipse.emf.ecore.EObject}s it compares. It >+ * always has to provide a left and right {@link IMatchScope}, in case it is used in a three-way-comparison >+ * setting, an ancestor {@link IMatchScope} also has to be provided. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public interface IMatchScopeProvider { >+ >+ /** >+ * The {@link IMatchScope} to restrict the left side of comparison. >+ * >+ * @return an instance of {@link IMatchScope}. May not be <code>null</code>. >+ */ >+ IMatchScope getLeftScope(); >+ >+ /** >+ * The {@link IMatchScope} to restrict the right side of comparison. >+ * >+ * @return an instance of {@link IMatchScope}. May not be <code>null</code>. >+ */ >+ IMatchScope getRightScope(); >+ >+ /** >+ * The {@link IMatchScope} to restrict the ancestor side of comparison. >+ * >+ * @return an instance of {@link IMatchScope}. May also be <code>null</code> in case it is used in a >+ * two-way-comparison scenario. >+ */ >+ IMatchScope getAncestorScope(); >+ >+ /** >+ * In case the left, right, and target {@link IMatchScope}s are based on >+ * {@link org.eclipse.emf.ecore.resource.Resource}s and not {@link org.eclipse.emf.ecore.EObject}s, the >+ * filter can be applied to further restrict the scope. Otherwise it will be ignored. >+ * >+ * @param filter >+ * the {@link IResourceFilter} to be applied to the left, right scopes, as well as the ancestor >+ * scope (if it is specified). >+ */ >+ void applyResourceFilter(IResourceFilter filter); >+} >#P org.eclipse.emf.compare >Index: src/org/eclipse/emf/compare/util/ModelUtils.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/util/ModelUtils.java,v >retrieving revision 1.34 >diff -u -r1.34 ModelUtils.java >--- src/org/eclipse/emf/compare/util/ModelUtils.java 23 Nov 2009 16:42:44 -0000 1.34 >+++ src/org/eclipse/emf/compare/util/ModelUtils.java 25 Feb 2010 22:04:55 -0000 >@@ -19,6 +19,7 @@ > import java.util.List; > import java.util.Map; > >+import org.eclipse.emf.common.util.TreeIterator; > import org.eclipse.emf.common.util.URI; > import org.eclipse.emf.compare.EMFCompareMessages; > import org.eclipse.emf.ecore.EObject; >@@ -122,7 +123,7 @@ > new XMIResourceFactoryImpl()); > } > >- return resourceSet.createResource(modelURI); >+ return resourceSet.createResource(resourceSet.getURIConverter().normalize(modelURI)); > } > > /** >@@ -424,4 +425,24 @@ > writer.flush(); > return result; > } >+ >+ /** >+ * Checks whether the given resource contains the given object by searching its complete contents ( >+ * {@link Resource#getAllContents()}). >+ * >+ * @param resource >+ * The resource whose contents is to be processed. >+ * @param eObject >+ * The object to be evaluated. >+ * @return <code>true</code> if the resource contains the eObject, <code>false</code> otherwise. >+ */ >+ public static boolean contains(Resource resource, EObject eObject) { >+ final TreeIterator<EObject> contentsIterator = resource.getAllContents(); >+ while (contentsIterator.hasNext()) { >+ if (contentsIterator.next() == eObject) { >+ return true; >+ } >+ } >+ return false; >+ } > } >#P org.eclipse.emf.compare.ui >Index: src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeContentProvider.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeContentProvider.java,v >retrieving revision 1.13 >diff -u -r1.13 ModelContentMergeContentProvider.java >--- src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeContentProvider.java 11 Jan 2010 09:46:53 -0000 1.13 >+++ src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeContentProvider.java 25 Feb 2010 22:04:59 -0000 >@@ -11,13 +11,19 @@ > package org.eclipse.emf.compare.ui.viewer.content; > > import java.io.IOException; >+import java.util.ArrayList; > import java.util.Collections; >+import java.util.List; > > import org.eclipse.compare.CompareConfiguration; > import org.eclipse.compare.contentmergeviewer.IMergeViewerContentProvider; > import org.eclipse.compare.structuremergeviewer.ICompareInput; > import org.eclipse.emf.compare.EMFComparePlugin; >+import org.eclipse.emf.compare.diff.metamodel.DiffModel; >+import org.eclipse.emf.compare.diff.metamodel.DiffResourceSet; >+import org.eclipse.emf.compare.match.metamodel.Side; > import org.eclipse.emf.compare.ui.ModelCompareInput; >+import org.eclipse.emf.ecore.resource.Resource; > import org.eclipse.jface.viewers.Viewer; > import org.eclipse.swt.graphics.Image; > >@@ -60,11 +66,29 @@ > * > * @see org.eclipse.compare.contentmergeviewer.IMergeViewerContentProvider#getAncestorContent(java.lang.Object) > */ >+ @SuppressWarnings("unchecked") > public Object getAncestorContent(Object element) { > Object content = null; >- if (element instanceof ModelCompareInput) >- content = ((ModelCompareInput)element).getAncestorResource(); >- else if (element instanceof ICompareInput) >+ if (element instanceof ModelCompareInput) { >+ // if we compared a complete resource set, we should display the different resources >+ final Object diff = ((ModelCompareInput)element).getDiff(); >+ final Resource res = ((ModelCompareInput)element).getAncestorResource(); >+ if (diff instanceof DiffResourceSet) { >+ if (res != null && res.getResourceSet() != null) { >+ content = new ArrayList<Resource>(); >+ for (Resource resource : res.getResourceSet().getResources()) { >+ if (hasChanged(resource, (DiffResourceSet)diff, null)) { >+ ((List<Resource>)content).add(resource); >+ } >+ } >+ if (((List<Resource>)content).isEmpty()) { >+ content = null; >+ } >+ } >+ } else if (diff instanceof DiffModel) { >+ content = res; >+ } >+ } else if (element instanceof ICompareInput) > content = ((ICompareInput)element).getAncestor(); > return content; > } >@@ -92,21 +116,67 @@ > * > * @see org.eclipse.compare.contentmergeviewer.IMergeViewerContentProvider#getLeftContent(java.lang.Object) > */ >+ @SuppressWarnings("unchecked") > public Object getLeftContent(Object element) { > Object content = null; > if (element instanceof ModelCompareInput) { >- content = ((ModelCompareInput)element).getLeftResource(); >- // final Resource res = ((ModelCompareInput)element).getLeftResource(); >- // if (res != null && res.getResourceSet() != null) >- // content = res.getResourceSet(); >- // else >- // content = res; >+ // if we compared a complete resource set, we should display the different resources >+ final Object diff = ((ModelCompareInput)element).getDiff(); >+ final Resource res = ((ModelCompareInput)element).getLeftResource(); >+ if (diff instanceof DiffResourceSet) { >+ if (res != null && res.getResourceSet() != null) { >+ content = new ArrayList<Resource>(); >+ for (Resource resource : res.getResourceSet().getResources()) { >+ if (hasChanged(resource, (DiffResourceSet)diff, Side.LEFT)) { >+ ((List<Resource>)content).add(resource); >+ } >+ } >+ if (((List<Resource>)content).isEmpty()) { >+ content = null; >+ } >+ } >+ } else if (diff instanceof DiffModel) { >+ content = res; >+ } > } else if (element instanceof ICompareInput) > content = ((ICompareInput)element).getLeft(); > return content; > } > > /** >+ * Checks whether the given resource does contain changes on the respective side of the given diff >+ * resource set. >+ * >+ * @param res >+ * the resource that is being checked. >+ * @param diffResourceSet >+ * the resource that that is to be tested for changes to the given resource >+ * @param side >+ * the side of the diff resource set that is to be evaluated. >+ * @return <code>true</code> if the resource has related changes, <code>false</code> otherwise. >+ */ >+ private boolean hasChanged(Resource res, DiffResourceSet diffResourceSet, Side side) { >+ for (DiffModel diffModel : diffResourceSet.getDiffModels()) { >+ // diff model does not have ref to its covered resource, so >+ // we have to indirectly check if the diff models root are within the contents of the resource >+ if (side == Side.LEFT) { >+ if (res.getContents().containsAll(diffModel.getLeftRoots())) { >+ return diffModel.getSubchanges() != 0; >+ } >+ } else if (side == Side.RIGHT) { >+ if (res.getContents().containsAll(diffModel.getRightRoots())) { >+ return diffModel.getSubchanges() != 0; >+ } >+ } else { // ancestor side >+ if (res.getContents().containsAll(diffModel.getAncestorRoots())) { >+ return diffModel.getSubchanges() != 0; >+ } >+ } >+ } >+ return false; >+ } >+ >+ /** > * {@inheritDoc} > * > * @see org.eclipse.compare.contentmergeviewer.IMergeViewerContentProvider#getLeftImage(java.lang.Object) >@@ -129,15 +199,28 @@ > * > * @see org.eclipse.compare.contentmergeviewer.IMergeViewerContentProvider#getRightContent(java.lang.Object) > */ >+ @SuppressWarnings("unchecked") > public Object getRightContent(Object element) { > Object content = null; > if (element instanceof ModelCompareInput) { >- content = ((ModelCompareInput)element).getRightResource(); >- // final Resource res = ((ModelCompareInput)element).getRightResource(); >- // if (res != null && res.getResourceSet() != null) >- // content = res.getResourceSet(); >- // else >- // content = res; >+ // if we compared a complete resource set, we should display the different resources >+ final Object diff = ((ModelCompareInput)element).getDiff(); >+ final Resource res = ((ModelCompareInput)element).getRightResource(); >+ if (diff instanceof DiffResourceSet) { >+ if (res != null && res.getResourceSet() != null) { >+ content = new ArrayList<Resource>(); >+ for (Resource resource : res.getResourceSet().getResources()) { >+ if (hasChanged(resource, (DiffResourceSet)diff, Side.RIGHT)) { >+ ((List<Resource>)content).add(resource); >+ } >+ } >+ if (((List<Resource>)content).isEmpty()) { >+ content = null; >+ } >+ } >+ } else if (diff instanceof DiffModel) { >+ content = res; >+ } > } else if (element instanceof ICompareInput) > content = ((ICompareInput)element).getRight(); > return content; >Index: src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeViewer.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeViewer.java,v >retrieving revision 1.37 >diff -u -r1.37 ModelContentMergeViewer.java >--- src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeViewer.java 21 Jan 2010 11:09:25 -0000 1.37 >+++ src/org/eclipse/emf/compare/ui/viewer/content/ModelContentMergeViewer.java 25 Feb 2010 22:05:00 -0000 >@@ -312,7 +312,7 @@ > super.setInput(input); > } else if (input instanceof ICompareInput) { > comparator.loadResources((ICompareInput)input); >- final ComparisonResourceSetSnapshot snapshot = comparator.compare(configuration); >+ final ComparisonSnapshot snapshot = comparator.compare(configuration); > super.setInput(createModelCompareInput(comparator, snapshot)); > configuration.setProperty(EMFCompareConstants.PROPERTY_CONTENT_INPUT_CHANGED, snapshot); > } else { >Index: src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureContentProvider.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureContentProvider.java,v >retrieving revision 1.24 >diff -u -r1.24 ModelStructureContentProvider.java >--- src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureContentProvider.java 22 Dec 2009 16:05:03 -0000 1.24 >+++ src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureContentProvider.java 25 Feb 2010 22:05:03 -0000 >@@ -18,6 +18,7 @@ > import org.eclipse.compare.structuremergeviewer.ICompareInput; > import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSetSnapshot; > import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSnapshot; >+import org.eclipse.emf.compare.diff.metamodel.ComparisonSnapshot; > import org.eclipse.emf.compare.diff.metamodel.DiffFactory; > import org.eclipse.emf.compare.diff.metamodel.DiffModel; > import org.eclipse.emf.compare.diff.metamodel.DiffResourceSet; >@@ -167,12 +168,30 @@ > } else if (newInput instanceof ComparisonResourceSetSnapshot) { > input = ((ComparisonResourceSetSnapshot)newInput).getDiffResourceSet(); > } else if (comparator.getComparisonResult() != null) { >- input = comparator.getComparisonResult().getDiffResourceSet(); >+ input = retrieveInputFromSnapshot(comparator.getComparisonResult()); > } else if (newInput instanceof ModelCompareInput) { > input = ((ModelCompareInput)newInput).getDiff(); > } else if (oldInput != newInput && newInput instanceof ICompareInput) { > comparator.loadResources((ICompareInput)newInput); >- input = comparator.compare(configuration).getDiffResourceSet(); >+ input = retrieveInputFromSnapshot(comparator.compare(configuration)); > } > } >+ >+ /** >+ * Utility function to retrieve the viewer input from the given comparison result. >+ * >+ * @param comparisonResult >+ * the result to evaluate >+ * @return a {@link DiffModel} in case the comparison result is a {@link ComparisonResourceSnapshot}, a >+ * {@link DiffResourceSet otherwise}. >+ */ >+ private Object retrieveInputFromSnapshot(final ComparisonSnapshot comparisonResult) { >+ Object retrievedInput = null; >+ if (comparisonResult instanceof ComparisonResourceSnapshot) { >+ retrievedInput = ((ComparisonResourceSnapshot)comparisonResult).getDiff(); >+ } else { >+ retrievedInput = ((ComparisonResourceSetSnapshot)comparisonResult).getDiffResourceSet(); >+ } >+ return retrievedInput; >+ } > } >Index: src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureMergeViewer.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureMergeViewer.java,v >retrieving revision 1.18 >diff -u -r1.18 ModelStructureMergeViewer.java >--- src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureMergeViewer.java 22 Dec 2009 16:03:44 -0000 1.18 >+++ src/org/eclipse/emf/compare/ui/viewer/structure/ModelStructureMergeViewer.java 25 Feb 2010 22:05:03 -0000 >@@ -19,6 +19,7 @@ > import org.eclipse.core.resources.IFile; > import org.eclipse.emf.compare.diff.metamodel.AbstractDiffExtension; > import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSetSnapshot; >+import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSnapshot; > import org.eclipse.emf.compare.diff.metamodel.ComparisonSnapshot; > import org.eclipse.emf.compare.diff.metamodel.DiffElement; > import org.eclipse.emf.compare.ui.EMFCompareUIMessages; >@@ -203,8 +204,13 @@ > if (!(input instanceof ComparisonSnapshot) && input != oldInput) { > final ComparisonSnapshot snapshot = ModelComparator.getComparator(configuration) > .getComparisonResult(); >- final Object match; >- match = ((ComparisonResourceSetSnapshot)snapshot).getMatchResourceSet(); >+ Object match = null; >+ // check whether a resource or resource set comparison was performed >+ if (snapshot instanceof ComparisonResourceSnapshot) { >+ match = ((ComparisonResourceSnapshot)snapshot).getMatch(); >+ } else { >+ match = ((ComparisonResourceSetSnapshot)snapshot).getMatchResourceSet(); >+ } > if (match != null) { > setInput(snapshot); > } else { >Index: src/org/eclipse/emf/compare/ui/emfcompareuimessages.properties >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/emfcompareuimessages.properties,v >retrieving revision 1.12 >diff -u -r1.12 emfcompareuimessages.properties >--- src/org/eclipse/emf/compare/ui/emfcompareuimessages.properties 8 Apr 2009 12:05:49 -0000 1.12 >+++ src/org/eclipse/emf/compare/ui/emfcompareuimessages.properties 25 Feb 2010 22:04:56 -0000 >@@ -10,8 +10,6 @@ > ################################################################################ > # General keys > IllegalSide=PartSide cannot be {0}. >-comparison.label.localResource=Local Resource >-comparison.label.remoteResource=Remote Resource > > # org.eclipse.emf.compare.ui > AbstractCompareAction.IllegalBundle=Bundle cannot be null. >@@ -22,6 +20,14 @@ > VisualEngineSelector.Dialog.Message = Please select the engine > VisualEngineSelector.Dialog.Cancel = engine selection cancelled. > >+ModelComparator.localResourceCompareLabel=Local Resource >+ModelComparator.localResourceSetCompareLabel=Local ResourceSet >+ModelComparator.MatchModelSelectionDialogResourceOption=Selected resource(s) only >+ModelComparator.MatchModelSelectionDialogResourceSetOption=Complete resource set(s) >+ModelComparator.MatchModeSelectionDialogMessage=Please choose whether you want to restrict the comparison to the selected resource(s) only, or whether you want to process the complete resource set(s). >+ModelComparator.MatchModeSelectionDialogTitle=Match Mode Selection >+ModelComparator.remoteResourceSetCompareLabel=Remote ResourceSet >+ModelComparator.remoteResourceCompareLabel=Remote Resource > ModelComparator.ResourceLoadingFailure = Comparison through EMF Compare failed. > ModelComparator.ResourceLoadingFailureGanymede = Comparison through EMF Compare failed.\nSwitch to text comparison using the drop down menu in the editor. > >Index: src/org/eclipse/emf/compare/ui/viewer/content/part/diff/ModelContentMergeDiffTab.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/viewer/content/part/diff/ModelContentMergeDiffTab.java,v >retrieving revision 1.26 >diff -u -r1.26 ModelContentMergeDiffTab.java >--- src/org/eclipse/emf/compare/ui/viewer/content/part/diff/ModelContentMergeDiffTab.java 19 Jan 2010 10:24:07 -0000 1.26 >+++ src/org/eclipse/emf/compare/ui/viewer/content/part/diff/ModelContentMergeDiffTab.java 25 Feb 2010 22:05:02 -0000 >@@ -117,8 +117,8 @@ > parent = parentFolder; > > setUseHashlookup(true); >- setContentProvider(new ModelContentMergeDiffTabContentProvider(AdapterUtils.getAdapterFactory())); >- setLabelProvider(new AdapterFactoryLabelProvider(AdapterUtils.getAdapterFactory())); >+ setContentProvider(createContentProvider()); >+ setLabelProvider(createLabelProvider()); > getTree().addPaintListener(new TreePaintListener()); > > // The following listeners will be used to invalidate the cache of >@@ -142,6 +142,24 @@ > } > > /** >+ * Utility function to create a new label provider. >+ * >+ * @return the new label provider instance. >+ */ >+ private AdapterFactoryLabelProvider createLabelProvider() { >+ return new AdapterFactoryLabelProvider(AdapterUtils.getAdapterFactory()); >+ } >+ >+ /** >+ * Utility function to create a new content provider. >+ * >+ * @return the new content provider instance. >+ */ >+ private ModelContentMergeDiffTabContentProvider createContentProvider() { >+ return new ModelContentMergeDiffTabContentProvider(AdapterUtils.getAdapterFactory()); >+ } >+ >+ /** > * {@inheritDoc} > * > * @see org.eclipse.emf.compare.ui.viewer.content.part.IModelContentMergeViewerTab#dispose() >@@ -250,7 +268,9 @@ > * @see org.eclipse.emf.compare.ui.viewer.content.part.IModelContentMergeViewerTab#redraw() > */ > public void redraw() { >+ clearCaches(); > getTree().redraw(); >+ setupCaches(); > } > > /** >@@ -260,10 +280,9 @@ > */ > @Override > public void refresh(Object element, boolean updateLabels) { >+ clearCaches(); > super.refresh(element, updateLabels); >- mapTreeItems(); >- mapDifferences(); >- mapTreeItemsToUI(); >+ setupCaches(); > } > > /** >@@ -271,17 +290,23 @@ > * > * @see org.eclipse.emf.compare.ui.viewer.content.part.IModelContentMergeViewerTab#setReflectiveInput(java.lang.Object) > */ >+ @SuppressWarnings("unchecked") > public void setReflectiveInput(Object object) { > // We *need* to invalidate the cache here since setInput() would try to > // use it otherwise > clearCaches(); > >- final AdapterFactory adapterFactory = AdapterUtils.getAdapterFactory(); >- setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory)); >+ // setLabelProvider(createLabelProvider()); // already set in constructor > if (object instanceof EObject) { > setInput(((EObject)object).eResource()); > } else { >- assert object instanceof Resource; >+ // may be invoked with a resourceSet, a list of resources, or a single resource >+ assert object instanceof Resource || object instanceof List; >+ if (object instanceof List) { >+ for (Object item : (List)object) { >+ assert item instanceof Resource; >+ } >+ } > setInput(object); > } > >@@ -307,6 +332,19 @@ > datas.add(EMFCompareEObjectUtils.getRightElement(items.get(i))); > } > } >+ >+ // filter null values >+ final Iterator<EObject> iterator = datas.iterator(); >+ while (iterator.hasNext()) { >+ if (iterator.next() == null) { >+ iterator.remove(); >+ } >+ } >+ >+ // expand those being selected first >+ for (EObject data : datas) { >+ reveal(data); >+ } > setSelection(new StructuredSelection(datas), true); > needsRedraw = true; > redraw(); >@@ -333,9 +371,8 @@ > return res; > else if (res != null) { > // mapped items are disposed >- mapTreeItems(); >- mapDifferences(); >- mapTreeItemsToUI(); >+ clearCaches(); >+ setupCaches(); > // won't call this recursively since it could eventually lead to > // stack overflows > dataToTreeItem.get(element); >@@ -367,16 +404,10 @@ > */ > @Override > protected void inputChanged(Object input, Object oldInput) { >- if (input != oldInput) { >- final TreePath[] expandedTreePaths = getExpandedTreePaths(); >- >- super.inputChanged(input, oldInput); >- >- // Expands all items so that we'll be able to find them back (defeats >- // purpose of lazy loading) >- expandAll(); >- setExpandedTreePaths(expandedTreePaths); >- } >+ // preserve expansion state >+ final TreePath[] expandedTreePaths = getExpandedTreePaths(); >+ super.inputChanged(input, oldInput); >+ setExpandedTreePaths(expandedTreePaths); > } > > /** >@@ -665,10 +696,14 @@ > // look for the matchedElement > data = getTree().getItems()[0].getData(); > } >- final Item actualItem = (Item)findItem(data); >- if (actualItem == null) { >+ final Widget actualWidget = findItem(data); >+ if (actualWidget == null) { >+ continue; >+ } >+ if (!(actualWidget instanceof Item)) { > continue; > } >+ final Item actualItem = (Item)actualWidget; > > Item visibleItem = null; > if (partSide == EMFCompareConstants.LEFT && diff instanceof ModelElementChangeRightTarget >@@ -839,8 +874,12 @@ > * > * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#getElements(java.lang.Object) > */ >+ @SuppressWarnings("unchecked") > @Override > public Object[] getElements(Object object) { >+ // overwritten to ensure contents of ResourceSets, List<Resource>, and Resource are correclty >+ // returned. >+ Object[] result = null; > if (object instanceof ResourceSet) { > final List<Resource> resources = ((ResourceSet)object).getResources(); > final List<Resource> elements = new ArrayList<Resource>(resources.size()); >@@ -850,9 +889,43 @@ > elements.add(resource); > } > } >- return elements.toArray(); >+ result = elements.toArray(); >+ } else if (object instanceof List) { >+ // we may also display a list of resources >+ result = ((List)object).toArray(); >+ } else if (object instanceof Resource) { >+ // return contents of resource >+ result = ((Resource)object).getContents().toArray(); >+ } else { >+ result = super.getElements(object); >+ } >+ return result; >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#getChildren(java.lang.Object) >+ */ >+ @Override >+ public Object[] getChildren(Object object) { >+ if (object instanceof Resource) { >+ return ((Resource)object).getContents().toArray(); >+ } >+ return super.getChildren(object); >+ } >+ >+ /** >+ *{@inheritDoc} >+ * >+ * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#hasChildren(java.lang.Object) >+ */ >+ @Override >+ public boolean hasChildren(Object object) { >+ if (object instanceof Resource) { >+ return ((Resource)object).getContents().size() > 0; > } >- return super.getElements(object); >+ return super.hasChildren(object); > } > } > } >Index: src/org/eclipse/emf/compare/ui/internal/ModelComparator.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/internal/ModelComparator.java,v >retrieving revision 1.23 >diff -u -r1.23 ModelComparator.java >--- src/org/eclipse/emf/compare/ui/internal/ModelComparator.java 28 Aug 2009 13:12:58 -0000 1.23 >+++ src/org/eclipse/emf/compare/ui/internal/ModelComparator.java 25 Feb 2010 22:04:58 -0000 >@@ -42,10 +42,13 @@ > import org.eclipse.emf.compare.diff.metamodel.ComparisonResourceSnapshot; > import org.eclipse.emf.compare.diff.metamodel.ComparisonSnapshot; > import org.eclipse.emf.compare.diff.metamodel.DiffFactory; >+import org.eclipse.emf.compare.diff.metamodel.DiffModel; > import org.eclipse.emf.compare.diff.metamodel.DiffResourceSet; > import org.eclipse.emf.compare.diff.service.DiffService; > import org.eclipse.emf.compare.match.MatchOptions; >+import org.eclipse.emf.compare.match.engine.GenericMatchScopeProvider; > import org.eclipse.emf.compare.match.metamodel.MatchFactory; >+import org.eclipse.emf.compare.match.metamodel.MatchModel; > import org.eclipse.emf.compare.match.metamodel.MatchResourceSet; > import org.eclipse.emf.compare.match.service.MatchService; > import org.eclipse.emf.compare.ui.EMFCompareUIMessages; >@@ -61,6 +64,7 @@ > import org.eclipse.jface.dialogs.Dialog; > import org.eclipse.jface.dialogs.ErrorDialog; > import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.dialogs.MessageDialog; > import org.eclipse.jface.operation.IRunnableWithProgress; > import org.eclipse.swt.widgets.Composite; > import org.eclipse.swt.widgets.Shell; >@@ -90,7 +94,7 @@ > private static final String TEAM_HANDLERS_EXTENSION_POINT = "org.eclipse.emf.compare.ui.team.handler"; //$NON-NLS-1$ > > /** This will hold the result of these resources' comparison. */ >- protected ComparisonResourceSetSnapshot comparisonResult; >+ protected ComparisonSnapshot comparisonResult; > > /** Keeps a reference to the last "ancestor" element of the input. */ > private ITypedElement ancestorElement; >@@ -230,66 +234,153 @@ > * data. > * @return Result of the comparison of the loaded resources. > */ >- public ComparisonResourceSetSnapshot compare(CompareConfiguration configuration) { >+ public ComparisonSnapshot compare(CompareConfiguration configuration) { > if (!loadingSucceeded) { > // We couldn't load the resource. It's useless to carry on. > comparisonResult = DiffFactory.eINSTANCE.createComparisonResourceSetSnapshot(); > } > > if (comparisonResult == null) { >- comparisonResult = DiffFactory.eINSTANCE.createComparisonResourceSetSnapshot(); > final Date start = Calendar.getInstance().getTime(); > > MatchService.setMatchEngineSelector(new VisualEngineSelector()); > DiffService.setDiffEngineSelector(new VisualEngineSelector()); > >- try { >- PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { >- public void run(IProgressMonitor monitor) throws InterruptedException { >- final Map<String, Object> options = new EMFCompareMap<String, Object>(); >- options.put(MatchOptions.OPTION_PROGRESS_MONITOR, monitor); >- final MatchResourceSet match; >- if (getAncestorResource() == null) { >- match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), >- getRightResource().getResourceSet(), options); >- } else { >- match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), >- getRightResource().getResourceSet(), getAncestorResource() >- .getResourceSet(), options); >- } >- final DiffResourceSet diff = DiffService.doDiff(match, getAncestorResource() != null); >+ // show prompt to select the match scope >+ final MessageDialog queryMatchScopeDialog = new MessageDialog( >+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), >+ EMFCompareUIMessages.getString("ModelComparator.MatchModeSelectionDialogTitle"), null, EMFCompareUIMessages.getString("ModelComparator.MatchModeSelectionDialogMessage"), MessageDialog.NONE, new String[] {EMFCompareUIMessages.getString("ModelComparator.MatchModelSelectionDialogResourceOption"), EMFCompareUIMessages.getString("ModelComparator.MatchModelSelectionDialogResourceSetOption") }, 0); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ >+ final boolean doResourceMatchOnly = queryMatchScopeDialog.open() == 0; > >- comparisonResult.setDate(Calendar.getInstance().getTime()); >- comparisonResult.setDiffResourceSet(diff); >- comparisonResult.setMatchResourceSet(match); >- } >- }); >- } catch (final InterruptedException e) { >- comparisonResult.setDate(Calendar.getInstance().getTime()); >- comparisonResult.setDiffResourceSet(DiffFactory.eINSTANCE.createDiffResourceSet()); >- comparisonResult.setMatchResourceSet(MatchFactory.eINSTANCE.createMatchResourceSet()); >- } catch (final EMFCompareException e) { >- comparisonResult.setDate(Calendar.getInstance().getTime()); >- comparisonResult.setDiffResourceSet(DiffFactory.eINSTANCE.createDiffResourceSet()); >- comparisonResult.setMatchResourceSet(MatchFactory.eINSTANCE.createMatchResourceSet()); >- } catch (final InvocationTargetException e) { >- EMFComparePlugin.log(e, true); >+ if (doResourceMatchOnly) { >+ comparisonResult = doResourceCompare(); >+ } else { >+ comparisonResult = doResourceSetCompare(); > } > >+ // set date of comparison > final Date end = Calendar.getInstance().getTime(); >- configuration.setProperty(EMFCompareConstants.PROPERTY_COMPARISON_TIME, end.getTime() >- - start.getTime()); >+ comparisonResult.setDate(end); >+ > configuration.setLeftEditable(configuration.isLeftEditable() && !isLeftRemote()); > configuration.setRightEditable(configuration.isRightEditable() && !isRightRemote()); >+ configuration.setProperty(EMFCompareConstants.PROPERTY_COMPARISON_TIME, end.getTime() >+ - start.getTime()); > if (isLeftRemote()) { >- configuration.setLeftLabel(EMFCompareUIMessages.getString("comparison.label.remoteResource")); //$NON-NLS-1$ >- configuration.setRightLabel(EMFCompareUIMessages.getString("comparison.label.localResource")); //$NON-NLS-1$ >+ if (doResourceMatchOnly) { >+ configuration.setLeftLabel(EMFCompareUIMessages.getString(EMFCompareUIMessages >+ .getString("ModelComparator.remoteResourceCompareLabel"))); //$NON-NLS-1$ >+ configuration.setRightLabel(EMFCompareUIMessages.getString(EMFCompareUIMessages >+ .getString("ModelComparator.localResourceCompareLabel"))); //$NON-NLS-1$ >+ } else { >+ >+ configuration.setLeftLabel(EMFCompareUIMessages.getString(EMFCompareUIMessages >+ .getString("ModelComparator.remoteResourceSetCompareLabel"))); //$NON-NLS-1$ >+ configuration.setRightLabel(EMFCompareUIMessages.getString(EMFCompareUIMessages >+ .getString("ModelComparator.localResourceSetCompareLabel"))); //$NON-NLS-1$ >+ >+ } > } > } > return comparisonResult; > } > > /** >+ * Perform a comparison of the left and right (and if specified ancestor resource). >+ * >+ * @return the {@link ComparisonResourceSnapshot} that contains the comparison result. >+ */ >+ protected ComparisonResourceSnapshot doResourceCompare() { >+ // create snapshot >+ final ComparisonResourceSnapshot snapshot = DiffFactory.eINSTANCE.createComparisonResourceSnapshot(); >+ snapshot.setDiff(DiffFactory.eINSTANCE.createDiffModel()); >+ snapshot.setMatch(MatchFactory.eINSTANCE.createMatchModel()); >+ >+ try { >+ PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { >+ public void run(IProgressMonitor monitor) throws InterruptedException { >+ final Map<String, Object> options = new EMFCompareMap<String, Object>(); >+ options.put(MatchOptions.OPTION_PROGRESS_MONITOR, monitor); >+ >+ // do comparison >+ final MatchModel match; >+ if (getAncestorResource() == null) { >+ options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( >+ getLeftResource(), getRightResource())); >+ match = MatchService.doResourceMatch(getLeftResource(), getRightResource(), options); >+ } else { >+ options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( >+ getLeftResource(), getRightResource(), getAncestorResource())); >+ match = MatchService.doResourceMatch(getLeftResource(), getRightResource(), >+ getAncestorResource(), options); >+ } >+ final DiffModel diff = DiffService.doDiff(match, getAncestorResource() != null); >+ snapshot.setDiff(diff); >+ snapshot.setMatch(match); >+ >+ } >+ }); >+ } catch (final InterruptedException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final EMFCompareException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final InvocationTargetException e) { >+ EMFComparePlugin.log(e, true); >+ } >+ >+ return snapshot; >+ } >+ >+ /** >+ * /** Perform a comparison of the left and right (and if specified ancestor resource), as well as all >+ * other resources, included in their respective resource sets. >+ * >+ * @return the {@link ComparisonResourceSetSnapshot} that contains the comparison result. >+ */ >+ protected ComparisonResourceSetSnapshot doResourceSetCompare() { >+ final ComparisonResourceSetSnapshot snapshot = DiffFactory.eINSTANCE >+ .createComparisonResourceSetSnapshot(); >+ snapshot.setDiffResourceSet(DiffFactory.eINSTANCE.createDiffResourceSet()); >+ snapshot.setMatchResourceSet(MatchFactory.eINSTANCE.createMatchResourceSet()); >+ >+ try { >+ PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { >+ public void run(IProgressMonitor monitor) throws InterruptedException { >+ final Map<String, Object> options = new EMFCompareMap<String, Object>(); >+ options.put(MatchOptions.OPTION_PROGRESS_MONITOR, monitor); >+ >+ // do comparison >+ final MatchResourceSet match; >+ if (getAncestorResource() == null) { >+ options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( >+ getLeftResource().getResourceSet(), getRightResource().getResourceSet())); >+ match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), >+ getRightResource().getResourceSet(), options); >+ } else { >+ options.put(MatchOptions.OPTION_MATCH_SCOPE_PROVIDER, new GenericMatchScopeProvider( >+ getLeftResource().getResourceSet(), getRightResource().getResourceSet(), >+ getAncestorResource().getResourceSet())); >+ match = MatchService.doResourceSetMatch(getLeftResource().getResourceSet(), >+ getRightResource().getResourceSet(), getAncestorResource().getResourceSet(), >+ options); >+ } >+ final DiffResourceSet diff = DiffService.doDiff(match, getAncestorResource() != null); >+ snapshot.setDiffResourceSet(diff); >+ snapshot.setMatchResourceSet(match); >+ } >+ }); >+ } catch (final InterruptedException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final EMFCompareException e) { >+ EMFComparePlugin.log(e, false); >+ } catch (final InvocationTargetException e) { >+ EMFComparePlugin.log(e, true); >+ } >+ >+ return snapshot; >+ } >+ >+ /** > * Returns the compared resources ancestor. > * > * @return The compared resources ancestor. >@@ -306,7 +397,7 @@ > * @return The comparison result. <code>null</code> if no comparison has been done since last loading > * resources. > */ >- public ComparisonResourceSetSnapshot getComparisonResult() { >+ public ComparisonSnapshot getComparisonResult() { > return comparisonResult; > } > >@@ -450,12 +541,12 @@ > comparisonResult.setDate(snapshot.getDate()); > final DiffResourceSet diffRS = DiffFactory.eINSTANCE.createDiffResourceSet(); > diffRS.getDiffModels().add(((ComparisonResourceSnapshot)snapshot).getDiff()); >- comparisonResult.setDiffResourceSet(diffRS); >+ ((ComparisonResourceSetSnapshot)comparisonResult).setDiffResourceSet(diffRS); > final MatchResourceSet matchRS = MatchFactory.eINSTANCE.createMatchResourceSet(); > matchRS.getMatchModels().add(((ComparisonResourceSnapshot)snapshot).getMatch()); >- comparisonResult.setMatchResourceSet(matchRS); >+ ((ComparisonResourceSetSnapshot)comparisonResult).setMatchResourceSet(matchRS); > } else { >- comparisonResult = (ComparisonResourceSetSnapshot)snapshot; >+ comparisonResult = snapshot; > } > } > >Index: src/org/eclipse/emf/compare/ui/internal/RevisionComparisonHandler.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.ui/src/org/eclipse/emf/compare/ui/internal/RevisionComparisonHandler.java,v >retrieving revision 1.9 >diff -u -r1.9 RevisionComparisonHandler.java >--- src/org/eclipse/emf/compare/ui/internal/RevisionComparisonHandler.java 8 Sep 2009 12:44:48 -0000 1.9 >+++ src/org/eclipse/emf/compare/ui/internal/RevisionComparisonHandler.java 25 Feb 2010 22:04:58 -0000 >@@ -26,12 +26,13 @@ > import org.eclipse.core.runtime.NullProgressMonitor; > import org.eclipse.core.runtime.Path; > import org.eclipse.emf.common.util.URI; >+import org.eclipse.emf.compare.ui.team.AbstractResolvingURIConverter; > import org.eclipse.emf.compare.ui.team.AbstractTeamHandler; > import org.eclipse.emf.compare.util.EclipseModelUtils; > import org.eclipse.emf.compare.util.ModelUtils; >+import org.eclipse.emf.ecore.plugin.EcorePlugin; > import org.eclipse.emf.ecore.resource.ResourceSet; > import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; >-import org.eclipse.emf.ecore.resource.impl.URIConverterImpl; > import org.eclipse.team.core.RepositoryProvider; > import org.eclipse.team.core.history.IFileHistory; > import org.eclipse.team.core.history.IFileHistoryProvider; >@@ -77,10 +78,10 @@ > > if (left instanceof FileRevisionTypedElement) { > try { >- leftResource = ModelUtils.load(((IStreamContentAccessor)left).getContents(), >- left.getName(), leftResourceSet).eResource(); > leftResourceSet.setURIConverter(new RevisionedURIConverter( > ((FileRevisionTypedElement)left).getFileRevision())); >+ leftResource = ModelUtils.load(((IStreamContentAccessor)left).getContents(), >+ left.getName(), leftResourceSet).eResource(); > } catch (final IOException e) { > // We couldn't load the resource. Considers it has been deleted > leftResource = ModelUtils.createResource(URI.createURI(left.getName())); >@@ -98,9 +99,9 @@ > } > > try { >+ rightResourceSet.setURIConverter(new RevisionedURIConverter(rightRevision)); > rightResource = ModelUtils.load(((IStreamContentAccessor)right).getContents(), > right.getName(), rightResourceSet).eResource(); >- rightResourceSet.setURIConverter(new RevisionedURIConverter(rightRevision)); > } catch (final IOException e) { > // We couldn't load the remote resource. Considers it has been added to the repository > rightResource = ModelUtils.createResource(URI.createURI(right.getName())); >@@ -112,9 +113,9 @@ > final IFileRevision ancestorRevision = ((FileRevisionTypedElement)ancestor).getFileRevision(); > final ResourceSet ancestorResourceSet = new ResourceSetImpl(); > try { >+ ancestorResourceSet.setURIConverter(new RevisionedURIConverter(ancestorRevision)); > ancestorResource = ModelUtils.load(((IStreamContentAccessor)ancestor).getContents(), > ancestor.getName(), ancestorResourceSet).eResource(); >- ancestorResourceSet.setURIConverter(new RevisionedURIConverter(ancestorRevision)); > } catch (final IOException e) { > // Couldn't load ancestor resource, create an empty one > ancestorResource = ModelUtils.createResource(URI.createURI(ancestor.getName())); >@@ -133,7 +134,7 @@ > * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> > * @since 1.0 > */ >- private class RevisionedURIConverter extends URIConverterImpl { >+ private class RevisionedURIConverter extends AbstractResolvingURIConverter { > /** The revision of the base model. This revision's timestamp will be used to resolve proxies. */ > private final IFileRevision baseRevision; > >@@ -151,39 +152,48 @@ > /** > * {@inheritDoc} > * >+ * @see org.eclipse.emf.compare.ui.team.AbstractResolvingURIConverter#resolve(org.eclipse.emf.common.util.URI) >+ */ >+ @Override >+ public URI resolve(URI uri) throws CoreException { >+ URI deresolvedURI = uri; >+ // We'll have to change the EMF URI to find the IFile it points to >+ final IStorage storage = baseRevision.getStorage(null); >+ if (uri.isRelative()) { >+ // Current revision, yet the proxy could point to a file that has changed since. >+ if (storage instanceof IFile) { >+ final IFile file = (IFile)storage; >+ deresolvedURI = uri.resolve(URI.createURI(file.getLocationURI().toString())); >+ } else { >+ final IResource stateFile = EcorePlugin.getWorkspaceRoot().findMember( >+ storage.getFullPath()); >+ deresolvedURI = uri.resolve(URI.createURI(stateFile.getLocationURI().toString())); >+ } >+ } >+ deresolvedURI = URI.createPlatformResourceURI(deresolvedURI.deresolve( >+ URI.createURI(EcorePlugin.getWorkspaceRoot().getLocationURI().toString() + '/')) >+ .toString()); >+ return deresolvedURI; >+ } >+ >+ /** >+ * {@inheritDoc} >+ * > * @see org.eclipse.emf.ecore.resource.URIConverter#createInputStream(org.eclipse.emf.common.util.URI) > */ > @Override > public InputStream createInputStream(URI uri) throws IOException { > InputStream stream = null; >- if (uri.isPlatformPlugin() || uri.toString().matches("(\\.\\./)+?plugins/.*")) { //$NON-NLS-1$ >- stream = super.createInputStream(uri); >+ final URI normalizedUri = normalize(uri); >+ if (normalizedUri.isPlatformPlugin() || normalizedUri.toString().matches("(\\.\\./)+?plugins/.*")) { //$NON-NLS-1$ >+ stream = super.createInputStream(normalizedUri); > } else { >- try { >- // We'll have to change the EMF URI to find the IFile it points to >- URI deresolvedURI = uri; >- >- final IStorage storage = baseRevision.getStorage(null); >- if (uri.isRelative()) { >- // Current revision, yet the proxy could point to a file that has changed since. >- if (storage instanceof IFile) { >- final IFile file = (IFile)storage; >- deresolvedURI = uri.resolve(URI.createURI(file.getLocationURI().toString())); >- } else { >- final IResource stateFile = workspaceRoot.findMember(storage.getFullPath()); >- deresolvedURI = uri.resolve(URI.createURI(stateFile.getLocationURI().toString())); >- } >- } >- deresolvedURI = deresolvedURI.deresolve(URI.createURI(workspaceRoot.getLocationURI() >- .toString() + '/')); >- >- final IResource targetFile = workspaceRoot.findMember(new Path(deresolvedURI >- .trimFragment().toString())); >- >- if (targetFile != null) >- stream = openRevisionStream(targetFile); >- } catch (final CoreException e) { >- stream = super.createInputStream(uri); >+ final IResource targetFile = EcorePlugin.getWorkspaceRoot().findMember( >+ new Path(normalizedUri.trimFragment().toPlatformString(true))); >+ if (targetFile != null) { >+ stream = openRevisionStream(targetFile); >+ } else { >+ super.createInputStream(normalizedUri); > } > } > return stream; >Index: src/org/eclipse/emf/compare/ui/team/AbstractResolvingURIConverter.java >=================================================================== >RCS file: src/org/eclipse/emf/compare/ui/team/AbstractResolvingURIConverter.java >diff -N src/org/eclipse/emf/compare/ui/team/AbstractResolvingURIConverter.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/compare/ui/team/AbstractResolvingURIConverter.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,57 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 itemis AG (http://www.itemis.de) >+ * 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: >+ * itemis AG - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.emf.compare.ui.team; >+ >+import org.eclipse.core.runtime.CoreException; >+import org.eclipse.emf.common.util.URI; >+import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl; >+ >+/** >+ * A converter, which performs automatic resolving of relative resources during normalization. >+ * >+ * @author <a href="mailto:alexander.nyssen@itemis.de">Alexander Nyssen</a> >+ * @since 1.1 >+ */ >+public abstract class AbstractResolvingURIConverter extends ExtensibleURIConverterImpl { >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl#normalize(org.eclipse.emf.common.util.URI) >+ */ >+ @Override >+ public URI normalize(URI uri) { >+ URI normalizedUri = null; >+ if (uri.isRelative()) { >+ try { >+ normalizedUri = super.normalize(resolve(uri)); >+ } catch (CoreException e) { >+ // cannot do anything here, let super implementation >+ // return a valid value >+ normalizedUri = super.normalize(uri); >+ } >+ } else { >+ normalizedUri = super.normalize(uri); >+ } >+ return normalizedUri; >+ } >+ >+ /** >+ * Called to delegate resvoling of a given relative uri to an absolute one. >+ * >+ * @param relativeUri >+ * the relative uri to resolve. >+ * @return the resolved absolute uri >+ * @throws CoreException >+ * in case resolving could not be successfully performed. >+ */ >+ protected abstract URI resolve(URI relativeUri) throws CoreException; >+} >#P org.eclipse.emf.compare.team.subversive >Index: src/org/eclipse/emf/compare/team/subversive/SubversiveTeamHandler.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.team.subversive/src/org/eclipse/emf/compare/team/subversive/SubversiveTeamHandler.java,v >retrieving revision 1.14 >diff -u -r1.14 SubversiveTeamHandler.java >--- src/org/eclipse/emf/compare/team/subversive/SubversiveTeamHandler.java 8 Sep 2009 12:44:49 -0000 1.14 >+++ src/org/eclipse/emf/compare/team/subversive/SubversiveTeamHandler.java 25 Feb 2010 22:05:06 -0000 >@@ -22,12 +22,12 @@ > import org.eclipse.compare.structuremergeviewer.ICompareInput; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.emf.common.util.URI; >+import org.eclipse.emf.compare.ui.team.AbstractResolvingURIConverter; > import org.eclipse.emf.compare.ui.team.AbstractTeamHandler; > import org.eclipse.emf.compare.util.EclipseModelUtils; > import org.eclipse.emf.compare.util.ModelUtils; > import org.eclipse.emf.ecore.resource.ResourceSet; > import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; >-import org.eclipse.emf.ecore.resource.impl.URIConverterImpl; > import org.eclipse.team.svn.core.connector.ISVNConnector; > import org.eclipse.team.svn.core.connector.ISVNProgressMonitor; > import org.eclipse.team.svn.core.connector.SVNConnectorException; >@@ -87,14 +87,14 @@ > } > > try { >- rightResource = ModelUtils.load(((ResourceElement)right).getContents(), right.getName(), >- rightResourceSet).eResource(); > final IRepositoryResource resource = ((ResourceElement)right).getRepositoryResource(); > // We might be comparing two distant files, in which case ancestor is null > ILocalResource local = null; > if (ancestor != null) > local = ((ResourceElement)ancestor).getLocalResource(); > rightResourceSet.setURIConverter(new RevisionedURIConverter(resource, local)); >+ rightResource = ModelUtils.load(((ResourceElement)right).getContents(), right.getName(), >+ rightResourceSet).eResource(); > } catch (final IOException e) { > // We couldn't load the remote resource. Considers it has been added to the repository > rightResource = ModelUtils.createResource(URI.createURI(right.getName())); >@@ -105,11 +105,11 @@ > if (ancestor != null) { > final ResourceSet ancestorResourceSet = new ResourceSetImpl(); > try { >- ancestorResource = ModelUtils.load(((IStreamContentAccessor)ancestor).getContents(), >- ancestor.getName(), ancestorResourceSet).eResource(); > final IRepositoryResource resource = ((ResourceElement)ancestor).getRepositoryResource(); > final ILocalResource local = ((ResourceElement)ancestor).getLocalResource(); > ancestorResourceSet.setURIConverter(new RevisionedURIConverter(resource, local)); >+ ancestorResource = ModelUtils.load(((IStreamContentAccessor)ancestor).getContents(), >+ ancestor.getName(), ancestorResourceSet).eResource(); > } catch (final IOException e) { > // Couldn't load ancestor resource, create an empty one > ancestorResource = ModelUtils.createResource(URI.createURI(ancestor.getName())); >@@ -128,7 +128,7 @@ > * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> > * @since 1.0 > */ >- private class RevisionedURIConverter extends URIConverterImpl { >+ private class RevisionedURIConverter extends AbstractResolvingURIConverter { > /** The revision of the base model. This revision's timestamp will be used to resolve proxies. */ > private final IRepositoryResource baseRevision; > >@@ -149,6 +149,24 @@ > localResource = local; > } > >+ private URI getRemoteResourceUri() { >+ return URI.createURI(baseRevision.getUrl()); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @see org.eclipse.emf.compare.ui.team.AbstractResolvingURIConverter#resolve(org.eclipse.emf.common.util.URI) >+ */ >+ @Override >+ protected URI resolve(URI uri) throws CoreException { >+ URI resolvedUri = uri; >+ if (uri.isRelative()) { >+ resolvedUri = uri.resolve(getRemoteResourceUri()); >+ } >+ return resolvedUri; >+ } >+ > /** > * {@inheritDoc} > * >@@ -157,25 +175,24 @@ > @Override > public InputStream createInputStream(URI uri) throws IOException { > InputStream resultStream = null; >- if (uri.isPlatformPlugin() || uri.toString().matches("(\\.\\./)+?plugins/.*")) { //$NON-NLS-1$ >+ >+ final URI normalizedUri = normalize(uri); >+ // load all local uris via super implementation (except for the local resource) >+ if (normalizedUri.isPlatformPlugin()) { > resultStream = super.createInputStream(uri); > } else { > try { >- // We'll have to change the EMF URI to find the IFile it points to >- URI deresolvedURI = uri; >- if (uri.isRelative()) { >- deresolvedURI = uri.resolve(URI.createURI(baseRevision.getUrl())); >- } >+ // load only remove resources via svn > final IRepositoryLocation location = baseRevision.getRepositoryLocation(); > final ISVNConnector proxy = location.acquireSVNProxy(); >- final IRepositoryResource target = location.asRepositoryFile(deresolvedURI.toString(), >+ final IRepositoryResource target = location.asRepositoryFile(normalizedUri.toString(), > false); > final long svnOptions = ISVNConnector.Options.NONE; > final String[] revProps = ISVNConnector.DEFAULT_LOG_ENTRY_PROPS; > final ISVNProgressMonitor monitor = new SVNNullProgressMonitor(); > > final SVNLogEntry[] entries = SVNUtility.logEntries(proxy, SVNUtility >- .asEntryReference(deresolvedURI.toString()), SVNRevision.HEAD, SVNRevision >+ .asEntryReference(normalizedUri.toString()), SVNRevision.HEAD, SVNRevision > .fromNumber(0), svnOptions, revProps, 0, monitor); > > StringOutputStream stream = null; >@@ -207,7 +224,7 @@ > if (stream != null) > resultStream = new StringInputStream(stream.getWriter().getBuffer().toString()); > } catch (final SVNConnectorException e) { >- resultStream = super.createInputStream(uri); >+ resultStream = super.createInputStream(normalizedUri); > } > } > return resultStream; >#P org.eclipse.emf.compare.diff >Index: src/org/eclipse/emf/compare/diff/engine/GenericDiffEngine.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.diff/src/org/eclipse/emf/compare/diff/engine/GenericDiffEngine.java,v >retrieving revision 1.41 >diff -u -r1.41 GenericDiffEngine.java >--- src/org/eclipse/emf/compare/diff/engine/GenericDiffEngine.java 3 Nov 2009 10:51:07 -0000 1.41 >+++ src/org/eclipse/emf/compare/diff/engine/GenericDiffEngine.java 25 Feb 2010 22:05:10 -0000 >@@ -773,7 +773,13 @@ > root.getSubDiffElements().add(curGroup); > return curGroup; > } >- buildHierarchyGroup(targetParent.eContainer(), root).getSubDiffElements().add(curGroup); >+ // if targetElement is the root of a fragment resource, do not walk the hierarchy up, >+ // instead report changes to fragments in their own resource's context >+ if (targetParent.eResource() == targetParent.eContainer().eResource()) { >+ buildHierarchyGroup(targetParent.eContainer(), root).getSubDiffElements().add(curGroup); >+ } else { >+ root.getSubDiffElements().add(curGroup); >+ } > return curGroup; > } > >Index: src/org/eclipse/emf/compare/diff/merge/service/MergeFactory.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.compare/plugins/org.eclipse.emf.compare.diff/src/org/eclipse/emf/compare/diff/merge/service/MergeFactory.java,v >retrieving revision 1.16 >diff -u -r1.16 MergeFactory.java >--- src/org/eclipse/emf/compare/diff/merge/service/MergeFactory.java 13 Feb 2009 13:31:10 -0000 1.16 >+++ src/org/eclipse/emf/compare/diff/merge/service/MergeFactory.java 25 Feb 2010 22:05:10 -0000 >@@ -24,6 +24,7 @@ > import org.eclipse.emf.compare.diff.internal.merge.DefaultMergerProvider; > import org.eclipse.emf.compare.diff.merge.DefaultMerger; > import org.eclipse.emf.compare.diff.merge.IMerger; >+import org.eclipse.emf.compare.diff.metamodel.AbstractDiffExtension; > import org.eclipse.emf.compare.diff.metamodel.DiffElement; > import org.eclipse.emf.compare.util.ClassUtils; > import org.eclipse.emf.compare.util.EMFCompareMap; >@@ -81,19 +82,28 @@ > * @return The merger adapted to <code>element</code>, <code>null</code> if it cannot be instantiated. > */ > public static IMerger createMerger(DiffElement element) { >- final Class<? extends IMerger> mergerClass = getBestMerger(element); >- > // If the merger provides a default constructor, we instantiate it > IMerger elementMerger = null; >- try { >- elementMerger = mergerClass.newInstance(); >- elementMerger.setDiffElement(element); >- } catch (final InstantiationException e) { >- EMFComparePlugin.log(e.getMessage(), false); >- } catch (final IllegalAccessException e) { >- EMFComparePlugin.log(e.getMessage(), false); >+ >+ // diff extensions may offer their own merger, so we use it here >+ if (element instanceof AbstractDiffExtension) { >+ elementMerger = ((AbstractDiffExtension)element).provideMerger(); >+ } >+ >+ if (elementMerger == null) { >+ try { >+ final Class<? extends IMerger> mergerClass = getBestMerger(element); >+ elementMerger = mergerClass.newInstance(); >+ } catch (final InstantiationException e) { >+ EMFComparePlugin.log(e.getMessage(), false); >+ } catch (final IllegalAccessException e) { >+ EMFComparePlugin.log(e.getMessage(), false); >+ } > } > >+ if (elementMerger != null) { >+ elementMerger.setDiffElement(element); >+ } > return elementMerger; > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 303976
: 160252