PY-79420 Jupyter: Refactor BelowCellInlayController. Split to separate components and local listeners for each component

We need to do it to not force gloval update on each change. Now each cmponent can be updated separatly and call on own disposable listeners

GitOrigin-RevId: 9d2d2191a4d69525de9f3bfd5e80aaea1c81a024
This commit is contained in:
Nikita.Ashihmin
2025-04-12 23:06:34 +00:00
committed by intellij-monorepo-bot
parent 391825456b
commit e7ef68a6d9
9 changed files with 44 additions and 46 deletions
@@ -84,6 +84,7 @@ interface NotebookCellInlayController {
val inlay: Inlay<*>
val factory: Factory
get() = error("It is not used keep with AIA compatibility")
fun onViewportChange(): Unit = Unit
@@ -1,7 +0,0 @@
package com.intellij.notebooks.visualization.ui
import java.time.ZonedDateTime
interface CellExecutionStatusView {
fun updateExecutionStatus(executionCount: Int?, progressStatus: ProgressStatus?, startTime: ZonedDateTime?, endTime: ZonedDateTime?)
}
@@ -6,7 +6,6 @@ import com.intellij.notebooks.visualization.NotebookCellLines.CellType
import com.intellij.notebooks.visualization.NotebookCellLines.Interval
import com.intellij.notebooks.visualization.NotebookIntervalPointer
import com.intellij.notebooks.visualization.UpdateContext
import com.intellij.notebooks.visualization.execution.ExecutionEvent
import com.intellij.notebooks.visualization.outputs.NotebookOutputDataKey
import com.intellij.notebooks.visualization.outputs.NotebookOutputDataKeyExtractor
import com.intellij.openapi.Disposable
@@ -26,7 +25,7 @@ private val CELL_EXTENSION_CONTAINER_KEY = Key<MutableMap<KClass<*>, EditorCellE
class EditorCell(
val notebook: EditorNotebook,
var intervalPointer: NotebookIntervalPointer,
private val editor: EditorImpl,
val editor: EditorImpl,
) : Disposable, UserDataHolder by UserDataHolderBase() {
val source: AtomicProperty<String> = AtomicProperty(getSource())
@@ -34,6 +33,7 @@ class EditorCell(
val type: CellType = interval.type
val interval: Interval get() = intervalPointer.get() ?: error("Invalid interval")
val intervalOrNull: Interval? get() = intervalPointer.get()
val view: EditorCellView?
get() = NotebookCellInlayManager.get(editor)!!.views[this]
@@ -117,22 +117,6 @@ class EditorCell(
outputs.updateOutputs()
}
fun onExecutionEvent(event: ExecutionEvent) {
when (event) {
is ExecutionEvent.ExecutionStarted -> {
executionStatus.set(executionStatus.get().copy(status = event.status, startTime = event.startTime))
}
is ExecutionEvent.ExecutionStopped -> {
executionStatus.set(executionStatus.get().copy(status = event.status, endTime = event.endTime, count = event.executionCount))
}
is ExecutionEvent.ExecutionSubmitted -> {
executionStatus.set(executionStatus.get().copy(status = event.status))
}
is ExecutionEvent.ExecutionReset -> {
executionStatus.set(executionStatus.get().copy(status = event.status))
}
}
}
fun requestCaret() {
view?.requestCaret()
@@ -10,6 +10,8 @@ import com.intellij.notebooks.ui.visualization.markerRenderers.NotebookCodeCellB
import com.intellij.notebooks.visualization.*
import com.intellij.notebooks.visualization.NotebookCellInlayController.InputFactory
import com.intellij.notebooks.visualization.context.NotebookDataContext
import com.intellij.notebooks.visualization.ui.EditorCell.ExecutionStatus
import com.intellij.notebooks.visualization.ui.cell.frame.EditorCellFrameManager
import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightableCellPanel
import com.intellij.notebooks.visualization.ui.jupyterToolbars.NotebookCellActionsToolbarStateTracker
import com.intellij.openapi.Disposable
@@ -32,7 +34,6 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.util.asSafely
import java.awt.Color
import java.awt.Rectangle
import java.time.ZonedDateTime
import javax.swing.JComponent
import kotlin.reflect.KClass
@@ -73,10 +74,11 @@ class EditorCellView(
var outputs: EditorCellOutputsView? = null
private set
val myEditorCellFrameManager: EditorCellFrameManager? =
val cellFrameManager: EditorCellFrameManager? =
if (interval.type == NotebookCellLines.CellType.MARKDOWN && Registry.`is`("jupyter.markdown.cells.border")) {
EditorCellFrameManager(editor, this, NotebookCellLines.CellType.MARKDOWN)
} else if (interval.type == NotebookCellLines.CellType.CODE && Registry.`is`("jupyter.code.cells.border")) {
}
else if (Registry.`is`("jupyter.code.cells.border")) {
EditorCellFrameManager(editor, this, NotebookCellLines.CellType.CODE)
} else null
@@ -91,7 +93,7 @@ class EditorCellView(
updateRunButtonVisibility()
updateCellHighlight()
updateCellActionsToolbarVisibility()
myEditorCellFrameManager?.updateCellFrameShow(value, mouseOver)
cellFrameManager?.updateCellFrameShow(value, mouseOver)
}
private var mouseOver = false
@@ -122,10 +124,9 @@ class EditorCellView(
}
this.selected = cell.selected.get()
cell.executionStatus.afterChange(this) { execution ->
updateExecutionStatus(execution.count, execution.status, execution.startTime, execution.endTime)
updateExecutionStatus(execution)
}
val executionStatus = cell.executionStatus.get()
updateExecutionStatus(executionStatus.count, executionStatus.status, executionStatus.startTime, executionStatus.endTime)
updateExecutionStatus(cell.executionStatus.get())
editor.notebookAppearance.codeCellBackgroundColor.afterChange(this) { backgroundColor ->
updateCellHighlight(force = true)
}
@@ -151,7 +152,7 @@ class EditorCellView(
_controllers.forEach { controller ->
disposeController(controller)
}
myEditorCellFrameManager?.let { Disposer.dispose(it) }
cellFrameManager?.let { Disposer.dispose(it) }
removeCellHighlight()
}
@@ -190,7 +191,14 @@ class EditorCellView(
.filter { it !is InputFactory }
val controllersToDispose = _controllers.toMutableSet()
_controllers = if (!editor.isDisposed) {
otherFactories.mapNotNull { factory -> failSafeCompute(factory, editor, _controllers, intervals.intervals.listIterator(interval.ordinal)) }
otherFactories.mapNotNull { factory ->
val intervalIterator = intervals.intervals.listIterator(interval.ordinal)
val cellInlayController = failSafeCompute(factory, editor, _controllers, intervalIterator)
if (cellInlayController is Disposable) {
Disposer.register(this, cellInlayController)
}
cellInlayController
}
}
else {
emptyList()
@@ -284,7 +292,7 @@ class EditorCellView(
mouseOver = false
updateFolding()
updateRunButtonVisibility()
myEditorCellFrameManager?.updateCellFrameShow(selected, mouseOver)
cellFrameManager?.updateCellFrameShow(selected, mouseOver)
updateCellActionsToolbarVisibility()
}
@@ -292,7 +300,7 @@ class EditorCellView(
mouseOver = true
updateFolding()
updateRunButtonVisibility()
myEditorCellFrameManager?.updateCellFrameShow(selected, mouseOver)
cellFrameManager?.updateCellFrameShow(selected, mouseOver)
updateCellActionsToolbarVisibility()
}
@@ -374,7 +382,7 @@ class EditorCellView(
selected = value
updateFolding()
updateCellHighlight()
myEditorCellFrameManager?.updateCellFrameShow(selected, mouseOver)
cellFrameManager?.updateCellFrameShow(selected, mouseOver)
}
private fun updateFolding() {
@@ -426,10 +434,8 @@ class EditorCellView(
it.updateFrameVisibility(selected, interval, color)
}
private fun updateExecutionStatus(executionCount: Int?, progressStatus: ProgressStatus?, startTime: ZonedDateTime?, endTime: ZonedDateTime?) {
_controllers.filterIsInstance<CellExecutionStatusView>().firstOrNull()
?.updateExecutionStatus(executionCount, progressStatus, startTime, endTime)
input.runCellButton?.updateGutterAction(progressStatus)
private fun updateExecutionStatus(executionStatus: ExecutionStatus) {
input.runCellButton?.updateGutterAction(executionStatus.status)
}
fun addDropHighlightIfApplicable(): Unit? =
@@ -19,7 +19,7 @@ import com.intellij.openapi.util.Key
import com.intellij.util.EventDispatcher
import kotlin.reflect.KClass
class EditorNotebook(private val editor: EditorImpl) : Disposable {
class EditorNotebook(val editor: EditorImpl) : Disposable {
private var _cells = mutableListOf<EditorCell>()
@@ -45,7 +45,7 @@ class NotebookVisibleCellsBatchUpdater(
}
private fun updateCell(cell: EditorCell) {
cell.view?.myEditorCellFrameManager?.redrawBorders()
cell.view?.cellFrameManager?.redrawBorders()
cell.view?.input?.cellActionsToolbar?.updateToolbarPosition()
}
override fun dispose() {
@@ -0,0 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.notebooks.visualization.ui.cell.frame
import com.intellij.ui.JBColor
import java.awt.Color
data class CellFrameState(val isVisible: Boolean = false, val color: Color = JBColor.background())
@@ -1,9 +1,11 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.notebooks.visualization.ui
package com.intellij.notebooks.visualization.ui.cell.frame
import com.intellij.notebooks.ui.visualization.NotebookUtil.notebookAppearance
import com.intellij.notebooks.ui.visualization.markerRenderers.NotebookMarkdownCellLeftBorderRenderer
import com.intellij.notebooks.visualization.NotebookCellLines
import com.intellij.notebooks.visualization.ui.EditorCellView
import com.intellij.notebooks.visualization.ui.EditorLayerController
import com.intellij.notebooks.visualization.ui.EditorLayerController.Companion.getLayerController
import com.intellij.openapi.Disposable
import com.intellij.openapi.editor.ex.RangeHighlighterEx
@@ -11,6 +13,7 @@ import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.editor.markup.HighlighterLayer
import com.intellij.openapi.editor.markup.HighlighterTargetArea
import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.observable.properties.AtomicProperty
import java.awt.Color
import java.awt.geom.Line2D
@@ -26,6 +29,8 @@ class EditorCellFrameManager(
private var isSelected = false
private var isHovered = false
val state: AtomicProperty<CellFrameState> = AtomicProperty(CellFrameState())
init {
if (cellType == NotebookCellLines.CellType.CODE) redrawBorders(editor.notebookAppearance.cellFrameHoveredColor.get())
}
@@ -68,6 +73,7 @@ class EditorCellFrameManager(
currentColor = color
val layerController = editor.getLayerController()
state.set(CellFrameState(true, currentColor))
view.updateFrameVisibility(true, currentColor)
redrawLeftBorder()
@@ -105,6 +111,7 @@ class EditorCellFrameManager(
}
private fun clearFrame() {
state.set(CellFrameState(false, currentColor))
view.updateFrameVisibility(false, currentColor)
removeLeftBorder()
removeRightBorder(editor.getLayerController())
@@ -144,4 +151,4 @@ class EditorCellFrameManager(
removeLeftBorder()
removeRightBorder(editor.getLayerController())
}
}
}
@@ -74,7 +74,7 @@ class NotebookEditorUiComponent(private val data: ComponentData) : JEditorUiComp
get() = xx("//div[@class='FullEditorWidthRenderer']//div[@class='JupyterMarkdownHtmlPane']").list()
val notebookCellExecutionInfos: List<JLabelUiComponent>
get() = xx("//div[@class='FullEditorWidthRenderer']/div[@class='NotebookBelowCellDelimiterPanel']/div[@class='JLabel']", JLabelUiComponent::class.java).list()
get() = xx("//div[@accessiblename='ExecutionLabel']", JLabelUiComponent::class.java).list()
val notebookTables: List<JTableUiComponent>
get() = xx("//div[@class='TableResultView']", JTableUiComponent::class.java).list()