diff --git a/plugins/git4idea/resources/intellij.vcs.git.xml b/plugins/git4idea/resources/intellij.vcs.git.xml
index 18575b73e620..d7293207f9ac 100644
--- a/plugins/git4idea/resources/intellij.vcs.git.xml
+++ b/plugins/git4idea/resources/intellij.vcs.git.xml
@@ -486,6 +486,8 @@
+
+
diff --git a/plugins/git4idea/src/git4idea/ui/toolbar/GitMainToolbarActions.kt b/plugins/git4idea/src/git4idea/ui/toolbar/GitMainToolbarActions.kt
new file mode 100644
index 000000000000..5400d8feef8d
--- /dev/null
+++ b/plugins/git4idea/src/git4idea/ui/toolbar/GitMainToolbarActions.kt
@@ -0,0 +1,157 @@
+// Copyright 2000-2024 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.push.VcsPushAction
+import com.intellij.icons.AllIcons
+import com.intellij.ide.HelpTooltip
+import com.intellij.ide.ui.laf.darcula.ui.ToolbarComboWidgetUiSizes
+import com.intellij.idea.AppMode
+import com.intellij.openapi.actionSystem.*
+import com.intellij.openapi.actionSystem.ex.ActionUtil
+import com.intellij.openapi.actionSystem.ex.CustomComponentAction
+import com.intellij.openapi.actionSystem.impl.ActionButton
+import com.intellij.openapi.actionSystem.impl.ActionButtonWithText
+import com.intellij.openapi.keymap.KeymapUtil
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.NlsSafe
+import com.intellij.openapi.vcs.update.CommonUpdateProjectAction
+import com.intellij.util.ui.JBUI
+import com.intellij.util.ui.JBUI.CurrentTheme.RunWidget.toolbarHeight
+import com.intellij.util.ui.JBUI.insets
+import com.intellij.util.ui.JBUI.size
+import git4idea.branch.GitBranchIncomingOutgoingManager
+import git4idea.branch.GitIncomingOutgoingColors
+import git4idea.branch.IncomingOutgoingState
+import git4idea.branch.calcTooltip
+import git4idea.i18n.GitBundle
+import git4idea.repo.GitRepository
+import git4idea.ui.toolbar.GitMainToolbar.showIncomingOutgoing
+import icons.DvcsImplIcons
+import org.jetbrains.annotations.ApiStatus
+import java.awt.Color
+import java.awt.Insets
+import javax.swing.JComponent
+
+class GitMainToolbarPushAction : VcsPushAction() {
+ init {
+ ActionUtil.copyFrom(this, "Vcs.Push")
+ templatePresentation.putClientProperty(ActionUtil.COMPONENT_PROVIDER, ButtonWithCustomForeground(this, GitIncomingOutgoingColors.OUTGOING_FOREGROUND))
+ }
+
+ override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
+
+ override fun update(e: AnActionEvent) {
+ super.update(e)
+ if (!e.presentation.isVisible) return
+
+ val project = e.project
+ if (project == null || e.place != ActionPlaces.MAIN_TOOLBAR) {
+ e.presentation.isEnabledAndVisible = false
+ return
+ }
+
+ e.presentation.icon = AllIcons.Vcs.Push
+ e.presentation.text = ""
+ e.presentation.putClientProperty(ActionButton.CUSTOM_HELP_TOOLTIP, null)
+ if (!showIncomingOutgoing) return
+
+ val repository = getCurrentRepository(project, e.dataContext) ?: return
+ e.presentation.icon = DvcsImplIcons.OutgoingPush
+
+ val incomingOutgoingState = getIncomingOutgoingState(project, repository) ?: return
+ val totalOutgoing = incomingOutgoingState.totalOutgoing()
+
+ if (totalOutgoing != 0) {
+ e.presentation.text = totalOutgoing.shrinkTo99()
+ }
+
+ val helpTooltip = HelpTooltip()
+ .setTitle(GitBundle.message("MainToolbarQuickActions.Git.Push.text"))
+ .setShortcut(KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("Vcs.Push")))
+ .setDescription(incomingOutgoingState.calcTooltip())
+ e.presentation.putClientProperty(ActionButton.CUSTOM_HELP_TOOLTIP, helpTooltip)
+ }
+}
+
+class GitMainToolbarUpdateProjectAction : CommonUpdateProjectAction() {
+ init {
+ ActionUtil.copyFrom(this, "Vcs.UpdateProject")
+ templatePresentation.putClientProperty(ActionUtil.COMPONENT_PROVIDER, ButtonWithCustomForeground(this, GitIncomingOutgoingColors.INCOMING_FOREGROUND))
+ }
+
+ override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
+
+ override fun update(e: AnActionEvent) {
+ super.update(e)
+ if (!e.presentation.isVisible) return
+
+ val project = e.project
+ if (project == null || e.place != ActionPlaces.MAIN_TOOLBAR) {
+ e.presentation.isEnabledAndVisible = false
+ return
+ }
+
+ e.presentation.icon = AllIcons.Actions.CheckOut
+ e.presentation.text = ""
+ e.presentation.putClientProperty(ActionButton.CUSTOM_HELP_TOOLTIP, null)
+ if (!showIncomingOutgoing) return
+
+ val repository = getCurrentRepository(project, e.dataContext) ?: return
+ e.presentation.icon = DvcsImplIcons.IncomingUpdate
+ val incomingOutgoingState = getIncomingOutgoingState(project, repository) ?: return
+ val totalIncoming = incomingOutgoingState.totalIncoming()
+
+ if (totalIncoming != 0) {
+ e.presentation.text = totalIncoming.shrinkTo99()
+ }
+
+ val helpTooltip = HelpTooltip()
+ .setTitle(GitBundle.message("MainToolbarQuickActions.Git.Update.text"))
+ .setShortcut(KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("Vcs.UpdateProject")))
+ .setDescription(incomingOutgoingState.calcTooltip())
+ e.presentation.putClientProperty(ActionButton.CUSTOM_HELP_TOOLTIP, helpTooltip)
+ }
+}
+
+private class ButtonWithCustomForeground(
+ private val action: AnAction,
+ private val fg: Color,
+) : CustomComponentAction {
+ override fun updateCustomComponent(component: JComponent, presentation: Presentation) {
+ component.foreground = fg
+ component.border = JBUI.Borders.empty(1, 0)
+ }
+
+ override fun createCustomComponent(presentation: Presentation, place: String): JComponent {
+ return object : ActionButtonWithText(action, presentation, place, {
+ size(16, toolbarHeight())
+ }) {
+ override fun iconTextSpace(): Int {
+ if (this.text.isBlank()) return 0
+ return ToolbarComboWidgetUiSizes.gapAfterLeftIcons
+ }
+
+ override fun getMargins(): Insets = insets(0, 7)
+ }
+ }
+}
+
+private fun getCurrentRepository(project: Project, dataContext: DataContext): GitRepository? {
+ val state = GitToolbarWidgetAction.getWidgetState(project, dataContext)
+ if (state !is GitToolbarWidgetAction.GitWidgetState.Repo) return null
+ return state.repository
+}
+
+private fun getIncomingOutgoingState(project: Project, repository: GitRepository): IncomingOutgoingState? {
+ val currentBranch = repository.currentBranch ?: return null
+ val incomingOutgoingManager = GitBranchIncomingOutgoingManager.getInstance(project)
+ return incomingOutgoingManager.getIncomingOutgoingState(repository, currentBranch)
+}
+
+private fun Int.shrinkTo99(): @NlsSafe String = if (this > 99) "99+" else this.toString()
+
+@ApiStatus.Internal
+internal object GitMainToolbar {
+ val showIncomingOutgoing: Boolean // todo: registry, setting or something else
+ get() = !AppMode.isRemoteDevHost()
+}
diff --git a/plugins/git4idea/src/git4idea/ui/toolbar/GitQuickActions.kt b/plugins/git4idea/src/git4idea/ui/toolbar/GitQuickActions.kt
index 3cf1aa30ccf2..733ba5c36d2e 100644
--- a/plugins/git4idea/src/git4idea/ui/toolbar/GitQuickActions.kt
+++ b/plugins/git4idea/src/git4idea/ui/toolbar/GitQuickActions.kt
@@ -10,9 +10,9 @@ import git4idea.i18n.GitBundle
private val insertStrategy = GroupEnd("MainToolbarNewUI", "MainToolbarVCSGroup")
.orElse(GroupEnd("MainToolbarNewUI", IdeActions.GROUP_MAIN_TOOLBAR_LEFT))
-class UpdateQuickAction: ToolbarAddQuickActionInfo(listOf("Vcs.UpdateProject"), GitBundle.message("MainToolbarQuickActions.Git.Update.text"), AllIcons.Actions.CheckOut, insertStrategy)
+class UpdateQuickAction: ToolbarAddQuickActionInfo(listOf("main.toolbar.git.Update"), GitBundle.message("MainToolbarQuickActions.Git.Update.text"), AllIcons.Actions.CheckOut, insertStrategy)
class CommitQuickAction: ToolbarAddQuickActionInfo(listOf("CheckinProject"), GitBundle.message("MainToolbarQuickActions.Git.Commit.text"), AllIcons.Actions.Commit, insertStrategy)
-class PushQuickAction: ToolbarAddQuickActionInfo(listOf("Vcs.Push"), GitBundle.message("MainToolbarQuickActions.Git.Push.text"), AllIcons.Vcs.Push, insertStrategy)
+class PushQuickAction: ToolbarAddQuickActionInfo(listOf("main.toolbar.git.Push"), GitBundle.message("MainToolbarQuickActions.Git.Push.text"), AllIcons.Vcs.Push, insertStrategy)
class DiffQuickAction: ToolbarAddQuickActionInfo(listOf("Compare.SameVersion"), GitBundle.message("MainToolbarQuickActions.Git.Diff.text"), AllIcons.Actions.Diff, insertStrategy)
class HistoryQuickAction: ToolbarAddQuickActionInfo(listOf("Vcs.ShowTabbedFileHistory"), GitBundle.message("MainToolbarQuickActions.Git.History.text"), AllIcons.Vcs.History, insertStrategy)
class RollbackQuickAction: ToolbarAddQuickActionInfo(listOf("ChangesView.Revert"), GitBundle.message("MainToolbarQuickActions.Git.Rollback.text"), AllIcons.Diff.Revert, insertStrategy)
diff --git a/plugins/git4idea/src/git4idea/ui/toolbar/GitToolbarWidgetAction.kt b/plugins/git4idea/src/git4idea/ui/toolbar/GitToolbarWidgetAction.kt
index ed474f84694c..c0b221cea96c 100644
--- a/plugins/git4idea/src/git4idea/ui/toolbar/GitToolbarWidgetAction.kt
+++ b/plugins/git4idea/src/git4idea/ui/toolbar/GitToolbarWidgetAction.kt
@@ -142,17 +142,21 @@ internal class GitToolbarWidgetAction : ExpandableComboAction(), DumbAware {
}
}
- val rightIcons = mutableListOf()
- if (syncStatus?.incoming == true) {
- rightIcons.add(DvcsImplIcons.Incoming)
+ if (!GitMainToolbar.showIncomingOutgoing) {
+ val rightIcons = mutableListOf()
+ if (syncStatus?.incoming == true) {
+ rightIcons.add(DvcsImplIcons.Incoming)
+ }
+ if (syncStatus?.outgoing == true) {
+ rightIcons.add(DvcsImplIcons.Outgoing)
+ }
+ e.presentation.putClientProperty(ActionUtil.SECONDARY_ICON, when {
+ rightIcons.isNotEmpty() -> RowIcon(*rightIcons.toTypedArray())
+ else -> null
+ })
+ } else {
+ e.presentation.putClientProperty(ActionUtil.SECONDARY_ICON, null)
}
- if (syncStatus?.outgoing == true) {
- rightIcons.add(DvcsImplIcons.Outgoing)
- }
- e.presentation.putClientProperty(ActionUtil.SECONDARY_ICON, when {
- rightIcons.isNotEmpty() -> RowIcon(*rightIcons.toTypedArray())
- else -> null
- })
}
companion object {