5647529c31ca33b2b184987ceb5ed3b1c56929dd
[idea/community.git] / platform / execution-impl / src / com / intellij / execution / runToolbar / RunToolbarMainWidgetComponent.kt
1 // Copyright 2000-2021 JetBrains s.r.o. and contributors. 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.execution.runToolbar
3
4 import com.intellij.execution.runToolbar.data.RWSlotManagerState
5 import com.intellij.execution.runToolbar.data.RWStateListener
6 import com.intellij.ide.DataManager
7 import com.intellij.openapi.actionSystem.ActionGroup
8 import com.intellij.openapi.actionSystem.AnAction
9 import com.intellij.openapi.actionSystem.DataProvider
10 import com.intellij.openapi.actionSystem.Presentation
11 import com.intellij.openapi.diagnostic.Logger
12 import com.intellij.openapi.project.Project
13 import com.intellij.openapi.util.Disposer
14 import com.intellij.openapi.wm.IdeFrame
15 import java.awt.event.ContainerEvent
16 import java.awt.event.ContainerListener
17 import javax.swing.SwingUtilities
18
19 class RunToolbarMainWidgetComponent(val presentation: Presentation, place: String, group: ActionGroup) :
20   FixWidthSegmentedActionToolbarComponent(place, group) {
21   companion object {
22     private val LOG = Logger.getInstance(RunToolbarMainWidgetComponent::class.java)
23     private var counter: MutableMap<Project, Int> = mutableMapOf()
24   }
25
26   override fun logNeeded(): Boolean = RunToolbarProcess.logNeeded
27
28   private var project: Project? = null
29     set(value) {
30       if(field == value) return
31       field?.let {
32         remove(it)
33       }
34
35       field = value
36
37       field?.let {
38         add(it)
39       }
40     }
41
42   private var popupController: RunToolbarPopupController? = null
43
44   private val componentListener = object : ContainerListener {
45     override fun componentAdded(e: ContainerEvent) {
46       rebuildPopupControllerComponent()
47     }
48
49     override fun componentRemoved(e: ContainerEvent) {
50       rebuildPopupControllerComponent()
51     }
52   }
53
54   private val managerStateListener = object : RWStateListener {
55     override fun stateChanged(state: RWSlotManagerState) {
56       updateState()
57     }
58   }
59
60   private var state: RunToolbarMainSlotState? = null
61
62   private fun updateState() {
63     state = project?.let {
64       val slotManager = RunToolbarSlotManager.getInstance(it)
65       val value = when (slotManager.getState()) {
66         RWSlotManagerState.SINGLE_MAIN -> {
67           RunToolbarMainSlotState.PROCESS
68         }
69         RWSlotManagerState.SINGLE_PLAIN,
70         RWSlotManagerState.MULTIPLE -> {
71           if(isOpened) RunToolbarMainSlotState.CONFIGURATION else RunToolbarMainSlotState.INFO
72         }
73         RWSlotManagerState.INACTIVE -> {
74           RunToolbarMainSlotState.CONFIGURATION
75         }
76         RWSlotManagerState.MULTIPLE_WITH_MAIN -> {
77           if(isOpened) RunToolbarMainSlotState.PROCESS else RunToolbarMainSlotState.INFO
78         }
79       }
80
81       value
82     }
83
84     if(RunToolbarProcess.logNeeded) LOG.info("MAIN SLOT state updated: $state RunToolbar")
85   }
86
87   override fun traceState(lastIds: List<String>, filteredIds: List<String>, ides: List<String>) {
88     if(logNeeded() && filteredIds != lastIds) LOG.info("MAIN SLOT state: ${state} new filtered: ${filteredIds}} visible: $ides RunToolbar")
89   }
90
91   internal var isOpened = false
92     set(value) {
93       if(field == value) return
94
95       field = value
96       if(RunToolbarProcess.logNeeded) LOG.info("MAIN SLOT isOpened: $isOpened RunToolbar")
97       updateState()
98
99       if (RunToolbarProcess.isExperimentalUpdatingEnabled) {
100         forceUpdate()
101       }
102     }
103
104   override fun isSuitableAction(action: AnAction): Boolean {
105     return state?.let {
106       if(action is RTBarAction) {
107         action.checkMainSlotVisibility(it)
108       } else true
109     } ?: true
110   }
111
112   override fun addNotify() {
113     super.addNotify()
114
115     (SwingUtilities.getWindowAncestor(this) as? IdeFrame)?.project?.let {
116       project = it
117
118       RUN_CONFIG_WIDTH = RunToolbarSettings.getInstance(it).getRunConfigWidth()
119
120     }
121   }
122
123   override fun updateWidthHandler() {
124     super.updateWidthHandler()
125     project?.let {
126       RunToolbarSettings.getInstance(it).setRunConfigWidth(RUN_CONFIG_WIDTH)
127     }
128   }
129
130   private fun rebuildPopupControllerComponent() {
131     popupController?.let {
132       it.updateControllerComponents(components.filter{it is PopupControllerComponent}.toMutableList())
133     }
134   }
135
136   override fun removeNotify() {
137     project = null
138     super.removeNotify()
139   }
140
141   private fun add(project: Project) {
142     popupController = RunToolbarPopupController(project, this)
143
144     val value = counter.getOrDefault(project, 0) + 1
145     counter[project] = value
146     val slotManager = RunToolbarSlotManager.getInstance(project)
147     DataManager.registerDataProvider(component, DataProvider { key ->
148       when {
149         RunToolbarData.RUN_TOOLBAR_DATA_KEY.`is`(key) -> {
150           slotManager.mainSlotData
151         }
152         RunToolbarData.RUN_TOOLBAR_POPUP_STATE_KEY.`is`(key) -> {
153           isOpened
154         }
155         RunToolbarData.RUN_TOOLBAR_MAIN_STATE.`is`(key) -> {
156           state
157         }
158         else -> null
159       }
160     })
161
162     if (value == 1) {
163       slotManager.stateListeners.addListener(managerStateListener)
164       slotManager.active = true
165     }
166
167     rebuildPopupControllerComponent()
168     addContainerListener(componentListener)
169   }
170
171   private fun remove(project: Project) {
172     RunToolbarSlotManager.getInstance(project).stateListeners.removeListener(managerStateListener)
173     counter[project]?.let {
174       val value = maxOf(it - 1, 0)
175       counter[project] = value
176       if (value == 0) {
177         RunToolbarSlotManager.getInstance(project).active = false
178         counter.remove(project)
179       }
180     }
181
182     removeContainerListener(componentListener)
183     popupController?.let {
184       if(!Disposer.isDisposed(it)) {
185         Disposer.dispose(it)
186       }
187     }
188     popupController = null
189     state = null
190   }
191 }
192