Skip to content

Commit 3119c27

Browse files
committed
feat: Improve ApiDashboard lifecycle management and context handling
1 parent 8736f91 commit 3119c27

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/dashboard/ApiDashboardPanel.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.itangcent.idea.plugin.api.dashboard
22

3+
import com.intellij.openapi.Disposable
34
import com.intellij.openapi.application.ApplicationManager
45
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
56
import com.intellij.openapi.project.Project
@@ -31,7 +32,6 @@ import java.awt.Dimension
3132
import java.awt.event.MouseAdapter
3233
import java.awt.event.MouseEvent
3334
import java.awt.event.MouseListener
34-
import java.util.concurrent.Executors
3535
import javax.swing.*
3636
import javax.swing.event.DocumentEvent
3737
import javax.swing.event.DocumentListener
@@ -45,7 +45,7 @@ import javax.swing.tree.TreePath
4545
import javax.swing.tree.TreeSelectionModel
4646
import kotlin.concurrent.thread
4747

48-
class ApiDashboardPanel(private val project: Project) : JBPanel<ApiDashboardPanel>(BorderLayout()) {
48+
class ApiDashboardPanel(private val project: Project) : JBPanel<ApiDashboardPanel>(BorderLayout()), Disposable {
4949
companion object : Log()
5050

5151
private val disabledFormTableBinder: ParamsTableBinder<FormParam> = DisabledFormTableBinder()
@@ -83,7 +83,6 @@ class ApiDashboardPanel(private val project: Project) : JBPanel<ApiDashboardPane
8383
private lateinit var service: ApiDashboardService
8484
private var apis: List<ProjectNodeData> = emptyList()
8585

86-
private val workThreadPool = Executors.newCachedThreadPool()
8786
private var currentResponse: HttpResponse? = null
8887
private var formTableBinder: ParamsTableBinder<FormParam> = disabledFormTableBinder
8988

@@ -276,7 +275,7 @@ class ApiDashboardPanel(private val project: Project) : JBPanel<ApiDashboardPane
276275
val node = apiTree.lastSelectedPathComponent as? DefaultMutableTreeNode
277276
val userObject = node?.userObject
278277
if (userObject is ProjectNodeData) {
279-
workThreadPool.submit {
278+
actionContext.runAsync {
280279
refreshProjectNodeData(userObject)
281280
}
282281
}
@@ -1228,4 +1227,9 @@ class ApiDashboardPanel(private val project: Project) : JBPanel<ApiDashboardPane
12281227
}
12291228
return null
12301229
}
1230+
1231+
override fun dispose() {
1232+
searchDebounceTimer.stop()
1233+
service.dispose()
1234+
}
12311235
}

idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/dashboard/ApiDashboardService.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import com.intellij.openapi.components.Service
55
import com.intellij.openapi.components.service
66
import com.intellij.openapi.module.ModuleManager
77
import com.intellij.openapi.project.Project
8+
import com.intellij.openapi.project.ProjectManager
9+
import com.intellij.openapi.project.ProjectManagerListener
810
import com.intellij.openapi.project.rootManager
911
import com.intellij.openapi.wm.ToolWindowManager
1012
import com.intellij.psi.*
@@ -95,7 +97,7 @@ class ApiDashboardService(private val project: Project) {
9597
@Inject
9698
private lateinit var httpContextCacheHelper: HttpContextCacheHelper
9799

98-
var actionContext: ActionContext
100+
lateinit var actionContext: ActionContext
99101
private set
100102

101103
private val requestRawInfoBinderFactory: DbBeanBinderFactory<RequestRawInfo> by lazy {
@@ -140,6 +142,19 @@ class ApiDashboardService(private val project: Project) {
140142

141143
init {
142144
Setup.load(ApiDashboardService::class.java.classLoader)
145+
createNewActionContext()
146+
147+
// Add project dispose listener
148+
project.messageBus.connect().subscribe(ProjectManager.TOPIC, object : ProjectManagerListener {
149+
override fun projectClosing(project: Project) {
150+
if (project == this@ApiDashboardService.project) {
151+
actionContext.stop()
152+
}
153+
}
154+
})
155+
}
156+
157+
fun createNewActionContext() {
143158
val builder = ActionContext.builder()
144159
builder.bindInstance(Project::class, project)
145160
builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() }
@@ -154,6 +169,12 @@ class ApiDashboardService(private val project: Project) {
154169
actionContext.init(this)
155170
}
156171

172+
fun ensureActionContextActive() {
173+
if (!::actionContext.isInitialized || actionContext.isStopped()) {
174+
createNewActionContext()
175+
}
176+
}
177+
157178
fun setDashboardPanel(panel: ApiDashboardPanel) {
158179
this.dashboardPanel = panel
159180
}
@@ -747,6 +768,12 @@ class ApiDashboardService(private val project: Project) {
747768
httpClientExporter.export(listOf(request))
748769
}
749770
}
771+
772+
fun dispose() {
773+
if (::actionContext.isInitialized && !actionContext.isStopped()) {
774+
actionContext.stop()
775+
}
776+
}
750777
}
751778

752779
interface DocContainer {

idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/dashboard/ApiDashboardToolWindow.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,35 @@ package com.itangcent.idea.plugin.api.dashboard
33
import com.intellij.openapi.project.Project
44
import com.intellij.openapi.wm.ToolWindow
55
import com.intellij.openapi.wm.ToolWindowFactory
6+
import com.intellij.openapi.wm.ToolWindowManager
7+
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
8+
import com.intellij.ui.content.ContentManagerEvent
9+
import com.intellij.ui.content.ContentManagerListener
610

711
class ApiDashboardToolWindow : ToolWindowFactory {
812
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
913
val dashboardPanel = ApiDashboardPanel(project)
1014
val content = toolWindow.contentManager.factory.createContent(dashboardPanel, "", false)
15+
16+
// Add content listener to handle disposal
17+
toolWindow.contentManager.addContentManagerListener(object : ContentManagerListener {
18+
override fun contentRemoved(event: ContentManagerEvent) {
19+
if (event.content == content) {
20+
dashboardPanel.dispose()
21+
}
22+
}
23+
})
24+
25+
// Add tool window visibility listener
26+
project.messageBus.connect().subscribe(ToolWindowManagerListener.TOPIC, object : ToolWindowManagerListener {
27+
override fun stateChanged(toolWindowManager: ToolWindowManager) {
28+
if (toolWindow.isVisible) {
29+
// When tool window becomes visible, ensure ActionContext is active
30+
ApiDashboardService.getInstance(project).ensureActionContextActive()
31+
}
32+
}
33+
})
34+
1135
toolWindow.contentManager.addContent(content)
1236
}
1337
}

0 commit comments

Comments
 (0)