Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2019-05-17 17:08:41 -0400
committerThomas Wolf2019-05-22 03:39:03 -0400
commite8ef6ff1e1044c8dc3b3443bd37f34873c6c7de0 (patch)
treec18dee2d054e0d07b16fe13c82549d92d0dcd766
parent2cd5ab8d6f1321384e17675fe7e6df5bd61d3839 (diff)
downloadegit-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>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java121
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java53
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffRegionFormatter.java11
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommandConfirmation.java158
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java82
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java28
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties1
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 faf7ff0cf..2e9099554 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 2cfe03452..4c7205396 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 46990e8e8..a95ca96eb 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 f1eae81d4..84a331ac5 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 c0d18ab14..bceb780b6 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 ebd027cb1..793304f40 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 bf1ea7d96..0b991000d 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 aa6a9128a..0252f2ca6 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

Back to the top