diff options
author | Laurent Goubet | 2012-11-14 09:03:38 +0000 |
---|---|---|
committer | Robin Stocker | 2013-01-18 18:29:19 +0000 |
commit | e7536536b48b48390db875502723c27daf89967a (patch) | |
tree | dd8db350a48fcdf732cdc87a8711065e9a9fd64d | |
parent | 821cb62ffba577cfd3286e44ac514146298629a0 (diff) | |
download | egit-e7536536b48b48390db875502723c27daf89967a.tar.gz egit-e7536536b48b48390db875502723c27daf89967a.tar.xz egit-e7536536b48b48390db875502723c27daf89967a.zip |
Improve support for logical models in Compare With operation
When comparing a file with another branch, tag or reference, take the
model providers into account and launch the synchronize perspective
instead of comparing the single, selected file into a compare editor
if this file is part of a model spanning more than one resource.
Bug: 393225
Change-Id: Id113b941afa44109b899c17957baa053bd75158f
Also-by: Gunnar Wagenknecht <gunnar@wagenknecht.org>
Signed-off-by: Gunnar Wagenknecht <gunnar@wagenknecht.org>
Signed-off-by: Robin Stocker <robin@nibor.org>
6 files changed, 181 insertions, 28 deletions
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java index 925d8801dd..b7102186e0 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java @@ -1,6 +1,8 @@ /******************************************************************************* * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> * Copyright (C) 2012, Robin Stocker <robin@nibor.org> + * Copyright (C) 2012, Laurent Goubet <laurent.goubet@obeo.fr> + * Copyright (C) 2012, Gunnar Wagenknecht <gunnar@wagenknecht.org> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,15 +14,23 @@ package org.eclipse.egit.core.internal.util; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.mapping.IModelProviderDescriptor; +import org.eclipse.core.resources.mapping.ModelProvider; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.egit.core.Activator; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.jgit.lib.Repository; @@ -150,4 +160,39 @@ public class ResourceUtil { resourcesList.add(path); } } + + /** + * This will query all model providers for those that are enabled on the + * given file and list all mappings available for that file. + * + * @param file + * The file for which we need the associated resource mappings. + * @param context + * Context from which remote content could be retrieved. + * @return All mappings available for that file. + */ + public static ResourceMapping[] getResourceMappings(IFile file, + ResourceMappingContext context) { + final IModelProviderDescriptor[] modelDescriptors = ModelProvider + .getModelProviderDescriptors(); + + final Set<ResourceMapping> mappings = new LinkedHashSet<ResourceMapping>(); + for (IModelProviderDescriptor candidate : modelDescriptors) { + try { + final IResource[] resources = candidate + .getMatchingResources(new IResource[] { file, }); + if (resources.length > 0) { + // get mappings from model provider if there are matching resources + final ModelProvider model = candidate.getModelProvider(); + final ResourceMapping[] modelMappings = model.getMappings( + file, context, null); + for (ResourceMapping mapping : modelMappings) + mappings.add(mapping); + } + } catch (CoreException e) { + Activator.logError(e.getMessage(), e); + } + } + return mappings.toArray(new ResourceMapping[mappings.size()]); + } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java index 0aa6bc4c86..0d502b6421 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java @@ -6,6 +6,8 @@ * Copyright (C) 2012, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2012, Daniel Megert <daniel_megert@ch.ibm.com> * Copyright (C) 2012, Robin Stocker <robin@nibor.org> + * Copyright (C) 2012, Laurent Goubet <laurent.goubet@obeo.fr> + * Copyright (C) 2012, Gunnar Wagenknecht <gunnar@wagenknecht.org> * 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 @@ -2158,6 +2160,9 @@ public class UIText extends NLS { public static String CompareWithIndexAction_errorOnAddToIndex; /** */ + public static String CompareWithRefAction_errorOnSynchronize; + + /** */ public static String CompareWithPreviousActionHandler_MessageRevisionNotFound; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CompareUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CompareUtils.java index 01b2519f63..aadacf165f 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CompareUtils.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/CompareUtils.java @@ -11,6 +11,8 @@ * Stefan Lay (SAP AG) - initial implementation * Yann Simon <yann.simon.fr@gmail.com> - implementation of getHeadTypedElement * Robin Stocker <robin@nibor.org> + * Laurent Goubet <laurent.goubet@obeo.fr> + * Gunnar Wagenknecht <gunnar@wagenknecht.org> *******************************************************************************/ package org.eclipse.egit.ui.internal; @@ -28,7 +30,11 @@ import org.eclipse.compare.structuremergeviewer.DiffNode; import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.compare.structuremergeviewer.IStructureComparator; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.Platform; @@ -42,6 +48,7 @@ import org.eclipse.egit.core.internal.CompareCoreUtils; import org.eclipse.egit.core.internal.storage.GitFileRevision; import org.eclipse.egit.core.internal.storage.WorkingTreeFileRevision; import org.eclipse.egit.core.internal.storage.WorkspaceFileRevision; +import org.eclipse.egit.core.internal.util.ResourceUtil; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIText; @@ -687,4 +694,47 @@ public class CompareUtils { } } + /** + * Indicates if it is OK to open the selected file directly in a compare + * editor. + * <p> + * It is not OK to show the single file if the file is part of a + * logical model element that spans multiple files. + * </p> + * + * @param file + * file the user is trying to compare + * @return <code>true</code> if the file can be opened directly in a compare + * editor, <code>false</code> if the synchronize view should be + * opened instead. + */ + public static boolean canDirectlyOpenInCompare(IFile file) { + /* + * Note : it would be better to use a remote context here in order to + * give the model provider a chance to resolve the remote logical model + * instead of only relying on the local one. However, this might be a + * long operation and would not really provide more context : we're + * trying to determine if the local file can be compared alone, this can + * be done by relying on the local model only. + */ + final ResourceMapping[] mappings = ResourceUtil.getResourceMappings( + file, ResourceMappingContext.LOCAL_CONTEXT); + + for (ResourceMapping mapping : mappings) { + try { + final ResourceTraversal[] traversals = mapping.getTraversals( + ResourceMappingContext.LOCAL_CONTEXT, null); + for (ResourceTraversal traversal : traversals) { + final IResource[] resources = traversal.getResources(); + for (IResource resource : resources) { + if (!resource.equals(file)) + return false; + } + } + } catch (CoreException e) { + Activator.logError(e.getMessage(), e); + } + } + return true; + } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithRefActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithRefActionHandler.java index d0d330b434..34f5e6efb3 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithRefActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/CompareWithRefActionHandler.java @@ -5,6 +5,11 @@ * 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: + * Mathias Kinzler <mathias.kinzler@sap.com> + * Laurent Goubet <laurent.goubet@obeo.fr> + * Gunnar Wagenknecht <gunnar@wagenknecht.org> *******************************************************************************/ package org.eclipse.egit.ui.internal.actions; @@ -17,13 +22,19 @@ import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.egit.core.internal.util.ResourceUtil; import org.eclipse.egit.core.project.RepositoryMapping; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIText; import org.eclipse.egit.ui.internal.CompareUtils; import org.eclipse.egit.ui.internal.GitCompareFileRevisionEditorInput; import org.eclipse.egit.ui.internal.dialogs.CompareTargetSelectionDialog; import org.eclipse.egit.ui.internal.dialogs.CompareTreeView; +import org.eclipse.egit.ui.internal.synchronize.GitModelSynchronize; import org.eclipse.jface.window.Window; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -54,29 +65,11 @@ public class CompareWithRefActionHandler extends RepositoryActionHandler { if (resources.length == 1 && resources[0] instanceof IFile) { final IFile baseFile = (IFile) resources[0]; - final ITypedElement base = SaveableCompareEditorInput - .createFileElement(baseFile); - - final ITypedElement next; - ITypedElement ancestor = null; - try { - RepositoryMapping mapping = RepositoryMapping - .getMapping(resources[0]); - next = getElementForRef(mapping.getRepository(), mapping - .getRepoRelativePath(baseFile), dlg.getRefName()); - ancestor = CompareUtils.getFileRevisionTypedElementForCommonAncestor( - mapping.getRepoRelativePath(baseFile), repo.resolve(Constants.HEAD), - repo.resolve(dlg.getRefName()), repo); - } catch (IOException e) { - Activator.handleError( - UIText.CompareWithIndexAction_errorOnAddToIndex, e, - true); - return null; + if (CompareUtils.canDirectlyOpenInCompare(baseFile)) { + showSingleFileComparison(baseFile, dlg.getRefName()); + } else { + synchronizeModel(baseFile, repo, dlg.getRefName()); } - final GitCompareFileRevisionEditorInput in = new GitCompareFileRevisionEditorInput( - base, next, ancestor, null); - in.getCompareConfiguration().setRightLabel(dlg.getRefName()); - CompareUI.openCompareEditor(in); } else { CompareTreeView view; try { @@ -92,6 +85,48 @@ public class CompareWithRefActionHandler extends RepositoryActionHandler { return null; } + private void showSingleFileComparison(IFile file, String refName) { + final ITypedElement base = SaveableCompareEditorInput + .createFileElement(file); + + final ITypedElement next; + try { + RepositoryMapping mapping = RepositoryMapping.getMapping(file); + next = getElementForRef(mapping.getRepository(), + mapping.getRepoRelativePath(file), refName); + } catch (IOException e) { + Activator.handleError( + UIText.CompareWithIndexAction_errorOnAddToIndex, e, true); + return; + } + + final GitCompareFileRevisionEditorInput in = new GitCompareFileRevisionEditorInput( + base, next, null); + in.getCompareConfiguration().setRightLabel(refName); + CompareUI.openCompareEditor(in); + } + + private void synchronizeModel(final IFile file, Repository repo, + String refName) { + try { + final GitSynchronizeData data = new GitSynchronizeData(repo, + Constants.HEAD, refName, true); + final GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet( + data); + + // use all available local mappings for proper model support + final ResourceMapping[] mappings = ResourceUtil + .getResourceMappings(file, + ResourceMappingContext.LOCAL_CONTEXT); + + GitModelSynchronize.launch(dataSet, mappings); + } catch (IOException e) { + Activator.handleError( + UIText.CompareWithRefAction_errorOnSynchronize, e, true); + return; + } + } + private ITypedElement getElementForRef(final Repository repository, final String gitPath, final String refName) throws IOException { ObjectId commitId = repository.resolve(refName + "^{commit}"); //$NON-NLS-1$ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronize.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronize.java index 753c5c6ae0..b2250e77ad 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronize.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronize.java @@ -1,5 +1,7 @@ /******************************************************************************* * Copyright (C) 2010, 2012 Dariusz Luksza <dariusz@luksza.org>. + * Copyright (C) 2012, Laurent Goubet <laurent.goubet@obeo.fr> + * Copyright (C) 2012, Gunnar Wagenknecht <gunnar@wagenknecht.org> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +44,7 @@ import org.eclipse.ui.PlatformUI; */ public class GitModelSynchronize { - private static final String providerId = "org.eclipse.egit.core.GitProvider"; //$NON-NLS-1$ + private static final String GIT_PROVIDER_ID = "org.eclipse.egit.core.GitProvider"; //$NON-NLS-1$ /** * Launches Git Model synchronization action @@ -63,7 +65,20 @@ public class GitModelSynchronize { */ public static final void launch(final GitSynchronizeDataSet gsdSet, IResource[] resources) { - ResourceMapping[] mappings = getSelectedResourceMappings(resources); + ResourceMapping[] mappings = getGitResourceMappings(resources); + + launch(gsdSet, mappings); + } + + /** + * Launches Git Model synchronization action using the specified resource + * mapping + * + * @param gsdSet + * @param mappings + */ + public static final void launch(final GitSynchronizeDataSet gsdSet, + ResourceMapping[] mappings) { IWorkbenchWindow window = PlatformUI.getWorkbench() .getActiveWorkbenchWindow(); @@ -78,7 +93,7 @@ public class GitModelSynchronize { * @return the resource mappings that contain resources associated with the * given provider */ - private static ResourceMapping[] getSelectedResourceMappings( + private static ResourceMapping[] getGitResourceMappings( IResource[] elements) { List<ResourceMapping> providerMappings = new ArrayList<ResourceMapping>(); @@ -87,7 +102,7 @@ public class GitModelSynchronize { if (adapted != null && adapted instanceof ResourceMapping) { ResourceMapping mapping = (ResourceMapping) adapted; - if (isMappedToProvider(mapping)) + if (isMappedToGitProvider(mapping)) providerMappings.add(mapping); } } @@ -119,13 +134,13 @@ public class GitModelSynchronize { * @return <code>true</code> if resource is mapped to Git provider, * <code>false</code> otherwise */ - private static boolean isMappedToProvider(ResourceMapping element) { + private static boolean isMappedToGitProvider(ResourceMapping element) { IProject[] projects = element.getProjects(); for (IProject project: projects) { RepositoryProvider provider = RepositoryProvider .getProvider(project); - if (provider != null && provider.getID().equals(providerId)) + if (provider != null && provider.getID().equals(GIT_PROVIDER_ID)) return true; } return false; diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties index 8140f08567..6fbae53d1b 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties @@ -12,6 +12,7 @@ # - Added context menu to the Commit Editor's header text # Markus Keller <markus_keller@ch.ibm.com> - Show the repository name in the title of the Pull Result dialog # Daniel Megert <daniel_megert@ch.ibm.com> - Use correct syntax when a single ref was updated +# Gunnar Wagenknecht <gunnar@wagenknecht.org> ############################################################################### AbortRebaseCommand_CancelDialogMessage=The abort operation was canceled AbortRebaseCommand_JobName=Aborting Rebase @@ -718,6 +719,8 @@ CompareWithIndexAction_errorOnAddToIndex=Error during adding to index CompareWithPreviousActionHandler_MessageRevisionNotFound=No previous revision of {0} could be found in the repository. CompareWithPreviousActionHandler_TaskGeneratingInput=Generating comparison with previous revision CompareWithPreviousActionHandler_TitleRevisionNotFound=Previous revision not found +CompareWithRefAction_errorOnSynchronize=Error reading from repository while preparing input for compare operation. + CompareUtils_errorCommonAncestor=Error finding common ancestor for {0} and {1} ConfirmationPage_cantConnectToAnyTitle=Can't Connect |