diff --git a/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java b/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java index 12e9a1cf0f88..886c40a0c5b2 100644 --- a/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java +++ b/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java @@ -39,6 +39,8 @@ public interface RepositoryManager { @Nullable T getRepositoryForRoot(@Nullable VirtualFile root); + boolean isExternal(@NotNull T repository); + /** * Returns the {@link Repository} which the given file belongs to, or {@code null} if the file is not under any Git or Hg repository. */ diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java index 96de75c17878..e0c4ea8dfca3 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsUtil.java @@ -27,12 +27,10 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.VcsKey; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.StatusBar; @@ -44,8 +42,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.TimedVcsCommit; -import com.intellij.vcs.log.VcsLog; -import com.intellij.vcs.log.VcsLogProvider; import org.intellij.images.editor.ImageFileEditor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -142,18 +138,6 @@ public class DvcsUtil { repositoryManager.getRepositories())); } - /** - * Checks if there are hg roots in the VCS log. - */ - public static boolean logHasRootForVcs(@NotNull VcsLog log, @Nullable final VcsKey vcsKey) { - return ContainerUtil.find(log.getLogProviders(), new Condition() { - @Override - public boolean value(VcsLogProvider logProvider) { - return logProvider.getSupportedVcs().equals(vcsKey); - } - }) != null; - } - @Nullable public static String joinMessagesOrNull(@NotNull Collection messages) { String joined = StringUtil.join(messages, "\n"); diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java index bea3508bc8c0..fb34150db89c 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/repo/AbstractRepositoryManager.java @@ -105,6 +105,17 @@ public abstract class AbstractRepositoryManager extends Ab } } + @Override + public boolean isExternal(@NotNull T repository) { + try { + REPO_LOCK.readLock().lock(); + return !myRepositories.containsValue(repository) && myExternalRepositories.containsValue(repository); + } + finally { + REPO_LOCK.readLock().unlock(); + } + } + @Override @Nullable public T getRepositoryForFile(@NotNull VirtualFile file) { diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/VcsLogAction.java b/platform/dvcs-impl/src/com/intellij/dvcs/ui/VcsLogAction.java index b6db95d54e86..23622c3f25e9 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/ui/VcsLogAction.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/VcsLogAction.java @@ -15,12 +15,16 @@ */ package com.intellij.dvcs.ui; +import com.intellij.dvcs.repo.AbstractRepositoryManager; import com.intellij.dvcs.repo.Repository; +import com.intellij.dvcs.repo.RepositoryManager; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsLog; @@ -33,7 +37,7 @@ import java.util.List; public abstract class VcsLogAction extends DumbAwareAction { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getRequiredData(CommonDataKeys.PROJECT); VcsLog log = e.getRequiredData(VcsLogDataKeys.VCS_LOG); List details = log.getSelectedDetails(); @@ -43,7 +47,7 @@ public abstract class VcsLogAction extends DumbAwareAct } @Override - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { Project project = e.getProject(); VcsLog log = e.getData(VcsLogDataKeys.VCS_LOG); if (project == null || log == null) { @@ -57,7 +61,7 @@ public abstract class VcsLogAction extends DumbAwareAct e.getPresentation().setEnabledAndVisible(false); } else { - e.getPresentation().setVisible(true); + e.getPresentation().setVisible(isVisible(project, grouped)); e.getPresentation().setEnabled(!grouped.isEmpty() && isEnabled(grouped)); } } @@ -66,6 +70,19 @@ public abstract class VcsLogAction extends DumbAwareAct protected abstract boolean isEnabled(@NotNull MultiMap grouped); + protected boolean isVisible(@NotNull final Project project, @NotNull MultiMap grouped) { + return ContainerUtil.and(grouped.keySet(), new Condition() { + @Override + public boolean value(Repo repo) { + RepositoryManager manager = getRepositoryManager(project); + return !manager.isExternal(repo); + } + }); + } + + @NotNull + protected abstract AbstractRepositoryManager getRepositoryManager(@NotNull Project project); + @Nullable protected abstract Repo getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root); diff --git a/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java index 83512de71d1f..1e6ba7de439f 100644 --- a/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java @@ -15,6 +15,7 @@ */ package git4idea.actions; +import com.intellij.dvcs.repo.AbstractRepositoryManager; import com.intellij.dvcs.ui.VcsLogSingleCommitAction; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; @@ -26,10 +27,16 @@ import org.jetbrains.annotations.Nullable; public abstract class GitLogSingleCommitAction extends VcsLogSingleCommitAction { + @NotNull + @Override + protected AbstractRepositoryManager getRepositoryManager(@NotNull Project project) { + return ServiceManager.getService(project, GitRepositoryManager.class); + } + @Override @Nullable protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { - return ServiceManager.getService(project, GitRepositoryManager.class).getRepositoryForRoot(root); + return getRepositoryManager(project).getRepositoryForRoot(root); } } diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java index 8162176ea3b0..3fd3446d0116 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java @@ -15,8 +15,9 @@ */ package git4idea.cherrypick; -import com.intellij.dvcs.DvcsUtil; +import com.intellij.dvcs.repo.RepositoryManager; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -25,9 +26,7 @@ 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.util.ThrowableComputable; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.util.Function; +import com.intellij.openapi.util.Condition; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import git4idea.GitLocalBranch; @@ -35,13 +34,9 @@ import git4idea.GitPlatformFacade; import git4idea.GitVcs; import git4idea.commands.Git; import git4idea.config.GitVcsSettings; -import git4idea.history.browser.GitHeavyCommit; -import git4idea.history.wholeTree.AbstractHash; -import git4idea.history.wholeTree.GitCommitDetailsProvider; import git4idea.repo.GitRepository; import icons.Git4ideaIcons; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.*; @@ -66,12 +61,9 @@ public class GitCherryPickAction extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { - final Project project = e.getProject(); - final List commits = getSelectedCommits(e); - if (project == null || commits == null || commits.isEmpty()) { - LOG.info(String.format("Cherry-pick action should be disabled. Project: %s, commits: %s", project, commits)); - return; - } + final Project project = e.getRequiredData(CommonDataKeys.PROJECT); + VcsLog log = e.getRequiredData(VcsLogDataKeys.VCS_LOG); + final List commits = log.getSelectedDetails(); for (VcsFullCommitDetails commit : commits) { myIdsInProgress.add(commit.getId()); @@ -136,24 +128,47 @@ public class GitCherryPickAction extends DumbAwareAction { } @Override - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { super.update(e); - VcsLog log = getVcsLog(e); + VcsLog log = e.getData(VcsLogDataKeys.VCS_LOG); Project project = getEventProject(e); - if (project == null || log == null || !DvcsUtil.logHasRootForVcs(log, GitVcs.getKey())) { + if (project == null || log == null || !logHasGitRoots(log)) { e.getPresentation().setEnabledAndVisible(false); + return; } - else { - e.getPresentation().setEnabled(enabled(e)); - e.getPresentation().setText(isAutoCommit(project) ? NAME : NAME + "..."); + + List details = log.getSelectedDetails(); + if (notFromGitAndProject(project, details)) { + e.getPresentation().setEnabledAndVisible(false); + return; } + + e.getPresentation().setEnabled(enabled(project, log, details)); + e.getPresentation().setText(isAutoCommit(project) ? NAME : NAME + "..."); } - private boolean enabled(AnActionEvent e) { - final List commits = getSelectedCommits(e); - final Project project = e.getProject(); + public static boolean logHasGitRoots(@NotNull VcsLog log) { + return ContainerUtil.find(log.getLogProviders(), new Condition() { + @Override + public boolean value(VcsLogProvider logProvider) { + return logProvider.getSupportedVcs().equals(GitVcs.getKey()); + } + }) != null; + } - if (commits == null || commits.isEmpty() || project == null) { + private boolean notFromGitAndProject(@NotNull Project project, @NotNull List details) { + final RepositoryManager manager = myPlatformFacade.getRepositoryManager(project); + return ContainerUtil.and(details, new Condition() { + @Override + public boolean value(VcsFullCommitDetails commit) { + GitRepository repository = manager.getRepositoryForRoot(commit.getRoot()); + return repository != null && manager.isExternal(repository); + } + }); + } + + private boolean enabled(@NotNull Project project, @NotNull VcsLog log, @NotNull List commits) { + if (commits.isEmpty()) { return false; } @@ -162,11 +177,9 @@ public class GitCherryPickAction extends DumbAwareAction { return false; } GitRepository repository = myPlatformFacade.getRepositoryManager(project).getRepositoryForRoot(commit.getRoot()); - if (repository == null) { - return false; - } + assert repository != null; GitLocalBranch currentBranch = repository.getCurrentBranch(); - Collection containingBranches = getContainingBranches(e, commit, repository); + Collection containingBranches = log.getContainingBranches(commit.getId()); if (currentBranch != null && containingBranches != null && containingBranches.contains(currentBranch.getName())) { // already is contained in the current branch return false; @@ -175,85 +188,4 @@ public class GitCherryPickAction extends DumbAwareAction { return true; } - // TODO remove after removing the old Vcs Log implementation - @Nullable - private List getSelectedCommits(AnActionEvent e) { - final Project project = e.getProject(); - if (project == null) { - return null; - } - List commits = e.getData(GitVcs.SELECTED_COMMITS); - if (commits != null) { - return convertHeavyCommitToFullDetails(commits, project); - } - final VcsLog log = getVcsLog(e); - if (log == null) { - return null; - } - - List selectedCommits = log.getSelectedCommits(); - List selectedDetails = ContainerUtil.newArrayList(); - for (Hash commit : selectedCommits) { - VcsFullCommitDetails details = log.getDetailsIfAvailable(commit); - if (details == null) { // let the action be unavailable until all details are loaded - return null; - } - GitRepository root = myPlatformFacade.getRepositoryManager(project).getRepositoryForRoot(details.getRoot()); - // don't allow to cherry-pick if a non-Git commit was selected - // we could cherry-pick just Git commits filtered from the list, but it might provide confusion - if (root == null) { - return null; - } - selectedDetails.add(details); - } - return selectedDetails; - } - - private static List convertHeavyCommitToFullDetails(List commits, final Project project) { - return ContainerUtil.map(commits, new Function() { - @Override - public VcsFullCommitDetails fun(GitHeavyCommit commit) { - final VcsLogObjectsFactory factory = ServiceManager.getService(project, VcsLogObjectsFactory.class); - List parents = ContainerUtil.map(commit.getParentsHashes(), new Function() { - @Override - public Hash fun(String hashValue) { - return factory.createHash(hashValue); - } - }); - final List changes = commit.getChanges(); - return factory.createFullDetails( - factory.createHash(commit.getHash().getValue()), parents, commit.getAuthorTime(), commit.getRoot(), commit.getSubject(), - commit.getAuthor(), commit.getAuthorEmail(), commit.getDescription(), commit.getCommitter(), commit.getCommitterEmail(), - commit.getDate().getTime(), new ThrowableComputable, Exception>() { - @Override - public Collection compute() throws Exception { - return changes; - } - } - ); - } - }); - } - - private static VcsLog getVcsLog(@NotNull AnActionEvent event) { - return event.getData(VcsLogDataKeys.VCS_LOG); - } - - // TODO remove after removing the old Vcs Log implementation - @Nullable - private static Collection getContainingBranches(AnActionEvent event, VcsFullCommitDetails commit, GitRepository repository) { - GitCommitDetailsProvider detailsProvider = event.getData(GitVcs.COMMIT_DETAILS_PROVIDER); - if (detailsProvider != null) { - return detailsProvider.getContainingBranches(repository.getRoot(), AbstractHash.create(commit.getId().toShortString())); - } - if (event.getProject() == null) { - return null; - } - VcsLog log = getVcsLog(event); - if (log == null) { - return null; - } - return log.getContainingBranches(commit.getId()); - } - } diff --git a/plugins/git4idea/src/git4idea/reset/GitResetAction.java b/plugins/git4idea/src/git4idea/reset/GitResetAction.java index 97b5b4ffeae8..bb456c078e20 100644 --- a/plugins/git4idea/src/git4idea/reset/GitResetAction.java +++ b/plugins/git4idea/src/git4idea/reset/GitResetAction.java @@ -15,7 +15,9 @@ */ package git4idea.reset; +import com.intellij.dvcs.repo.AbstractRepositoryManager; import com.intellij.dvcs.ui.VcsLogOneCommitPerRepoAction; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; @@ -24,15 +26,20 @@ import com.intellij.util.ObjectUtils; import com.intellij.vcs.log.VcsFullCommitDetails; import git4idea.config.GitVcsSettings; import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; -import static git4idea.GitUtil.getRepositoryManager; - public class GitResetAction extends VcsLogOneCommitPerRepoAction { + @NotNull + @Override + protected AbstractRepositoryManager getRepositoryManager(@NotNull Project project) { + return ServiceManager.getService(project, GitRepositoryManager.class); + } + @Nullable @Override protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java index 43ef70ed2446..82ff61194c2a 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java @@ -16,6 +16,7 @@ package org.zmlx.hg4idea.action; +import com.intellij.dvcs.repo.AbstractRepositoryManager; import com.intellij.dvcs.ui.VcsLogSingleCommitAction; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; @@ -27,10 +28,16 @@ import org.zmlx.hg4idea.repo.HgRepositoryManager; public abstract class HgLogSingleCommitAction extends VcsLogSingleCommitAction { + @NotNull + @Override + protected AbstractRepositoryManager getRepositoryManager(@NotNull Project project) { + return ServiceManager.getService(project, HgRepositoryManager.class); + } + @Nullable @Override protected HgRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { - return ServiceManager.getService(project, HgRepositoryManager.class).getRepositoryForRoot(root); + return getRepositoryManager(project).getRepositoryForRoot(root); } }