[intention-preview] Do not cache NO_PREVIEW and LOADING_PREVIEW UI components

Later the listener could be added to these components, so memory leak through the listener is possible
Fixes IJPL-161082 Intention preview leaks project

GitOrigin-RevId: 28c0b15b9ee35ebd19c6d300b52e5aad9ec97093
This commit is contained in:
Tagir Valeev
2024-08-28 11:44:59 +02:00
committed by intellij-monorepo-bot
parent 40326372e3
commit 97111e7f7c
2 changed files with 14 additions and 6 deletions

View File

@@ -2,6 +2,7 @@
package com.intellij.codeInsight.intention.impl.preview
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.CodeInsightBundle.message
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
import com.intellij.ide.plugins.MultiPanel
import com.intellij.openapi.Disposable
@@ -24,7 +25,7 @@ internal class IntentionPreviewComponent(parent: Disposable) :
val multiPanel: MultiPanel = object : MultiPanel() {
override fun create(key: Int): JComponent {
return when (key) {
LOADING_PREVIEW -> LOADING_LABEL
LOADING_PREVIEW -> createHtmlPanel(IntentionPreviewInfo.Html(message("intention.preview.loading.preview")))
else -> previewComponent!! // It's set in IntentionPreviewPopupUpdateProcessor#select
}
}
@@ -40,8 +41,14 @@ internal class IntentionPreviewComponent(parent: Disposable) :
const val NO_PREVIEW: Int = -1
const val LOADING_PREVIEW: Int = -2
private val BORDER: JBEmptyBorder = JBUI.Borders.empty(6, 10)
internal var NO_PREVIEW_LABEL = createHtmlPanel(IntentionPreviewInfo.Html(CodeInsightBundle.message("intention.preview.no.available.text")))
private var LOADING_LABEL = createHtmlPanel(IntentionPreviewInfo.Html(CodeInsightBundle.message("intention.preview.loading.preview")))
internal fun createNoPreviewPanel(): JPanel {
val panel = createHtmlPanel(IntentionPreviewInfo.Html(message("intention.preview.no.available.text")))
panel.putClientProperty("NO_PREVIEW", true)
return panel
}
internal fun JComponent.isNoPreviewPanel(): Boolean = this.getClientProperty("NO_PREVIEW") != null
internal fun createHtmlPanel(htmlInfo: IntentionPreviewInfo.Html): JPanel {
val targetSize = IntentionPreviewPopupUpdateProcessor.MIN_WIDTH * UIUtil.getLabelFont().size.coerceAtMost(24) / 12

View File

@@ -3,6 +3,7 @@ package com.intellij.codeInsight.intention.impl.preview
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewComponent.Companion.LOADING_PREVIEW
import com.intellij.codeInsight.intention.impl.preview.IntentionPreviewComponent.Companion.isNoPreviewPanel
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo.Html
import com.intellij.openapi.actionSystem.IdeActions
@@ -171,7 +172,7 @@ class IntentionPreviewPopupUpdateProcessor internal constructor(
is IntentionPreviewDiffResult -> {
val editors = IntentionPreviewEditorsPanel.createEditors(project, result)
if (editors.isEmpty()) {
IntentionPreviewComponent.NO_PREVIEW_LABEL
IntentionPreviewComponent.createNoPreviewPanel()
}
else {
val location = popup.locationOnScreen
@@ -211,7 +212,7 @@ class IntentionPreviewPopupUpdateProcessor internal constructor(
}
}
is Html -> IntentionPreviewComponent.createHtmlPanel(result)
else -> IntentionPreviewComponent.NO_PREVIEW_LABEL
else -> IntentionPreviewComponent.createNoPreviewPanel()
}
}
@@ -249,7 +250,7 @@ class IntentionPreviewPopupUpdateProcessor internal constructor(
private fun select(index: Int, previewComponent: JComponent? = null) {
val selectedComponent = previewComponent ?: component.multiPanel.getValue(index, false)
getPopupWindow()?.isVisible = selectedComponent != IntentionPreviewComponent.NO_PREVIEW_LABEL || justActivated
getPopupWindow()?.isVisible = !selectedComponent.isNoPreviewPanel() || justActivated
justActivated = false
component.stopLoading()
// need to set previewComponent before select, as multiPanel.create expects previewComponent to be initialized