diff options
| author | Thomas Wolf | 2019-05-17 21:08:41 +0000 |
|---|---|---|
| committer | Thomas Wolf | 2019-05-22 07:39:03 +0000 |
| commit | e8ef6ff1e1044c8dc3b3443bd37f34873c6c7de0 (patch) | |
| tree | c18dee2d054e0d07b16fe13c82549d92d0dcd766 | |
| parent | 2cd5ab8d6f1321384e17675fe7e6df5bd61d3839 (diff) | |
| download | egit-e8ef6ff1e1044c8dc3b3443bd37f34873c6c7de0.tar.gz egit-e8ef6ff1e1044c8dc3b3443bd37f34873c6c7de0.tar.xz egit-e8ef6ff1e1044c8dc3b3443bd37f34873c6c7de0.zip | |
History: new operation to check out files from a commit
Add a new operation in the CommitFileDiffViewer to check out file
revisions shown into the working tree. Previously the user would
have to navigate to the file in the package explorer (or project
explorer) and use "Replace with...->Commit" there, which opens a
dialog to choose the commit. Or use "Open This Version" and then
copy-paste the text. Both are rather round-about ways to achieve
this. Newly there's a "Check Out This Version" command in the context
menu that enables the user to do this directly.
The same operation is also available in the outline view of the
unified diff page of the commit viewer.
The code checking for potential loss of uncommitted changes and
for running launches and then asking the user to confirm the
operation has been factored out of DiscardChangesActionHandler
into CommandConfirmation.
Bug: 362907
Change-Id: Ie237e24b9e78b888b0de816d39c1c43ca44c400a
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
8 files changed, 298 insertions, 159 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java index faf7ff0cf9..2e9099554d 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java @@ -4592,6 +4592,9 @@ public class UIText extends NLS { public static String CommitFileDiffViewer_CanNotOpenCompareEditorTitle; /** */ + public static String CommitFileDiffViewer_CheckoutThisVersionMenuLabel; + + /** */ public static String CommitFileDiffViewer_CompareMenuLabel; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java index 2cfe03452c..4c72053962 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java @@ -15,32 +15,20 @@ *******************************************************************************/ package org.eclipse.egit.ui.internal.actions; -import java.text.MessageFormat; import java.util.Collection; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.stream.Stream; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.egit.core.Activator; -import org.eclipse.egit.core.internal.indexdiff.IndexDiffCache; -import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry; -import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; import org.eclipse.egit.core.internal.job.JobUtil; import org.eclipse.egit.core.op.DiscardChangesOperation; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.internal.UIText; -import org.eclipse.egit.ui.internal.branch.LaunchFinder; +import org.eclipse.egit.ui.internal.dialogs.CommandConfirmation; import org.eclipse.egit.ui.internal.operations.GitScopeUtil; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.ui.IWorkbenchPart; @@ -64,23 +52,8 @@ public class DiscardChangesActionHandler extends RepositoryActionHandler { } Map<Repository, Collection<String>> paths = operation .getPathsPerRepository(); - if (haveChanges(paths)) { - String question = UIText.DiscardChangesAction_confirmActionMessage; - String launch = LaunchFinder - .getRunningLaunchConfiguration(paths.keySet(), null); - if (launch != null) { - question = MessageFormat.format(question, - "\n\n" + MessageFormat.format( //$NON-NLS-1$ - UIText.LaunchFinder_RunningLaunchMessage, - launch)); - } else { - question = MessageFormat.format(question, ""); //$NON-NLS-1$ - } - if (!openConfirmationDialog(event, question)) { - return null; - } - } else if (LaunchFinder.shouldCancelBecauseOfRunningLaunches( - paths.keySet(), null)) { + if (!CommandConfirmation.confirmCheckout(getShell(event), paths, + !hasDirectories)) { return null; } JobUtil.scheduleUserWorkspaceJob(operation, @@ -93,94 +66,6 @@ public class DiscardChangesActionHandler extends RepositoryActionHandler { } } - private boolean haveChanges(Map<Repository, Collection<String>> paths) { - IndexDiffCache cache = Activator.getDefault().getIndexDiffCache(); - for (Map.Entry<Repository, Collection<String>> entry : paths - .entrySet()) { - Repository repo = entry.getKey(); - Assert.isNotNull(repo); - IndexDiffCacheEntry indexDiff = cache.getIndexDiffCacheEntry(repo); - if (indexDiff == null) { - return true; // No info, assume worst case - } - IndexDiffData diff = indexDiff.getIndexDiff(); - if (diff == null || hasChanges(diff, entry.getValue())) { - return true; - } - } - return false; - } - - private boolean hasChanges(@NonNull IndexDiffData diff, - Collection<String> paths) { - Set<String> repoPaths = new HashSet<>(paths); - // Untracked files are ignored and won't be removed. - if (repoPaths.contains("")) { //$NON-NLS-1$ - // Working tree root included - return diff.hasChanges(); - } - // Do the directories later to avoid having to do all the (potentially - // expensive) substrings if a plain file already matches. - if (containsAny(repoPaths, diff.getAdded()) - || containsAny(repoPaths, diff.getChanged()) - || containsAny(repoPaths, diff.getModified()) - || containsAny(repoPaths, diff.getRemoved())) { - return true; - } - if (hasDirectories) { - return containsAnyDirectory(repoPaths, diff.getAdded()) - || containsAnyDirectory(repoPaths, diff.getChanged()) - || containsAnyDirectory(repoPaths, diff.getModified()) - || containsAnyDirectory(repoPaths, diff.getRemoved()); - } - return false; - } - - private boolean containsAny(Set<String> repoPaths, - Collection<String> files) { - return files.stream().anyMatch(repoPaths::contains); - } - - private boolean containsAnyDirectory(Set<String> repoPaths, - Collection<String> files) { - String lastDirectory = null; - for (String file : files) { - int j = file.lastIndexOf('/'); - if (j <= 0) { - continue; - } - String directory = file.substring(0, j); - String withTerminator = directory + '/'; - if (lastDirectory != null - && lastDirectory.startsWith(withTerminator)) { - continue; - } - if (repoPaths.contains(directory)) { - return true; - } - lastDirectory = withTerminator; - for (int i = directory.indexOf('/'); i > 0; i = directory.indexOf( - '/', i + 1)) { - if (repoPaths.contains(directory.substring(0, i))) { - return true; - } - } - } - return false; - } - - private boolean openConfirmationDialog(ExecutionEvent event, - String question) throws ExecutionException { - MessageDialog dlg = new MessageDialog(getShell(event), - UIText.DiscardChangesAction_confirmActionTitle, null, question, - MessageDialog.CONFIRM, - new String[] { - UIText.DiscardChangesAction_discardChangesButtonText, - IDialogConstants.CANCEL_LABEL }, - 0); - return dlg.open() == Window.OK; - } - @Override public boolean isEnabled() { Repository[] repositories = getRepositories(); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java index 46990e8e8f..a95ca96eb6 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java @@ -24,6 +24,7 @@ import org.eclipse.core.runtime.Path; import org.eclipse.egit.ui.internal.UIIcons; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.commit.DiffRegionFormatter.FileDiffRegion; +import org.eclipse.egit.ui.internal.history.CommitFileDiffViewer.CheckoutAction; import org.eclipse.egit.ui.internal.history.FileDiff; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.MenuManager; @@ -46,6 +47,7 @@ import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; @@ -230,31 +232,52 @@ public class DiffEditorOutlinePage extends NestedContentOutlinePage { } } }); - if (selected.size() == 1 && !haveNew.isEmpty()) { - // "Compare with previous" makes only sense if there are - // both a new and a previous version. + } + if (!haveNew.isEmpty()) { + boolean hasFiles = haveNew.stream() + .anyMatch(d -> !d.getDiff().isSubmodule()); + if (hasFiles) { menuManager.add(new Separator()); - menuManager.add(new Action( - UIText.CommitFileDiffViewer_CompareMenuLabel) { - - @Override - public void run() { - FileDiffRegion fileDiff = selected.iterator() - .next(); - DiffViewer.showTwoWayFileDiff(fileDiff.getDiff()); - } - }); + CheckoutAction action = new CheckoutAction( + this::getStructuredSelection); + menuManager.add(action); + action.setEnabled(haveNew.iterator().next().getDiff() + .getRepository().getRepositoryState() + .equals(RepositoryState.SAFE)); } } + if (selected.size() == 1 && !haveNew.isEmpty() + && !haveOld.isEmpty()) { + // "Compare with previous" makes only sense if there are + // both a new and a previous version. + menuManager.add(new Separator()); + menuManager.add(new Action( + UIText.CommitFileDiffViewer_CompareMenuLabel) { + + @Override + public void run() { + FileDiffRegion fileDiff = selected.iterator().next(); + DiffViewer.showTwoWayFileDiff(fileDiff.getDiff()); + } + }); + } }); Menu menu = contextMenu.createContextMenu(viewer.getTree()); viewer.getTree().setMenu(menu); } - private Collection<FileDiffRegion> getSelectedFileDiffs() { + private IStructuredSelection getStructuredSelection() { ISelection currentSelection = getSelection(); + if (currentSelection instanceof IStructuredSelection) { + return (IStructuredSelection) currentSelection; + } + return StructuredSelection.EMPTY; + } + + private Collection<FileDiffRegion> getSelectedFileDiffs() { + IStructuredSelection currentSelection = getStructuredSelection(); List<FileDiffRegion> result = new ArrayList<>(); - if (!currentSelection.isEmpty() && currentSelection instanceof StructuredSelection) { + if (!currentSelection.isEmpty()) { for (Object selected : ((StructuredSelection) currentSelection).toList()) { if (selected instanceof FileDiffRegion && !((FileDiffRegion) selected).getDiff() diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffRegionFormatter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffRegionFormatter.java index f1eae81d40..84a331ac5d 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffRegionFormatter.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffRegionFormatter.java @@ -19,6 +19,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.egit.core.internal.CompareCoreUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.commit.DiffRegionFormatter.DiffRegion.Type; @@ -143,7 +144,7 @@ public class DiffRegionFormatter extends DiffFormatter { /** * Region giving access to the {@link FileDiff} that generated the content. */ - public static class FileDiffRegion extends Region { + public static class FileDiffRegion extends Region implements IAdaptable { private final @NonNull FileDiff diff; @@ -188,6 +189,14 @@ public class DiffRegionFormatter extends DiffFormatter { return "[FileDiffRange " + diff.getPath() //$NON-NLS-1$ + ' ' + super.toString() + ']'; } + + @Override + public <T> T getAdapter(Class<T> adapter) { + if (FileDiff.class.equals(adapter)) { + return adapter.cast(diff); + } + return null; + } } private static class DocumentOutputStream extends OutputStream { diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommandConfirmation.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommandConfirmation.java index c0d18ab14d..bceb780b69 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommandConfirmation.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommandConfirmation.java @@ -15,20 +15,32 @@ package org.eclipse.egit.ui.internal.dialogs; import java.text.MessageFormat; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.eclipse.core.runtime.Assert; +import org.eclipse.egit.core.Activator; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffCache; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.branch.LaunchFinder; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.window.Window; +import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.lib.Repository; import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; /** * Dialog to confirm a potentially destructive command */ public class CommandConfirmation { + /** * Ask the user to confirm hard reset. Warns the user if a running launch * could be affected by the reset. @@ -61,4 +73,150 @@ public class CommandConfirmation { return messageDialog.open() == Window.OK; } + + /** + * Ask the user to confirm an operation that might lose uncommitted changes. + * + * @param shell + * to use as parent for the dialog asking the user. If + * {@code null} a suitable parent is determined automatically. + * @param repository + * to check + * @return {@code true} if the user confirmed the operation, {@code false} + * otherwise + */ + public static boolean confirmCheckout(Shell shell, Repository repository) { + return confirmCheckout(shell, + Collections.singletonMap(repository, Collections.emptyList()), + true); + } + + /** + * Ask the user to confirm an operation that might lose uncommitted changes. + * + * @param shell + * to use as parent for the dialog asking the user. If + * {@code null} a suitable parent is determined automatically. + * @param repoAndPaths + * to check + * @param filesOnly + * {@code true} if the paths are all for files; {@code false} if + * there may be directories among the paths + * @return {@code true} if the user confirmed the operation, {@code false} + * otherwise + */ + public static boolean confirmCheckout(Shell shell, + Map<Repository, Collection<String>> repoAndPaths, + boolean filesOnly) { + if (haveChanges(repoAndPaths, filesOnly)) { + String question = UIText.DiscardChangesAction_confirmActionMessage; + String launch = LaunchFinder + .getRunningLaunchConfiguration(repoAndPaths.keySet(), null); + if (launch != null) { + question = MessageFormat.format(question, + "\n\n" + MessageFormat.format( //$NON-NLS-1$ + UIText.LaunchFinder_RunningLaunchMessage, + launch)); + } else { + question = MessageFormat.format(question, ""); //$NON-NLS-1$ + } + Shell parent = shell != null ? shell + : PlatformUI.getWorkbench().getModalDialogShellProvider() + .getShell(); + MessageDialog messageDialog = new MessageDialog(parent, + UIText.DiscardChangesAction_confirmActionTitle, null, + question, MessageDialog.CONFIRM, + new String[] { + UIText.DiscardChangesAction_discardChangesButtonText, + IDialogConstants.CANCEL_LABEL }, + 0); + return messageDialog.open() == Window.OK; + } else { + return !LaunchFinder.shouldCancelBecauseOfRunningLaunches( + repoAndPaths.keySet(), null); + } + } + + private static boolean haveChanges( + Map<Repository, Collection<String>> paths, + boolean filesOnly) { + IndexDiffCache cache = Activator.getDefault().getIndexDiffCache(); + for (Map.Entry<Repository, Collection<String>> entry : paths + .entrySet()) { + Repository repo = entry.getKey(); + Assert.isNotNull(repo); + IndexDiffCacheEntry indexDiff = cache.getIndexDiffCacheEntry(repo); + if (indexDiff == null) { + return true; // No info, assume worst case + } + IndexDiffData diff = indexDiff.getIndexDiff(); + if (diff == null || hasChanges(diff, entry.getValue(), filesOnly)) { + return true; + } + } + return false; + } + + private static boolean hasChanges(@NonNull IndexDiffData diff, + Collection<String> paths, boolean filesOnly) { + if (paths.isEmpty()) { + // We're going to do _something_, but it's unknown which paths will + // be affected + return diff.hasChanges(); + } + Set<String> repoPaths = new HashSet<>(paths); + // Untracked files are ignored and won't be removed. + if (repoPaths.contains("")) { //$NON-NLS-1$ + // Working tree root included + return diff.hasChanges(); + } + // Do the directories later to avoid having to do all the (potentially + // expensive) substrings if a plain file already matches. + if (containsAny(repoPaths, diff.getAdded()) + || containsAny(repoPaths, diff.getChanged()) + || containsAny(repoPaths, diff.getModified()) + || containsAny(repoPaths, diff.getRemoved())) { + return true; + } + if (!filesOnly) { + return containsAnyDirectory(repoPaths, diff.getAdded()) + || containsAnyDirectory(repoPaths, diff.getChanged()) + || containsAnyDirectory(repoPaths, diff.getModified()) + || containsAnyDirectory(repoPaths, diff.getRemoved()); + } + return false; + } + + private static boolean containsAny(Set<String> repoPaths, + Collection<String> files) { + return files.stream().anyMatch(repoPaths::contains); + } + + private static boolean containsAnyDirectory(Set<String> repoPaths, + Collection<String> files) { + String lastDirectory = null; + for (String file : files) { + int j = file.lastIndexOf('/'); + if (j <= 0) { + continue; + } + String directory = file.substring(0, j); + String withTerminator = directory + '/'; + if (lastDirectory != null + && lastDirectory.startsWith(withTerminator)) { + continue; + } + if (repoPaths.contains(directory)) { + return true; + } + lastDirectory = withTerminator; + for (int i = directory.indexOf('/'); i > 0; i = directory + .indexOf('/', i + 1)) { + if (repoPaths.contains(directory.substring(0, i))) { + return true; + } + } + } + return false; + } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java index ebd027cb17..793304f40d 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java @@ -23,11 +23,15 @@ import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Adapters; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -40,6 +44,7 @@ import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.egit.core.internal.job.JobUtil; import org.eclipse.egit.core.internal.storage.CommitFileRevision; import org.eclipse.egit.core.internal.util.ResourceUtil; +import org.eclipse.egit.core.op.DiscardChangesOperation; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.UIPreferences; @@ -50,6 +55,7 @@ import org.eclipse.egit.ui.internal.UIIcons; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.blame.BlameOperation; import org.eclipse.egit.ui.internal.commit.DiffViewer; +import org.eclipse.egit.ui.internal.dialogs.CommandConfirmation; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; @@ -72,6 +78,7 @@ import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; @@ -133,6 +140,8 @@ public class CommitFileDiffViewer extends TableViewer { private IAction copyAll; + private IAction checkOutThisVersion; + private IAction openThisVersion; private IAction openPreviousVersion; @@ -243,6 +252,8 @@ public class CommitFileDiffViewer extends TableViewer { final MenuManager mgr = new MenuManager(); rawTable.setMenu(mgr.createContextMenu(rawTable)); + checkOutThisVersion = new CheckoutAction(this::getStructuredSelection); + openThisVersion = new Action( UIText.CommitFileDiffViewer_OpenInEditorMenuLabel) { @Override @@ -326,6 +337,8 @@ public class CommitFileDiffViewer extends TableViewer { mgr.add(openThisVersion); mgr.add(openPreviousVersion); mgr.add(new Separator()); + mgr.add(checkOutThisVersion); + mgr.add(new Separator()); mgr.add(compareWithPrevious); mgr.add(compareWorkingTreeVersion); mgr.add(blame); @@ -412,8 +425,12 @@ public class CommitFileDiffViewer extends TableViewer { boolean submoduleSelected = false; boolean addSelected = false; boolean deleteSelected = false; + Repository repository = null; for (Object item : sel.toList()) { FileDiff fileDiff = (FileDiff) item; + if (repository == null) { + repository = fileDiff.getRepository(); + } if (fileDiff.isSubmodule()) { submoduleSelected = true; } @@ -432,6 +449,9 @@ public class CommitFileDiffViewer extends TableViewer { if (!submoduleSelected) { boolean oneOrMoreSelected = !sel.isEmpty(); + checkOutThisVersion.setEnabled( + oneOrMoreSelected && repository != null && repository + .getRepositoryState().equals(RepositoryState.SAFE)); openThisVersion.setEnabled(oneOrMoreSelected && !deleteSelected); openPreviousVersion.setEnabled(oneOrMoreSelected && !addSelected); compareWithPrevious.setEnabled( @@ -453,6 +473,7 @@ public class CommitFileDiffViewer extends TableViewer { openWorkingTreeVersion.setEnabled(oneOrMoreSelected); } } else { + checkOutThisVersion.setEnabled(false); openThisVersion.setEnabled(false); openPreviousVersion.setEnabled(false); openWorkingTreeVersion.setEnabled(false); @@ -836,4 +857,65 @@ public class CommitFileDiffViewer extends TableViewer { } + /** + * An action to check out selected {@link FileDiff}s from the commit. + */ + public static class CheckoutAction extends Action { + + private final Supplier<IStructuredSelection> selectionProvider; + + /** + * Creates a new {@link CheckoutAction}. + * + * @param selectionProvider + * to get the selection from + */ + public CheckoutAction( + Supplier<IStructuredSelection> selectionProvider) { + super(UIText.CommitFileDiffViewer_CheckoutThisVersionMenuLabel); + this.selectionProvider = selectionProvider; + } + + @Override + public void run() { + DiscardChangesOperation operation = createOperation(); + if (operation == null) { + return; + } + Map<Repository, Collection<String>> paths = operation + .getPathsPerRepository(); + if (!CommandConfirmation.confirmCheckout(null, paths, true)) { + return; + } + JobUtil.scheduleUserWorkspaceJob(operation, + UIText.DiscardChangesAction_discardChanges, + JobFamilies.DISCARD_CHANGES); + } + + private DiscardChangesOperation createOperation() { + Collection<FileDiff> diffs = getFileDiffs(selectionProvider.get()); + if (diffs.isEmpty()) { + return null; + } + FileDiff first = diffs.iterator().next(); + Repository repository = first.getRepository(); + String revision = first.getCommit().getName(); + List<String> paths = diffs.stream().map(d -> d.getNewPath()) + .collect(Collectors.toList()); + return new DiscardChangesOperation(repository, paths, revision); + } + + private Collection<FileDiff> getFileDiffs( + IStructuredSelection selection) { + List<FileDiff> result = new ArrayList<>(); + for (Object obj : selection.toList()) { + FileDiff diff = Adapters.adapt(obj, FileDiff.class); + if (diff != null && diff.getChange() != ChangeType.DELETE + && !diff.isSubmodule()) { + result.add(diff); + } + } + return result; + } + } } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java index bf1ea7d96a..0b991000d9 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java @@ -26,7 +26,6 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; import java.util.HashSet; @@ -81,7 +80,6 @@ import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.actions.ActionCommands; import org.eclipse.egit.ui.internal.actions.BooleanPrefAction; import org.eclipse.egit.ui.internal.actions.ReplaceWithOursTheirsMenu; -import org.eclipse.egit.ui.internal.branch.LaunchFinder; import org.eclipse.egit.ui.internal.commands.shared.AbortRebaseCommand; import org.eclipse.egit.ui.internal.commands.shared.AbstractRebaseCommandHandler; import org.eclipse.egit.ui.internal.commands.shared.ContinueRebaseCommand; @@ -93,6 +91,7 @@ import org.eclipse.egit.ui.internal.commit.CommitProposalProcessor; import org.eclipse.egit.ui.internal.commit.DiffViewer; import org.eclipse.egit.ui.internal.components.RepositoryMenuUtil.RepositoryToolbarAction; import org.eclipse.egit.ui.internal.decorators.ProblemLabelDecorator; +import org.eclipse.egit.ui.internal.dialogs.CommandConfirmation; import org.eclipse.egit.ui.internal.dialogs.CommitMessageArea; import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponent; import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponentState; @@ -152,7 +151,6 @@ import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; -import org.eclipse.jface.window.Window; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.AddCommand; @@ -3120,28 +3118,8 @@ public class StagingView extends ViewPart @Override public void run() { - String question = UIText.DiscardChangesAction_confirmActionMessage; - String launch = LaunchFinder - .getRunningLaunchConfiguration( - Collections.singleton(getCurrentRepository()), - null); - if (launch != null) { - question = MessageFormat.format(question, - "\n\n" + MessageFormat.format( //$NON-NLS-1$ - UIText.LaunchFinder_RunningLaunchMessage, - launch)); - } else { - question = MessageFormat.format(question, ""); //$NON-NLS-1$ - } - - MessageDialog dlg = new MessageDialog(form.getShell(), - UIText.DiscardChangesAction_confirmActionTitle, null, - question, MessageDialog.CONFIRM, - new String[] { - UIText.DiscardChangesAction_discardChangesButtonText, - IDialogConstants.CANCEL_LABEL }, - 0); - if (dlg.open() != Window.OK) { + if (!CommandConfirmation.confirmCheckout(form.getShell(), + getCurrentRepository())) { return; } List<String> files = new ArrayList<>(); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties index aa6a9128ac..0252f2ca60 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties @@ -1611,6 +1611,7 @@ MultiBranchOperationResultDialog_CheckoutResultOK=Checkout completed normally MultiBranchOperationResultDialog_CheckoutResultNotTried=The operation was not executed CommitFileDiffViewer_CanNotOpenCompareEditorTitle=Cannot Open Compare Editor +CommitFileDiffViewer_CheckoutThisVersionMenuLabel=Chec&k Out This Version CommitFileDiffViewer_CompareMenuLabel=Compare with Previous &Version CommitFileDiffViewer_CompareWorkingDirectoryMenuLabel=Compare with &Working Tree CommitFileDiffViewer_CopyFilePathMenuLabel=&Copy File Path |
