git: support particular selected repository in a multi-root project in branches tree popup (IDEA-311758)

GitOrigin-RevId: 7d62b45f3fe53fd03475900cf121a26ea059648a
This commit is contained in:
Dmitry Zhuravlev
2023-02-02 17:25:56 +00:00
committed by intellij-monorepo-bot
parent 09fe20b21c
commit dcef9d4eeb
9 changed files with 82 additions and 45 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch
import com.intellij.dvcs.repo.Repository
@@ -65,7 +65,7 @@ open class GitBranchWidget(project: Project) : DvcsStatusWidget<GitRepository>(p
override fun getWidgetPopup(project: Project, repository: GitRepository): JBPopup {
branchWidgetClicked()
return if (isEnabled()) {
create(project)
create(project, repository)
}
else {
GitBranchPopup.getInstance(project, repository, DataManager.getInstance().getDataContext(myStatusBar!!.component)).asListPopup()
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
@@ -36,14 +22,14 @@ public class GitBranchesAction extends DumbAwareAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getRequiredData(CommonDataKeys.PROJECT);
GitRepository repository = GitBranchUtil.guessRepositoryForOperation(project, e.getDataContext());
if (repository == null) return;
if (GitBranchesTreePopup.isEnabled()) {
GitBranchesTreePopup.show(project);
GitBranchesTreePopup.show(project, repository);
}
else {
GitRepository repository = GitBranchUtil.guessRepositoryForOperation(project, e.getDataContext());
if (repository != null) {
GitBranchPopup.getInstance(project, repository, e.getDataContext()).asListPopup().showCenteredInCurrentWindow(project);
}
GitBranchPopup.getInstance(project, repository, e.getDataContext()).asListPopup().showCenteredInCurrentWindow(project);
}
}
@@ -701,15 +701,23 @@ class GitBranchesTreePopup(project: Project, step: GitBranchesTreePopupStep, par
@JvmStatic
fun isEnabled() = true
/**
* @param selectedRepository - Selected repository:
* e.g. [git4idea.branch.GitBranchUtil.guessRepositoryForOperation] or [git4idea.branch.GitBranchUtil.guessWidgetRepository]
*/
@JvmStatic
fun show(project: Project) {
create(project).showCenteredInCurrentWindow(project)
fun show(project: Project, selectedRepository: GitRepository?) {
create(project, selectedRepository).showCenteredInCurrentWindow(project)
}
/**
* @param selectedRepository - Selected repository:
* e.g. [git4idea.branch.GitBranchUtil.guessRepositoryForOperation] or [git4idea.branch.GitBranchUtil.guessWidgetRepository]
*/
@JvmStatic
fun create(project: Project): JBPopup {
fun create(project: Project, selectedRepository: GitRepository?): JBPopup {
val repositories = GitRepositoryManager.getInstance(project).repositories
return GitBranchesTreePopup(project, GitBranchesTreePopupStep(project, repositories, true))
return GitBranchesTreePopup(project, GitBranchesTreePopupStep(project, selectedRepository, repositories, true))
}
@JvmStatic
@@ -1,10 +1,10 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch.popup
import git4idea.ui.branch.tree.GitBranchesTreeRenderer
class GitBranchesTreePopupRenderer(private val step: GitBranchesTreePopupStep) :
GitBranchesTreeRenderer(step.project, step.treeModel, step.repositories) {
GitBranchesTreeRenderer(step.project, step.treeModel, step.selectedRepository, step.repositories) {
override fun hasRightArrow(nodeUserObject: Any?): Boolean = step.hasSubstep(nodeUserObject)
}
@@ -25,12 +25,14 @@ import com.intellij.util.containers.FList
import git4idea.GitBranch
import git4idea.GitVcs
import git4idea.actions.branch.GitBranchActionsUtil
import git4idea.actions.branch.GitBranchActionsUtil.userWantsSyncControl
import git4idea.repo.GitRepository
import git4idea.ui.branch.GitBranchPopupActions.EXPERIMENTAL_BRANCH_POPUP_ACTION_GROUP
import git4idea.ui.branch.tree.*
import javax.swing.tree.TreePath
class GitBranchesTreePopupStep(internal val project: Project,
internal val selectedRepository: GitRepository?,
internal val repositories: List<GitRepository>,
private val isFirstStep: Boolean) : PopupStep<Any> {
@@ -66,6 +68,10 @@ class GitBranchesTreePopupStep(internal val project: Project,
}
private fun createTreeModel(filterActive: Boolean): GitBranchesTreeModel {
return when {
!filterActive && repositories.size > 1
&& !userWantsSyncControl(project) && selectedRepository != null -> {
GitBranchesTreeSelectedRepoModel(project, selectedRepository, repositories, topLevelItems)
}
filterActive && repositories.size > 1 -> GitBranchesTreeMultiRepoFilteringModel(project, repositories, topLevelItems)
!filterActive && repositories.size > 1 -> GitBranchesTreeMultiRepoModel(project, repositories, topLevelItems)
else -> GitBranchesTreeSingleRepoModel(project, repositories.first(), topLevelItems)
@@ -86,7 +92,7 @@ class GitBranchesTreePopupStep(internal val project: Project,
fun isBranchesDiverged(): Boolean {
return repositories.size > 1
&& repositories.diverged()
&& GitBranchActionsUtil.userWantsSyncControl(project)
&& userWantsSyncControl(project)
}
fun getPreferredSelection(): TreePath? {
@@ -138,7 +144,7 @@ class GitBranchesTreePopupStep(internal val project: Project,
override fun onChosen(selectedValue: Any?, finalChoice: Boolean): PopupStep<out Any>? {
if (selectedValue is GitRepository) {
return GitBranchesTreePopupStep(project, listOf(selectedValue), false)
return GitBranchesTreePopupStep(project, null, listOf(selectedValue), false)
}
val branchUnderRepository = selectedValue as? GitBranchesTreeModel.BranchUnderRepository
@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch.tree
import com.intellij.dvcs.DvcsUtil
@@ -46,6 +46,7 @@ import javax.swing.tree.TreePath
abstract class GitBranchesTreeRenderer(private val project: Project,
private val treeModel: GitBranchesTreeModel,
private val selectedRepository: GitRepository?,
private val repositories: List<GitRepository>) : TreeCellRenderer {
private val colorManager = RepositoryChangesBrowserNode.getColorManager(project)
@@ -76,9 +77,13 @@ abstract class GitBranchesTreeRenderer(private val project: Project,
}
private fun getBranchIcon(branch: GitBranch, repositories: List<GitRepository>, isSelected: Boolean): Icon {
val isCurrent = repositories.all { it.currentBranch == branch }
val isCurrent =
selectedRepository?.let { it.currentBranch == branch } ?: repositories.all { it.currentBranch == branch }
val branchManager = project.service<GitBranchManager>()
val isFavorite = repositories.all { branchManager.isFavorite(GitBranchType.of(branch), it, branch.name) }
val isFavorite =
selectedRepository?.let { branchManager.isFavorite(GitBranchType.of(branch), it, branch.name) }
?: repositories.all { branchManager.isFavorite(GitBranchType.of(branch), it, branch.name) }
return when {
isSelected && isFavorite -> AllIcons.Nodes.Favorite
@@ -297,14 +302,24 @@ abstract class GitBranchesTreeRenderer(private val project: Project,
@JvmField
internal val MAIN_ICON = Key.create<Boolean>("MAIN_ICON")
internal fun getText(treeNode: Any?, treeModel: GitBranchesTreeModel, repositories: List<GitRepository>): @NlsSafe String? {
internal fun getText(treeNode: Any?, model: GitBranchesTreeModel, repositories: List<GitRepository>): @NlsSafe String? {
val value = treeNode ?: return null
return when (value) {
GitBranchType.LOCAL -> {
if (repositories.size > 1) GitBundle.message("common.local.branches") else GitBundle.message("group.Git.Local.Branch.title")
when {
model is GitBranchesTreeSelectedRepoModel -> GitBundle.message("branches.local.branches.in.repo",
DvcsUtil.getShortRepositoryName(model.selectedRepository))
repositories.size > 1 -> GitBundle.message("common.local.branches")
else -> GitBundle.message("group.Git.Local.Branch.title")
}
}
GitBranchType.REMOTE -> {
if (repositories.size > 1) GitBundle.message("common.remote.branches") else GitBundle.message("group.Git.Remote.Branch.title")
when {
model is GitBranchesTreeSelectedRepoModel -> GitBundle.message("branches.remote.branches.in.repo",
DvcsUtil.getShortRepositoryName(model.selectedRepository))
repositories.size > 1 -> GitBundle.message("common.remote.branches")
else -> GitBundle.message("group.Git.Remote.Branch.title")
}
}
is GitBranchesTreeModel.BranchesPrefixGroup -> value.prefix.last()
is GitRepository -> DvcsUtil.getShortRepositoryName(value)
@@ -314,8 +329,8 @@ abstract class GitBranchesTreeRenderer(private val project: Project,
GitBranchType.REMOTE -> GitBundle.message("group.Git.Remote.Branch.title")
}
}
is BranchUnderRepository -> getText(value.branch, treeModel, repositories)
is GitBranch -> if (treeModel.isPrefixGrouping) value.name.split('/').last() else value.name
is BranchUnderRepository -> getText(value.branch, model, repositories)
is GitBranch -> if (model.isPrefixGrouping) value.name.split('/').last() else value.name
is PopupFactoryImpl.ActionItem -> value.text
else -> null
}
@@ -0,0 +1,22 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch.tree
import com.intellij.openapi.project.Project
import git4idea.branch.GitBranchType
import git4idea.repo.GitRepository
import git4idea.ui.branch.popup.GitBranchesTreePopup
class GitBranchesTreeSelectedRepoModel(
project: Project,
selectedRepository: GitRepository,
private val repositories: List<GitRepository>,
topLevelActions: List<Any> = emptyList()
) : GitBranchesTreeSingleRepoModel(project, selectedRepository, topLevelActions) {
val selectedRepository get() = repository
private val branchesSubtreeSeparator = GitBranchesTreePopup.createTreeSeparator()
override fun getTopLevelNodes(): List<Any> {
return topLevelActions + repositories + branchesSubtreeSeparator + GitBranchType.LOCAL + GitBranchType.REMOTE
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.branch.tree
import com.intellij.dvcs.branch.GroupingKey.GROUPING_BY_DIRECTORY
@@ -15,10 +15,10 @@ import git4idea.ui.branch.tree.GitBranchesTreeModel.*
import javax.swing.tree.TreePath
import kotlin.properties.Delegates.observable
class GitBranchesTreeSingleRepoModel(
open class GitBranchesTreeSingleRepoModel(
private val project: Project,
private val repository: GitRepository,
private val topLevelActions: List<Any> = emptyList()
protected val repository: GitRepository,
protected val topLevelActions: List<Any> = emptyList()
) : AbstractTreeModel(), GitBranchesTreeModel {
private val branchManager = project.service<GitBranchManager>()
@@ -73,7 +73,7 @@ class GitBranchesTreeSingleRepoModel(
}
}
private fun getTopLevelNodes(): List<Any> {
protected open fun getTopLevelNodes(): List<Any> {
return topLevelActions + GitBranchType.LOCAL + GitBranchType.REMOTE
}
@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package git4idea.ui.toolbar
import com.intellij.dvcs.repo.Repository
@@ -44,7 +44,7 @@ internal class GitToolbarWidgetAction : ExpandableComboAction() {
val repository = GitBranchUtil.guessWidgetRepository(project, event.dataContext)
val popup: JBPopup = if (repository != null) {
if (GitBranchesTreePopup.isEnabled()) GitBranchesTreePopup.create(project)
if (GitBranchesTreePopup.isEnabled()) GitBranchesTreePopup.create(project, repository)
else GitBranchPopup.getInstance(project, repository, event.dataContext).asListPopup()
}
else {