vcs: non-modal: Make "Switch to Commit Dialog" action available in search everywhere
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / ui / ChangesViewToolWindowFactory.kt
1 // 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.
2 package com.intellij.openapi.vcs.changes.ui
3
4 import com.intellij.icons.AllIcons
5 import com.intellij.internal.statistic.collectors.fus.ui.GotItUsageCollector
6 import com.intellij.internal.statistic.collectors.fus.ui.GotItUsageCollectorGroup
7 import com.intellij.openapi.actionSystem.ActionGroup
8 import com.intellij.openapi.actionSystem.ActionManager
9 import com.intellij.openapi.actionSystem.ActionToolbar
10 import com.intellij.openapi.actionSystem.impl.ActionButton
11 import com.intellij.openapi.project.Project
12 import com.intellij.openapi.ui.popup.Balloon
13 import com.intellij.openapi.util.Disposer
14 import com.intellij.openapi.vcs.VcsBundle.message
15 import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager.Companion.COMMIT_TOOLWINDOW_ID
16 import com.intellij.openapi.wm.ToolWindow
17 import com.intellij.openapi.wm.ToolWindowManager
18 import com.intellij.openapi.wm.ex.ToolWindowEx
19 import com.intellij.openapi.wm.impl.content.ToolWindowContentUi.HIDE_ID_LABEL
20 import com.intellij.ui.GotItTooltip
21 import com.intellij.ui.awt.RelativePoint
22 import com.intellij.ui.awt.RelativePoint.getSouthOf
23 import com.intellij.util.ui.PositionTracker
24 import com.intellij.util.ui.UIUtil.uiTraverser
25 import com.intellij.util.ui.update.Activatable
26 import com.intellij.util.ui.update.UiNotifyConnector
27 import javax.swing.JComponent
28
29 private class ChangesViewToolWindowFactory : VcsToolWindowFactory() {
30   override fun updateState(project: Project, toolWindow: ToolWindow) {
31     super.updateState(project, toolWindow)
32     toolWindow.stripeTitle = project.vcsManager.allActiveVcss.singleOrNull()?.displayName ?: ChangesViewContentManager.TOOLWINDOW_ID
33   }
34 }
35
36 private class CommitToolWindowFactory : VcsToolWindowFactory() {
37   override fun init(window: ToolWindow) {
38     super.init(window)
39
40     window as ToolWindowEx
41     window.setAdditionalGearActions(ActionManager.getInstance().getAction("CommitView.GearActions") as ActionGroup)
42   }
43
44   override fun shouldBeAvailable(project: Project): Boolean {
45     return super.shouldBeAvailable(project) && project.isCommitToolWindowShown
46   }
47
48   override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
49     toolWindow.component.putClientProperty(HIDE_ID_LABEL, "true")
50     super.createToolWindowContent(project, toolWindow)
51   }
52 }
53
54 internal class SwitchToCommitDialogHint(private val toolWindow: ToolWindowEx, private val toolbar: ActionToolbar) :
55   ChangesViewContentManagerListener,
56   Activatable {
57
58   private val toolbarVisibilityTracker =
59     UiNotifyConnector(toolbar.component, this).also { Disposer.register(toolWindow.disposable, it) }
60   private var balloon: Balloon? = null
61
62   init {
63     toolWindow.project.messageBus.connect(toolbarVisibilityTracker).subscribe(ChangesViewContentManagerListener.TOPIC, this)
64   }
65
66   override fun showNotify() = showHint()
67   override fun hideNotify() = hideHint(false)
68
69   override fun toolWindowMappingChanged() = hideHint(true)
70
71   private fun showHint() {
72     val c : JComponent = toolbar.getGearButton() ?: toolbar.component
73     GotItTooltip("changes.view.toolwindow", message("switch.to.commit.dialog.hint.text"), toolbarVisibilityTracker).
74       setOnBalloonCreated { balloon = it }.
75       show(c, GotItTooltip.BOTTOM_MIDDLE)
76   }
77
78   private fun hideHint(dispose: Boolean) {
79     balloon?.hide(true)
80     GotItUsageCollector.instance.logClose("changes.view.toolwindow", GotItUsageCollectorGroup.CloseType.AncestorRemoved)
81     balloon = null
82
83     if (dispose) Disposer.dispose(toolbarVisibilityTracker)
84   }
85
86   companion object {
87     fun install(project: Project) {
88       val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(COMMIT_TOOLWINDOW_ID) as? ToolWindowEx ?: return
89       val toolbar = toolWindow.decorator.headerToolbar ?: return
90
91       SwitchToCommitDialogHint(toolWindow, toolbar)
92     }
93   }
94 }
95
96 private class SouthPositionTracker(private val component: JComponent) : PositionTracker<Balloon>(component) {
97   override fun recalculateLocation(balloon: Balloon): RelativePoint = getSouthOf(component)
98 }
99
100 private fun ActionToolbar.getGearButton(): ActionButton? =
101   uiTraverser(component)
102     .filter(ActionButton::class.java)
103     .filter { it.icon == AllIcons.General.GearPlain }
104     .first()