RIDER-77734 Compound run configs are duplicated if it's started out of the toolbar
[idea/community.git] / platform / execution-impl / src / com / intellij / execution / runToolbar / RunToolbarData.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.RunnerAndConfigurationSettings
5 import com.intellij.execution.executors.ExecutorGroup
6 import com.intellij.execution.impl.EditConfigurationsDialog
7 import com.intellij.execution.impl.ProjectRunConfigurationConfigurable
8 import com.intellij.execution.impl.RunConfigurable
9 import com.intellij.execution.impl.SingleConfigurationConfigurable
10 import com.intellij.execution.runners.ExecutionEnvironment
11 import com.intellij.execution.ui.RunContentDescriptor
12 import com.intellij.icons.AllIcons
13 import com.intellij.ide.DataManager
14 import com.intellij.openapi.actionSystem.*
15 import com.intellij.openapi.options.Configurable
16 import com.intellij.openapi.project.Project
17 import com.intellij.openapi.util.Key
18 import com.intellij.openapi.util.text.HtmlBuilder
19 import com.intellij.openapi.util.text.HtmlChunk
20 import com.intellij.openapi.wm.ToolWindowManager
21 import com.intellij.ui.ColorUtil
22 import com.intellij.util.ui.JBUI
23 import org.jetbrains.annotations.ApiStatus
24 import org.jetbrains.annotations.Nls
25 import javax.swing.Icon
26
27 interface RunToolbarData {
28   companion object {
29     @JvmField val RUN_TOOLBAR_DATA_KEY: DataKey<RunToolbarData> = DataKey.create("RUN_TOOLBAR_DATA_KEY")
30     @JvmField val RUN_TOOLBAR_POPUP_STATE_KEY: DataKey<Boolean> = DataKey.create("RUN_TOOLBAR_POPUP_STATE_KEY")
31     @JvmField val RUN_TOOLBAR_MAIN_STATE: DataKey<RunToolbarMainSlotState> = DataKey.create("RUN_TOOLBAR_MAIN_STATE")
32
33     internal fun prepareDescription(@Nls text: String, @Nls description: String): @Nls String {
34       return HtmlBuilder().append(text)
35           .br()
36           .append(
37             HtmlChunk
38               .font(-1)
39               .addText(description)
40               .wrapWith(HtmlChunk.font(ColorUtil.toHtmlColor(JBUI.CurrentTheme.Label.disabledForeground())))).toString()
41     }
42   }
43
44   val id: String
45   var configuration: RunnerAndConfigurationSettings?
46   val environment: ExecutionEnvironment?
47
48   fun clear()
49 }
50
51 internal fun RunContentDescriptor.environment(): ExecutionEnvironment? {
52   return this.attachedContent?.component?.let {
53     ExecutionDataKeys.EXECUTION_ENVIRONMENT.getData(DataManager.getInstance().getDataContext(it))
54   }
55 }
56
57 internal fun AnActionEvent.runToolbarData(): RunToolbarData? {
58   return this.dataContext.runToolbarData()
59 }
60
61 fun DataContext.runToolbarData(): RunToolbarData? {
62   return this.getData(RunToolbarData.RUN_TOOLBAR_DATA_KEY)
63 }
64
65 fun AnActionEvent.mainState(): RunToolbarMainSlotState? {
66   return this.dataContext.getData(RunToolbarData.RUN_TOOLBAR_MAIN_STATE)
67 }
68
69 internal fun DataContext.configuration(): RunnerAndConfigurationSettings? {
70   return runToolbarData()?.configuration
71 }
72
73 private fun getConfiguration(dataContext: DataContext): RunnerAndConfigurationSettings? {
74   return dataContext.configuration()
75 }
76
77 internal fun AnActionEvent.isActiveProcess(): Boolean {
78   return this.environment() != null
79 }
80
81 internal fun AnActionEvent.setConfiguration(value: RunnerAndConfigurationSettings?) {
82   this.runToolbarData()?.configuration = value
83 }
84
85 internal fun DataContext.setConfiguration(value: RunnerAndConfigurationSettings?) {
86   runToolbarData()?.configuration = value
87 }
88
89 internal fun AnActionEvent.configuration(): RunnerAndConfigurationSettings? {
90   return runToolbarData()?.configuration
91 }
92
93 internal fun AnActionEvent.arrowIcon(): Icon? {
94   val isOpened = this.dataContext.getData(RunToolbarData.RUN_TOOLBAR_POPUP_STATE_KEY)
95                  ?: return null
96   return when {
97     isOpened -> {
98       AllIcons.Toolbar.Collapse
99     }
100     else -> {
101       AllIcons.Toolbar.Expand
102     }
103   }
104 }
105
106 fun ExecutionEnvironment.getDisplayName(): String? {
107   return this.contentToReuse?.displayName
108 }
109
110 fun AnActionEvent.environment(): ExecutionEnvironment? {
111   return runToolbarData()?.environment
112 }
113
114 fun ExecutionEnvironment.isRunning(): Boolean? {
115   return this.contentToReuse?.processHandler?.let {
116     !it.isProcessTerminating && !it.isProcessTerminated
117   }
118 }
119
120
121 fun AnActionEvent.isProcessTerminating(): Boolean {
122   return this.environment()?.isProcessTerminating() == true
123 }
124
125 fun ExecutionEnvironment.isProcessTerminating(): Boolean {
126   return this.contentToReuse?.processHandler?.isProcessTerminating == true
127 }
128
129 internal fun AnActionEvent.id(): String? {
130   return runToolbarData()?.id
131 }
132
133 internal fun ExecutionEnvironment.getRunToolbarProcess(): RunToolbarProcess? {
134   return ExecutorGroup.getGroupIfProxy(this.executor)?.let { executorGroup ->
135     RunToolbarProcess.getProcesses().firstOrNull {
136       it.executorId == executorGroup.id
137     }
138   } ?: run {
139     RunToolbarProcess.getProcesses().firstOrNull {
140       it.executorId == this.executor.id
141     }
142   }
143 }
144
145 internal fun DataContext.editConfiguration() {
146   getData(CommonDataKeys.PROJECT)?.let {
147     EditConfigurationsDialog(it, createRunConfigurationConfigurable(it, this)).show()
148   }
149 }
150
151 internal fun ExecutionEnvironment.showToolWindowTab() {
152   ToolWindowManager.getInstance(this.project).getToolWindow(this.contentToReuse?.contentToolWindowId ?: this.executor.id)?.let {
153     val contentManager = it.contentManager
154     contentManager.contents.firstOrNull { it.executionId == this.executionId }?.let { content ->
155       contentManager.setSelectedContent(content)
156     }
157     it.show()
158   }
159 }
160
161 private fun createRunConfigurationConfigurable(project: Project, dataContext: DataContext): RunConfigurable {
162   val settings: RunnerAndConfigurationSettings? = getConfiguration(dataContext)
163
164   fun updateActiveConfigurationFromSelected(configurable: Configurable?) {
165     configurable?.let {
166       if (it is SingleConfigurationConfigurable<*>) {
167         dataContext.setConfiguration(it.settings)
168       }
169     }
170   }
171
172   return when {
173     project.isDefault -> object : RunConfigurable(project) {
174       override fun getSelectedConfiguration(): RunnerAndConfigurationSettings? {
175         return settings
176       }
177
178       override fun updateActiveConfigurationFromSelected() {
179         updateActiveConfigurationFromSelected(getSelectedConfigurable())
180       }
181     }
182     else -> object : ProjectRunConfigurationConfigurable(project) {
183       override fun getSelectedConfiguration(): RunnerAndConfigurationSettings? {
184         return settings
185       }
186
187       override fun updateActiveConfigurationFromSelected() {
188        updateActiveConfigurationFromSelected(getSelectedConfigurable())
189       }
190     }
191   }
192 }