mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-156485 git: allow to copy content from 'compare with branch' dialog
* Do not wait for contents to load before showing windows GitOrigin-RevId: 7980f000e20b6d5bd2840b2dd577f9bc884ebffd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8f506ccaeb
commit
2a83474c00
@@ -90,9 +90,7 @@ compare.branches.dialog.title.branch.with.branch=Comparing {0} with {1}
|
||||
compare.branches.dialog.title.branch.with.branch.in.root=Comparing {0} with {1} in root {2}
|
||||
compare.branches.commits.that.exist.in.branch.but.not.in.branch.vcs.command=Commits that exist in {0} but don''t exist in {1} ({2}):
|
||||
popup.title.select.branch.to.compare=Select Branch to Compare
|
||||
progress.title.collecting.changes=Collecting Changes...
|
||||
notification.title.couldn.t.compare.with.branch=Couldn't compare with branch
|
||||
notification.message.couldn.t.compare.with.branch=Couldn''t compare {0,choice,1#file|2#directory} {1} with branch ''{2}'':\n{3}
|
||||
compare.with.dialog.get.from.vcs.action.title=Get from VCS
|
||||
error.text.file.not.found.in.branch={0,choice,1#File|2#Directory} {1} doesn''t exist in branch ''{2}''
|
||||
dialog.message.following.repositories.already.have.specified=<html>The following repositories already have specified {0}<b>{1}</b>:<br>{2}.<br>Do you want to checkout existing {3}?
|
||||
dialog.title.already.exists={0} Already Exists
|
||||
|
||||
@@ -24,5 +24,6 @@
|
||||
<orderEntry type="library" name="StreamEx" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.diff.impl" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.dvcs.actions;
|
||||
|
||||
import com.intellij.dvcs.ui.DvcsBundle;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangesUtil;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.changes.ui.SimpleChangesBrowser;
|
||||
import com.intellij.openapi.vcs.changes.ui.browser.LoadingChangesPanel;
|
||||
import com.intellij.openapi.vcs.history.actions.GetVersionAction;
|
||||
import com.intellij.openapi.vcs.history.actions.GetVersionAction.FileRevisionProvider;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.StatusText;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CompareWithLocalDialog {
|
||||
public static void showDialog(@NotNull Project project,
|
||||
@NotNull @NlsContexts.DialogTitle String dialogTitle,
|
||||
@NotNull LocalContent localContent,
|
||||
@NotNull ThrowableComputable<? extends Collection<Change>, ? extends VcsException> changesLoader) {
|
||||
Disposable loadingDisposable = Disposer.newDisposable();
|
||||
MyChangesBrowser changesBrowser = new MyChangesBrowser(project, localContent);
|
||||
MyLoadingChangesPanel changesPanel = new MyLoadingChangesPanel(changesBrowser, loadingDisposable) {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<Change> loadChanges() throws VcsException {
|
||||
return changesLoader.compute();
|
||||
}
|
||||
};
|
||||
changesPanel.reloadChanges();
|
||||
|
||||
DialogBuilder dialogBuilder = new DialogBuilder(project);
|
||||
dialogBuilder.setTitle(dialogTitle);
|
||||
dialogBuilder.setActionDescriptors(new DialogBuilder.CloseDialogAction());
|
||||
dialogBuilder.setCenterPanel(changesPanel);
|
||||
dialogBuilder.setPreferredFocusComponent(changesPanel.getChangesBrowser().getPreferredFocusedComponent());
|
||||
dialogBuilder.addDisposable(loadingDisposable);
|
||||
dialogBuilder.setDimensionServiceKey("Git.DiffForPathsDialog");
|
||||
dialogBuilder.showNotModal();
|
||||
}
|
||||
|
||||
private static abstract class MyLoadingChangesPanel extends JPanel implements DataProvider {
|
||||
public static final DataKey<MyLoadingChangesPanel> DATA_KEY = DataKey.create("git4idea.log.MyLoadingChangesPanel");
|
||||
|
||||
private final SimpleChangesBrowser myChangesBrowser;
|
||||
private final LoadingChangesPanel myLoadingPanel;
|
||||
|
||||
private MyLoadingChangesPanel(@NotNull SimpleChangesBrowser changesBrowser, @NotNull Disposable disposable) {
|
||||
super(new BorderLayout());
|
||||
|
||||
myChangesBrowser = changesBrowser;
|
||||
|
||||
StatusText emptyText = myChangesBrowser.getViewer().getEmptyText();
|
||||
myLoadingPanel = new LoadingChangesPanel(myChangesBrowser, emptyText, disposable);
|
||||
add(myLoadingPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SimpleChangesBrowser getChangesBrowser() {
|
||||
return myChangesBrowser;
|
||||
}
|
||||
|
||||
public void reloadChanges() {
|
||||
myLoadingPanel.loadChangesInBackground(this::loadChanges, this::applyResult);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract Collection<Change> loadChanges() throws VcsException;
|
||||
|
||||
private void applyResult(@Nullable Collection<Change> changes) {
|
||||
myChangesBrowser.setChangesToDisplay(changes != null ? changes : Collections.emptyList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NotNull String dataId) {
|
||||
if (DATA_KEY.is(dataId)) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyChangesBrowser extends SimpleChangesBrowser {
|
||||
@NotNull private final CompareWithLocalDialog.LocalContent myLocalContent;
|
||||
|
||||
private MyChangesBrowser(@NotNull Project project, @NotNull LocalContent localContent) {
|
||||
super(project, false, true);
|
||||
myLocalContent = localContent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createToolbarActions() {
|
||||
return ContainerUtil.append(
|
||||
super.createToolbarActions(),
|
||||
new MyGetVersionAction()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createPopupMenuActions() {
|
||||
return ContainerUtil.append(
|
||||
super.createPopupMenuActions(),
|
||||
new MyGetVersionAction()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyGetVersionAction extends DumbAwareAction {
|
||||
private MyGetVersionAction() {
|
||||
super(VcsBundle.messagePointer("action.name.get.file.content.from.repository"),
|
||||
VcsBundle.messagePointer("action.description.get.file.content.from.repository"), AllIcons.Actions.Download);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
MyLoadingChangesPanel changesPanel = e.getData(MyLoadingChangesPanel.DATA_KEY);
|
||||
if (project == null || changesPanel == null) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MyChangesBrowser browser = ObjectUtils.tryCast(changesPanel.getChangesBrowser(), MyChangesBrowser.class);
|
||||
boolean isVisible = browser != null && browser.myLocalContent != LocalContent.NONE;
|
||||
boolean isEnabled = isVisible && !browser.getSelectedChanges().isEmpty();
|
||||
e.getPresentation().setVisible(isVisible);
|
||||
e.getPresentation().setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = Objects.requireNonNull(e.getProject());
|
||||
MyLoadingChangesPanel changesPanel = e.getRequiredData(MyLoadingChangesPanel.DATA_KEY);
|
||||
MyChangesBrowser browser = (MyChangesBrowser)changesPanel.getChangesBrowser();
|
||||
|
||||
List<FileRevisionProvider> fileContentProviders = ContainerUtil.map(changesPanel.getChangesBrowser().getSelectedChanges(), change -> {
|
||||
return new MyFileContentProvider(change, browser.myLocalContent);
|
||||
});
|
||||
GetVersionAction.doGet(project, DvcsBundle.message("compare.with.dialog.get.from.vcs.action.title"), fileContentProviders,
|
||||
() -> changesPanel.reloadChanges());
|
||||
}
|
||||
|
||||
private static class MyFileContentProvider implements FileRevisionProvider {
|
||||
@NotNull private final Change myChange;
|
||||
@NotNull private final CompareWithLocalDialog.LocalContent myLocalContent;
|
||||
|
||||
private MyFileContentProvider(@NotNull Change change,
|
||||
@NotNull LocalContent localContent) {
|
||||
myChange = change;
|
||||
myLocalContent = localContent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FilePath getFilePath() {
|
||||
return ChangesUtil.getFilePath(myChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte @Nullable [] getContent() throws VcsException {
|
||||
ContentRevision revision = myLocalContent == LocalContent.AFTER ? myChange.getBeforeRevision()
|
||||
: myChange.getAfterRevision();
|
||||
if (revision == null) return null;
|
||||
|
||||
return ChangesUtil.loadContentRevision(revision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum LocalContent {BEFORE, AFTER, NONE}
|
||||
}
|
||||
@@ -1,23 +1,31 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.dvcs.actions;
|
||||
|
||||
import com.intellij.diff.DiffDialogHints;
|
||||
import com.intellij.diff.DiffManager;
|
||||
import com.intellij.diff.chains.DiffRequestChain;
|
||||
import com.intellij.diff.chains.DiffRequestProducerException;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx;
|
||||
import com.intellij.dvcs.DvcsUtil;
|
||||
import com.intellij.dvcs.repo.AbstractRepositoryManager;
|
||||
import com.intellij.dvcs.repo.Repository;
|
||||
import com.intellij.dvcs.ui.DvcsBundle;
|
||||
import com.intellij.openapi.ListSelection;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsNotifier;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangeDiffRequestChain;
|
||||
import com.intellij.openapi.vcs.history.VcsDiffUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
@@ -25,11 +33,8 @@ import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.vcs.VcsNotificationIdsHolder.COULD_NOT_COMPARE_WITH_BRANCH;
|
||||
import static com.intellij.util.ObjectUtils.chooseNotNull;
|
||||
|
||||
/**
|
||||
@@ -88,32 +93,38 @@ public abstract class DvcsCompareWithBranchAction<T extends Repository> extends
|
||||
@NotNull final VirtualFile file,
|
||||
@NotNull final @NlsSafe String head,
|
||||
@NotNull final @NlsSafe String compare) {
|
||||
new Task.Backgroundable(project, DvcsBundle.message("progress.title.collecting.changes"), true) {
|
||||
private Collection<Change> changes;
|
||||
FilePath filePath = VcsUtil.getFilePath(file);
|
||||
String revNumTitle1 = VcsDiffUtil.getRevisionTitle(compare, false);
|
||||
String revNumTitle2 = VcsDiffUtil.getRevisionTitle(head, true);
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
changes = getDiffChanges(project, file, compare);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
VcsNotifier.getInstance(project).notifyImportantWarning(
|
||||
COULD_NOT_COMPARE_WITH_BRANCH,
|
||||
DvcsBundle.message("notification.title.couldn.t.compare.with.branch"),
|
||||
DvcsBundle.message("notification.message.couldn.t.compare.with.branch",
|
||||
file.isDirectory() ? 1 : 0, file.getPresentableUrl(), compare, e.getMessage()));
|
||||
}
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
String dialogTitle = VcsBundle.message("history.dialog.title.difference.between.versions.in",
|
||||
revNumTitle1, revNumTitle2, filePath.getName());
|
||||
CompareWithLocalDialog.showDialog(project, dialogTitle, CompareWithLocalDialog.LocalContent.AFTER, () -> {
|
||||
return getDiffChanges(project, file, compare);
|
||||
});
|
||||
}
|
||||
else {
|
||||
DiffRequestChain requestChain = new ChangeDiffRequestChain.Async() {
|
||||
@Override
|
||||
protected @NotNull ListSelection<ChangeDiffRequestProducer> loadRequestProducers() throws DiffRequestProducerException {
|
||||
try {
|
||||
Collection<Change> changes = getDiffChanges(project, file, compare);
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
//if changes null -> then exception occurred before
|
||||
if (changes != null) {
|
||||
VcsDiffUtil.showDiffFor(project, changes, VcsDiffUtil.getRevisionTitle(compare, false), VcsDiffUtil.getRevisionTitle(head, true),
|
||||
VcsUtil.getFilePath(file));
|
||||
Map<Key<?>, Object> changeContext = new HashMap<>(2);
|
||||
changeContext.put(DiffUserDataKeysEx.VCS_DIFF_LEFT_CONTENT_TITLE, revNumTitle1);
|
||||
changeContext.put(DiffUserDataKeysEx.VCS_DIFF_RIGHT_CONTENT_TITLE, revNumTitle2);
|
||||
|
||||
return ListSelection.createAt(new ArrayList<>(changes), 0)
|
||||
.map(change -> ChangeDiffRequestProducer.create(project, change, changeContext));
|
||||
}
|
||||
catch (VcsException e) {
|
||||
throw new DiffRequestProducerException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.queue();
|
||||
};
|
||||
DiffManager.getInstance().showDiff(project, requestChain, DiffDialogHints.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
@NlsSafe
|
||||
|
||||
+11
@@ -69,4 +69,15 @@ public class ShowDiffContext {
|
||||
if (!myRequestContext.containsKey(change)) myRequestContext.put(change, new HashMap<>());
|
||||
myRequestContext.get(change).put(key, value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ShowDiffContext createStaticChangeContext(@NotNull Map<Key<?>, Object> map) {
|
||||
return new ShowDiffContext() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<Key<?>, Object> getChangeContext(@NotNull Change change) {
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ public final class VcsDiffUtil {
|
||||
@NotNull @Nls String revNumTitle2,
|
||||
@NotNull FilePath filePath) {
|
||||
if (filePath.isDirectory()) {
|
||||
showChangesDialog(project, getDialogTitle(filePath, revNumTitle1, revNumTitle2), new ArrayList<>(changes));
|
||||
String dialogTitle = VcsBundle.message("history.dialog.title.difference.between.versions.in",
|
||||
revNumTitle1, revNumTitle2, filePath.getName());
|
||||
showChangesDialog(project, dialogTitle, new ArrayList<>(changes));
|
||||
}
|
||||
else {
|
||||
if (changes.isEmpty()) {
|
||||
@@ -57,27 +59,12 @@ public final class VcsDiffUtil {
|
||||
Map<Key<?>, Object> revTitlesMap = new HashMap<>(2);
|
||||
revTitlesMap.put(VCS_DIFF_LEFT_CONTENT_TITLE, revNumTitle1);
|
||||
revTitlesMap.put(VCS_DIFF_RIGHT_CONTENT_TITLE, revNumTitle2);
|
||||
ShowDiffContext showDiffContext = new ShowDiffContext() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<Key<?>, Object> getChangeContext(@NotNull Change change) {
|
||||
return revTitlesMap;
|
||||
}
|
||||
};
|
||||
ShowDiffContext showDiffContext = ShowDiffContext.createStaticChangeContext(revTitlesMap);
|
||||
ShowDiffAction.showDiffForChange(project, changes, 0, showDiffContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static @NlsContexts.DialogTitle String getDialogTitle(@NotNull final FilePath filePath, @NotNull final String revNumTitle1,
|
||||
@NotNull final String revNumTitle2) {
|
||||
return VcsBundle.message("history.dialog.title.difference.between.versions.in",
|
||||
revNumTitle1,
|
||||
revNumTitle2,
|
||||
filePath.getName());
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
public static String getRevisionTitle(@NotNull @NlsSafe String revision, boolean localMark) {
|
||||
|
||||
@@ -944,7 +944,6 @@ git.log.diff.handler.failed.message={0} failed
|
||||
git.log.diff.handler.paths.diff.title=Changes Between {0} and {1} in {2}
|
||||
git.log.diff.handler.local.version.name=local version
|
||||
git.log.diff.handler.local.version.content.title=Local
|
||||
git.log.diff.handler.get.from.vcs.title=Get from VCS
|
||||
|
||||
git.log.refGroup.local=Local
|
||||
|
||||
|
||||
@@ -11,33 +11,15 @@ import com.intellij.diff.chains.SimpleDiffRequestProducer;
|
||||
import com.intellij.diff.contents.DiffContent;
|
||||
import com.intellij.diff.contents.EmptyContent;
|
||||
import com.intellij.diff.requests.SimpleDiffRequest;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.dvcs.actions.CompareWithLocalDialog;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogBuilder;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangesUtil;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.changes.ui.SimpleChangesBrowser;
|
||||
import com.intellij.openapi.vcs.changes.ui.browser.LoadingChangesPanel;
|
||||
import com.intellij.openapi.vcs.history.actions.GetVersionAction;
|
||||
import com.intellij.openapi.vcs.history.actions.GetVersionAction.FileRevisionProvider;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.StatusText;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcs.log.VcsLogDiffHandler;
|
||||
@@ -53,13 +35,9 @@ import git4idea.util.GitFileUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.diff.DiffRequestFactoryImpl.*;
|
||||
import static com.intellij.util.ObjectUtils.chooseNotNull;
|
||||
@@ -136,30 +114,14 @@ public class GitLogDiffHandler implements VcsLogDiffHandler {
|
||||
rightRevisionTitle,
|
||||
getTitleForPaths(root, affectedPaths));
|
||||
|
||||
Disposable loadingDisposable = Disposer.newDisposable();
|
||||
MyChangesBrowser changesBrowser = new MyChangesBrowser(myProject, isWithLocal);
|
||||
MyLoadingChangesPanel changesPanel = new MyLoadingChangesPanel(changesBrowser, loadingDisposable) {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<Change> loadChanges() throws VcsException {
|
||||
if (isWithLocal) {
|
||||
return GitChangeUtils.getDiffWithWorkingDir(myProject, root, leftRevision.asString(), filePaths, false);
|
||||
}
|
||||
else {
|
||||
return GitChangeUtils.getDiff(myProject, root, leftRevision.asString(), rightRevision.asString(), filePaths);
|
||||
}
|
||||
CompareWithLocalDialog.showDialog(myProject, dialogTitle, CompareWithLocalDialog.LocalContent.AFTER, () -> {
|
||||
if (isWithLocal) {
|
||||
return GitChangeUtils.getDiffWithWorkingDir(myProject, root, leftRevision.asString(), filePaths, false);
|
||||
}
|
||||
};
|
||||
changesPanel.reloadChanges();
|
||||
|
||||
DialogBuilder dialogBuilder = new DialogBuilder(myProject);
|
||||
dialogBuilder.setTitle(dialogTitle);
|
||||
dialogBuilder.setActionDescriptors(new DialogBuilder.CloseDialogAction());
|
||||
dialogBuilder.setCenterPanel(changesPanel);
|
||||
dialogBuilder.setPreferredFocusComponent(changesPanel.getChangesBrowser().getPreferredFocusedComponent());
|
||||
dialogBuilder.addDisposable(loadingDisposable);
|
||||
dialogBuilder.setDimensionServiceKey("Git.DiffForPathsDialog");
|
||||
dialogBuilder.showNotModal();
|
||||
else {
|
||||
return GitChangeUtils.getDiff(myProject, root, leftRevision.asString(), rightRevision.asString(), filePaths);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,129 +186,4 @@ public class GitLogDiffHandler implements VcsLogDiffHandler {
|
||||
GitRevisionNumber revisionNumber = new GitRevisionNumber(hash.asString());
|
||||
return GitContentRevision.createRevision(filePath, revisionNumber, myProject);
|
||||
}
|
||||
|
||||
private static abstract class MyLoadingChangesPanel extends JPanel implements DataProvider {
|
||||
public static final DataKey<MyLoadingChangesPanel> DATA_KEY = DataKey.create("git4idea.log.MyLoadingChangesPanel");
|
||||
|
||||
private final SimpleChangesBrowser myChangesBrowser;
|
||||
private final LoadingChangesPanel myLoadingPanel;
|
||||
|
||||
private MyLoadingChangesPanel(@NotNull SimpleChangesBrowser changesBrowser, @NotNull Disposable disposable) {
|
||||
super(new BorderLayout());
|
||||
|
||||
myChangesBrowser = changesBrowser;
|
||||
|
||||
StatusText emptyText = myChangesBrowser.getViewer().getEmptyText();
|
||||
myLoadingPanel = new LoadingChangesPanel(myChangesBrowser, emptyText, disposable);
|
||||
add(myLoadingPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SimpleChangesBrowser getChangesBrowser() {
|
||||
return myChangesBrowser;
|
||||
}
|
||||
|
||||
public void reloadChanges() {
|
||||
myLoadingPanel.loadChangesInBackground(this::loadChanges, this::applyResult);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract Collection<Change> loadChanges() throws VcsException;
|
||||
|
||||
private void applyResult(@Nullable Collection<Change> changes) {
|
||||
myChangesBrowser.setChangesToDisplay(changes != null ? changes : Collections.emptyList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getData(@NotNull String dataId) {
|
||||
if (DATA_KEY.is(dataId)) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyChangesBrowser extends SimpleChangesBrowser {
|
||||
public final boolean myIsWithLocal;
|
||||
|
||||
private MyChangesBrowser(@NotNull Project project, boolean isWithLocal) {
|
||||
super(project, false, true);
|
||||
myIsWithLocal = isWithLocal;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createToolbarActions() {
|
||||
return ContainerUtil.append(
|
||||
super.createToolbarActions(),
|
||||
new MyGetVersionAction()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<AnAction> createPopupMenuActions() {
|
||||
return ContainerUtil.append(
|
||||
super.createPopupMenuActions(),
|
||||
new MyGetVersionAction()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyGetVersionAction extends DumbAwareAction {
|
||||
private MyGetVersionAction() {
|
||||
super(VcsBundle.messagePointer("action.name.get.file.content.from.repository"),
|
||||
VcsBundle.messagePointer("action.description.get.file.content.from.repository"), AllIcons.Actions.Download);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
MyLoadingChangesPanel changesPanel = e.getData(MyLoadingChangesPanel.DATA_KEY);
|
||||
if (project == null || changesPanel == null) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MyChangesBrowser browser = ObjectUtils.tryCast(changesPanel.getChangesBrowser(), MyChangesBrowser.class);
|
||||
boolean isVisible = browser != null && browser.myIsWithLocal;
|
||||
boolean isEnabled = isVisible && !browser.getSelectedChanges().isEmpty();
|
||||
e.getPresentation().setVisible(isVisible);
|
||||
e.getPresentation().setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = Objects.requireNonNull(e.getProject());
|
||||
MyLoadingChangesPanel changesPanel = e.getRequiredData(MyLoadingChangesPanel.DATA_KEY);
|
||||
|
||||
List<FileRevisionProvider> fileContentProviders = ContainerUtil.map(changesPanel.getChangesBrowser().getSelectedChanges(),
|
||||
MyFileContentProvider::new);
|
||||
GetVersionAction.doGet(project, GitBundle.message("git.log.diff.handler.get.from.vcs.title"), fileContentProviders,
|
||||
() -> changesPanel.reloadChanges());
|
||||
}
|
||||
|
||||
private static class MyFileContentProvider implements FileRevisionProvider {
|
||||
@NotNull private final Change myChange;
|
||||
|
||||
private MyFileContentProvider(@NotNull Change change) {
|
||||
myChange = change;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FilePath getFilePath() {
|
||||
return ChangesUtil.getFilePath(myChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte @Nullable [] getContent() throws VcsException {
|
||||
ContentRevision revision = myChange.getBeforeRevision();
|
||||
if (revision == null) return null;
|
||||
|
||||
return ChangesUtil.loadContentRevision(revision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user