diff --git a/notebooks/visualization/resources/intellij.notebooks.visualization.xml b/notebooks/visualization/resources/intellij.notebooks.visualization.xml index 86e2b2e392d3..ee3e96247aab 100644 --- a/notebooks/visualization/resources/intellij.notebooks.visualization.xml +++ b/notebooks/visualization/resources/intellij.notebooks.visualization.xml @@ -29,6 +29,11 @@ interface="com.intellij.notebooks.visualization.controllers.selfUpdate.SelfManagedControllerFactory" dynamic="true"/> + + + diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookBelowLastCellPanel.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookBelowLastCellPanel.kt index 658c88ba6cf3..01cfb3a74ab9 100644 --- a/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookBelowLastCellPanel.kt +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookBelowLastCellPanel.kt @@ -3,17 +3,17 @@ package com.intellij.notebooks.visualization import com.intellij.notebooks.ui.visualization.NotebookEditorAppearanceUtils.isOrdinaryNotebookEditor import com.intellij.notebooks.ui.visualization.NotebookUtil.notebookAppearance -import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightableCellPanel +import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightable import com.intellij.notebooks.visualization.ui.jupyterToolbars.JupyterAddNewCellToolbar import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.util.ui.JBEmptyBorder -import java.awt.Graphics2D import org.intellij.lang.annotations.Language import java.awt.FlowLayout -import javax.swing.JPanel import java.awt.Graphics +import java.awt.Graphics2D +import javax.swing.JPanel /** * Basically, this panel consists only of @@ -21,8 +21,8 @@ import java.awt.Graphics * * a highlightable border to show drop destination */ class NotebookBelowLastCellPanel( - val editor: EditorImpl -) : JPanel(FlowLayout(FlowLayout.CENTER)), DropHighlightableCellPanel { + val editor: EditorImpl, +) : JPanel(FlowLayout(FlowLayout.CENTER)), DropHighlightable { private var isHighlighted = false diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookCellInlayManager.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookCellInlayManager.kt index b2f91e989e0b..81b2daf102d4 100644 --- a/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookCellInlayManager.kt +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/NotebookCellInlayManager.kt @@ -2,20 +2,18 @@ package com.intellij.notebooks.visualization import com.intellij.ide.ui.LafManagerListener import com.intellij.notebooks.ui.bind -import com.intellij.notebooks.ui.visualization.NotebookUtil.notebookAppearance -import com.intellij.notebooks.visualization.context.NotebookDataContext.NOTEBOOK_CELL_LINES_INTERVAL import com.intellij.notebooks.visualization.ui.* import com.intellij.notebooks.visualization.ui.EditorCellEventListener.* import com.intellij.notebooks.visualization.ui.EditorCellViewEventListener.CellViewCreated import com.intellij.notebooks.visualization.ui.EditorCellViewEventListener.CellViewRemoved +import com.intellij.notebooks.visualization.ui.endInlay.EditorNotebookEndInlay +import com.intellij.notebooks.visualization.ui.endInlay.EditorNotebookEndInlayProvider import com.intellij.openapi.Disposable -import com.intellij.openapi.actionSystem.UiDataProvider import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.FoldRegion -import com.intellij.openapi.editor.Inlay import com.intellij.openapi.editor.colors.EditorColorsListener import com.intellij.openapi.editor.colors.EditorColorsManager import com.intellij.openapi.editor.event.CaretEvent @@ -35,7 +33,7 @@ import java.awt.Point class NotebookCellInlayManager private constructor( val editor: EditorImpl, private val shouldCheckInlayOffsets: Boolean, - private val notebook: EditorNotebook, + val notebook: EditorNotebook, ) : Disposable, NotebookIntervalPointerFactory.ChangeListener { private val notebookCellLines = NotebookCellLines.get(editor) @@ -44,10 +42,9 @@ class NotebookCellInlayManager private constructor( val cells: List get() = notebook.cells - internal val views: MutableMap = mutableMapOf() + val endNotebookInlays: List = EditorNotebookEndInlayProvider.create(this) - val belowLastCellPanel: NotebookBelowLastCellPanel = NotebookBelowLastCellPanel(editor) - private var belowLastCellInlay: Inlay<*>? = null + internal val views: MutableMap = mutableMapOf() private val cellViewEventListeners = EventDispatcher.create(EditorCellViewEventListener::class.java) @@ -128,7 +125,7 @@ class NotebookCellInlayManager private constructor( setupFoldingListener() setupSelectionUI() - addBelowLastCellInlay() + notebook.addCellEventsListener(this, object : EditorCellEventListener { override fun onEditorCellEvents(events: List) { @@ -216,22 +213,6 @@ class NotebookCellInlayManager private constructor( } } - private fun addBelowLastCellInlay() { // PY-77218 - belowLastCellInlay = editor.addComponentInlay( - UiDataProvider.wrapComponent(belowLastCellPanel) { sink -> - sink[NOTEBOOK_CELL_LINES_INTERVAL] = editor.notebook?.cells?.lastOrNull()?.interval - }, - isRelatedToPrecedingText = true, - showAbove = false, - priority = editor.notebookAppearance.jupyterBelowLastCellInlayPriority, - offset = editor.document.getLineEndOffset((editor.document.lineCount - 1).coerceAtLeast(0)) - ) - } - - fun removeBelowLastCellInlay() { - belowLastCellInlay?.let { Disposer.dispose(it) } - belowLastCellInlay = null - } private fun setupFoldingListener() { val foldingModel = editor.foldingModel diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/EditorCellView.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/EditorCellView.kt index 89f046cf5b21..49835432bb2a 100644 --- a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/EditorCellView.kt +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/EditorCellView.kt @@ -7,7 +7,7 @@ import com.intellij.notebooks.visualization.* import com.intellij.notebooks.visualization.NotebookCellInlayController.InputFactory import com.intellij.notebooks.visualization.controllers.selfUpdate.SelfManagedCellController import com.intellij.notebooks.visualization.controllers.selfUpdate.SelfManagedControllerFactory -import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightableCellPanel +import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightable import com.intellij.openapi.Disposable import com.intellij.openapi.application.runInEdt import com.intellij.openapi.diagnostic.thisLogger @@ -59,9 +59,6 @@ class EditorCellView( // We are storing last lines range for highlighters to prevent highlighters unnecessary recreation on the same lines. private var lastHighLightersLines: IntRange? = null - //We do not use it - var disableActions: Boolean = false - var isUnderDiff: Boolean get() = cell.isUnderDiff.get() set(value) = cell.isUnderDiff.set(value) @@ -322,11 +319,11 @@ class EditorCellView( } fun addDropHighlightIfApplicable() { - selfManagedControllers.filterIsInstance().firstOrNull()?.addDropHighlight() + selfManagedControllers.filterIsInstance().firstOrNull()?.addDropHighlight() } fun removeDropHighlightIfPresent() { - selfManagedControllers.filterIsInstance().firstOrNull()?.removeDropHighlight() + selfManagedControllers.filterIsInstance().firstOrNull()?.removeDropHighlight() } diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightableCellPanel.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightable.kt similarity index 85% rename from notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightableCellPanel.kt rename to notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightable.kt index 256578db2d41..fcf42ffa591a 100644 --- a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightableCellPanel.kt +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/DropHighlightable.kt @@ -1,7 +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.cellsDnD -interface DropHighlightableCellPanel { +interface DropHighlightable { fun addDropHighlight() fun removeDropHighlight() } \ No newline at end of file diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/EditorCellDragAssistant.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/EditorCellDragAssistant.kt index df4c228058b9..80571274d99d 100644 --- a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/EditorCellDragAssistant.kt +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/cellsDnD/EditorCellDragAssistant.kt @@ -197,9 +197,14 @@ class EditorCellDragAssistant( } } - private fun addHighlightAfterLastCell() = inlayManager?.belowLastCellPanel?.addDropHighlight() + private fun addHighlightAfterLastCell() = inlayManager?.endNotebookInlays?.filterIsInstance()?.forEach { + it.addDropHighlight() + } + + private fun removeHighlightAfterLastCell() = inlayManager?.endNotebookInlays?.filterIsInstance()?.forEach { + it.removeDropHighlight() + } - private fun removeHighlightAfterLastCell() = inlayManager?.belowLastCellPanel?.removeDropHighlight() private fun deleteDropIndicatorForTargetCell(cell: EditorCell) = try { cell.view?.removeDropHighlightIfPresent() diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlay.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlay.kt new file mode 100644 index 000000000000..3d9e5833a64f --- /dev/null +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlay.kt @@ -0,0 +1,6 @@ +// 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.endInlay + +import com.intellij.openapi.Disposable + +interface EditorNotebookEndInlay : Disposable.Default \ No newline at end of file diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlayProvider.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlayProvider.kt new file mode 100644 index 000000000000..2fc9c123cecd --- /dev/null +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/EditorNotebookEndInlayProvider.kt @@ -0,0 +1,22 @@ +// 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.endInlay + +import com.intellij.notebooks.visualization.NotebookCellInlayManager +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.util.Disposer + +interface EditorNotebookEndInlayProvider { + fun create(inlayManager: NotebookCellInlayManager): EditorNotebookEndInlay? + + companion object { + private val EP = ExtensionPointName.create("org.jetbrains.plugins.notebooks.editorNotebookEndInlayProvider") + + fun create(inlayManager: NotebookCellInlayManager): List { + return EP.extensionsIfPointIsRegistered.mapNotNull { + val endInlay = it.create(inlayManager) ?: return@mapNotNull null + Disposer.register(inlayManager, endInlay) + endInlay + } + } + } +} \ No newline at end of file diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbar.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbar.kt new file mode 100644 index 000000000000..0268b72da23c --- /dev/null +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbar.kt @@ -0,0 +1,41 @@ +// 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.endInlay.addToolbar + +import com.intellij.notebooks.ui.visualization.NotebookUtil.notebookAppearance +import com.intellij.notebooks.visualization.NotebookBelowLastCellPanel +import com.intellij.notebooks.visualization.NotebookCellInlayManager +import com.intellij.notebooks.visualization.context.NotebookDataContext.NOTEBOOK_CELL_LINES_INTERVAL +import com.intellij.notebooks.visualization.ui.addComponentInlay +import com.intellij.notebooks.visualization.ui.cellsDnD.DropHighlightable +import com.intellij.notebooks.visualization.ui.endInlay.EditorNotebookEndInlay +import com.intellij.openapi.actionSystem.UiDataProvider +import com.intellij.openapi.util.Disposer + +class EditorNotebookEndAddToolbar(val inlayManager: NotebookCellInlayManager) : EditorNotebookEndInlay, DropHighlightable { + private val editor = inlayManager.editor + + private val belowLastCellPanel: NotebookBelowLastCellPanel = NotebookBelowLastCellPanel(editor) + + init { + // PY-77218 + editor.addComponentInlay( + UiDataProvider.wrapComponent(belowLastCellPanel) { sink -> + sink[NOTEBOOK_CELL_LINES_INTERVAL] = inlayManager.notebook.cells.lastOrNull()?.interval + }, + isRelatedToPrecedingText = true, + showAbove = false, + priority = editor.notebookAppearance.jupyterBelowLastCellInlayPriority, + offset = editor.document.getLineEndOffset((editor.document.lineCount - 1).coerceAtLeast(0)) + ).also { + Disposer.register(this, it) + } + } + + override fun addDropHighlight() { + belowLastCellPanel.addDropHighlight() + } + + override fun removeDropHighlight() { + belowLastCellPanel.removeDropHighlight() + } +} \ No newline at end of file diff --git a/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbarProvider.kt b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbarProvider.kt new file mode 100644 index 000000000000..d903376d65bc --- /dev/null +++ b/notebooks/visualization/src/com/intellij/notebooks/visualization/ui/endInlay/addToolbar/EditorNotebookEndAddToolbarProvider.kt @@ -0,0 +1,15 @@ +// 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.endInlay.addToolbar + +import com.intellij.notebooks.ui.visualization.NotebookEditorAppearanceUtils.isOrdinaryNotebookEditor +import com.intellij.notebooks.visualization.NotebookCellInlayManager +import com.intellij.notebooks.visualization.ui.endInlay.EditorNotebookEndInlay +import com.intellij.notebooks.visualization.ui.endInlay.EditorNotebookEndInlayProvider + +class EditorNotebookEndAddToolbarProvider : EditorNotebookEndInlayProvider { + override fun create(inlayManager: NotebookCellInlayManager): EditorNotebookEndInlay? { + if (!inlayManager.editor.isOrdinaryNotebookEditor()) + return null + return EditorNotebookEndAddToolbar(inlayManager) + } +} \ No newline at end of file