IDEA-267354 git: show 'Merge' action on hover in Local Changes
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / ChangesViewPanel.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
3
4 import com.intellij.ide.DataManager
5 import com.intellij.ide.DefaultTreeExpander
6 import com.intellij.openapi.actionSystem.ActionManager
7 import com.intellij.openapi.actionSystem.ActionPlaces.CHANGES_VIEW_TOOLBAR
8 import com.intellij.openapi.actionSystem.ActionToolbar
9 import com.intellij.openapi.actionSystem.DefaultActionGroup
10 import com.intellij.openapi.project.Project
11 import com.intellij.openapi.vcs.changes.ui.ChangesBrowserNode
12 import com.intellij.openapi.vcs.changes.ui.ChangesListView
13 import com.intellij.openapi.vcs.changes.ui.HoverIcon
14 import com.intellij.ui.IdeBorderFactory.createBorder
15 import com.intellij.ui.JBColor
16 import com.intellij.ui.ScrollPaneFactory.createScrollPane
17 import com.intellij.ui.SideBorder
18 import com.intellij.util.EditSourceOnDoubleClickHandler.isToggleEvent
19 import com.intellij.util.OpenSourceUtil.openSourcesFrom
20 import com.intellij.util.Processor
21 import com.intellij.util.ui.JBUI.Panels.simplePanel
22 import com.intellij.util.ui.components.BorderLayoutPanel
23 import com.intellij.util.ui.tree.TreeUtil
24 import javax.swing.JComponent
25 import javax.swing.JTree
26 import javax.swing.SwingConstants
27 import kotlin.properties.Delegates.observable
28
29 class ChangesViewPanel(project: Project) : BorderLayoutPanel() {
30   val changesView: ChangesListView = MyChangesListView(project).apply {
31     treeExpander = object : DefaultTreeExpander(this) {
32       override fun collapseAll(tree: JTree, keepSelectionLevel: Int) {
33         super.collapseAll(tree, 2)
34         TreeUtil.expand(tree, 1)
35       }
36     }
37     doubleClickHandler = Processor { e ->
38       if (isToggleEvent(this, e)) return@Processor false
39
40       openSourcesFrom(DataManager.getInstance().getDataContext(this), true)
41       true
42     }
43     enterKeyHandler = Processor {
44       openSourcesFrom(DataManager.getInstance().getDataContext(this), false)
45       true
46     }
47   }
48
49   val toolbarActionGroup = DefaultActionGroup()
50
51   var isToolbarHorizontal: Boolean by observable(false) { _, oldValue, newValue ->
52     if (oldValue != newValue) {
53       addToolbar(newValue) // this also removes toolbar from previous parent
54     }
55   }
56
57   val toolbar: ActionToolbar =
58     ActionManager.getInstance().createActionToolbar(CHANGES_VIEW_TOOLBAR, toolbarActionGroup, isToolbarHorizontal).apply {
59       setTargetComponent(changesView)
60     }
61
62   var statusComponent by observable<JComponent?>(null) { _, oldValue, newValue ->
63     if (oldValue == newValue) return@observable
64
65     if (oldValue != null) centerPanel.remove(oldValue)
66     if (newValue != null) centerPanel.addToBottom(newValue)
67   }
68
69   private val centerPanel = simplePanel(createScrollPane(changesView))
70
71   init {
72     addToCenter(centerPanel)
73     addToolbar(isToolbarHorizontal)
74   }
75
76   private fun addToolbar(isHorizontal: Boolean) {
77     if (isHorizontal) {
78       toolbar.setOrientation(SwingConstants.HORIZONTAL)
79       centerPanel.border = createBorder(JBColor.border(), SideBorder.TOP)
80       addToTop(toolbar.component)
81     }
82     else {
83       toolbar.setOrientation(SwingConstants.VERTICAL)
84       centerPanel.border = createBorder(JBColor.border(), SideBorder.LEFT)
85       addToLeft(toolbar.component)
86     }
87   }
88
89   private class MyChangesListView(project: Project) : ChangesListView(project, false) {
90     override fun getHoverIcon(node: ChangesBrowserNode<*>): HoverIcon? {
91       return ChangesViewNodeAction.EP_NAME.computeSafeIfAny(project) { it.createNodeHoverIcon(node) }
92     }
93   }
94 }