diff --git a/platform/dvcs-api/resources/messages/DvcsBundle.properties b/platform/dvcs-api/resources/messages/DvcsBundle.properties index 3dfd3d3511f7..a5f6dfb33d26 100644 --- a/platform/dvcs-api/resources/messages/DvcsBundle.properties +++ b/platform/dvcs-api/resources/messages/DvcsBundle.properties @@ -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=The following repositories already have specified {0}{1}:
{2}.
Do you want to checkout existing {3}? dialog.title.already.exists={0} Already Exists diff --git a/platform/dvcs-impl/intellij.platform.vcs.dvcs.impl.iml b/platform/dvcs-impl/intellij.platform.vcs.dvcs.impl.iml index fb6976340a14..b6a9a64df71d 100644 --- a/platform/dvcs-impl/intellij.platform.vcs.dvcs.impl.iml +++ b/platform/dvcs-impl/intellij.platform.vcs.dvcs.impl.iml @@ -24,5 +24,6 @@ + \ No newline at end of file diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/actions/CompareWithLocalDialog.java b/platform/dvcs-impl/src/com/intellij/dvcs/actions/CompareWithLocalDialog.java new file mode 100644 index 000000000000..7ae605034fa9 --- /dev/null +++ b/platform/dvcs-impl/src/com/intellij/dvcs/actions/CompareWithLocalDialog.java @@ -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 VcsException> changesLoader) { + Disposable loadingDisposable = Disposer.newDisposable(); + MyChangesBrowser changesBrowser = new MyChangesBrowser(project, localContent); + MyLoadingChangesPanel changesPanel = new MyLoadingChangesPanel(changesBrowser, loadingDisposable) { + @NotNull + @Override + protected Collection 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 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 loadChanges() throws VcsException; + + private void applyResult(@Nullable Collection 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 createToolbarActions() { + return ContainerUtil.append( + super.createToolbarActions(), + new MyGetVersionAction() + ); + } + + @NotNull + @Override + protected List 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 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} +} diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/actions/DvcsCompareWithBranchAction.java b/platform/dvcs-impl/src/com/intellij/dvcs/actions/DvcsCompareWithBranchAction.java index b70618f501f9..c94daa8e0635 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/actions/DvcsCompareWithBranchAction.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/actions/DvcsCompareWithBranchAction.java @@ -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 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 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 loadRequestProducers() throws DiffRequestProducerException { + try { + Collection 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, 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 diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffContext.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffContext.java index 2f81af36e652..fd842987b15b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffContext.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ShowDiffContext.java @@ -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, Object> map) { + return new ShowDiffContext() { + @NotNull + @Override + public Map, Object> getChangeContext(@NotNull Change change) { + return map; + } + }; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsDiffUtil.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsDiffUtil.java index 2143090d9d2c..a2c24ff15c71 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsDiffUtil.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/VcsDiffUtil.java @@ -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, 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, 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) { diff --git a/plugins/git4idea/resources/messages/GitBundle.properties b/plugins/git4idea/resources/messages/GitBundle.properties index 7a2c2ad3d5c1..02733642aad4 100644 --- a/plugins/git4idea/resources/messages/GitBundle.properties +++ b/plugins/git4idea/resources/messages/GitBundle.properties @@ -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 diff --git a/plugins/git4idea/src/git4idea/log/GitLogDiffHandler.java b/plugins/git4idea/src/git4idea/log/GitLogDiffHandler.java index f67ab245c699..925d0df8a7b0 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogDiffHandler.java +++ b/plugins/git4idea/src/git4idea/log/GitLogDiffHandler.java @@ -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 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 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 loadChanges() throws VcsException; - - private void applyResult(@Nullable Collection 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 createToolbarActions() { - return ContainerUtil.append( - super.createToolbarActions(), - new MyGetVersionAction() - ); - } - - @NotNull - @Override - protected List 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 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); - } - } - } }