diff --git a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupPanel.java b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupPanel.java index ec9404a24589..f0316a2f6fe1 100644 --- a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupPanel.java +++ b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupPanel.java @@ -152,14 +152,6 @@ public class LineStatusMarkerPopupPanel extends JPanel { return size; } - - public static void showPopupAt(@NotNull Editor editor, - @NotNull LineStatusMarkerPopupPanel panel, - @Nullable Point mousePosition, - @NotNull Disposable popupDisposable) { - LineStatusMarkerPopupService.getInstance().showPopupAt(editor, panel, mousePosition, popupDisposable); - } - @NotNull public static EditorTextField createTextField(@NotNull Editor editor, @NotNull String content) { EditorTextField field = new EditorTextField(content); diff --git a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupService.kt b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupService.kt index 4cbfac618f22..2affddb9b4f0 100644 --- a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupService.kt +++ b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopupService.kt @@ -19,7 +19,10 @@ import com.intellij.openapi.editor.event.* import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.util.Disposer -import com.intellij.ui.* +import com.intellij.ui.EditorTextComponent +import com.intellij.ui.HintHint +import com.intellij.ui.HintListener +import com.intellij.ui.LightweightHint import com.intellij.util.concurrency.annotations.RequiresEdt import com.intellij.util.ui.UIUtil import java.awt.Point @@ -28,11 +31,29 @@ import java.awt.event.ComponentEvent import java.awt.event.MouseAdapter @Service(Service.Level.APP) -internal class LineStatusMarkerPopupService { - private var lastKnownHint: Hint? = null +class LineStatusMarkerPopupService { + private var activePopupDisposable: Disposable? = null @RequiresEdt - fun showPopupAt( + fun buildAndShowPopup(parentDisposable: Disposable, editor: Editor, mousePosition: Point?, builder: (popupDisposable: Disposable) -> LineStatusMarkerPopupPanel) { + val popupDisposable = getNextPopupDisposable(parentDisposable) + val markerPopupPanel = builder(popupDisposable) + showPopupAt(editor, markerPopupPanel, mousePosition, popupDisposable) + } + + private fun getNextPopupDisposable(parentDisposable: Disposable): Disposable { + closeActivePopup() + activePopupDisposable = Disposer.newDisposable(parentDisposable, "LineStatusMarkerPopup") + + return activePopupDisposable!! + } + + fun closeActivePopup() { + if (activePopupDisposable != null) Disposer.dispose(activePopupDisposable!!) + } + + @RequiresEdt + private fun showPopupAt( editor: Editor, panel: LineStatusMarkerPopupPanel, mousePosition: Point?, @@ -42,16 +63,14 @@ internal class LineStatusMarkerPopupService { Disposer.register(popupDisposable, Disposable { UIUtil.invokeLaterIfNeeded { hint.hide() - resetLastHint() } }) - hint.addHintListener(HintListener { Disposer.dispose(popupDisposable) }) + hint.addHintListener(HintListener { Disposer.dispose(popupDisposable) }) // doesn't need it anymore? hint.setForceLightweightPopup(true) // if there are no listeners, events are passed to the top level panel.addMouseListener(object : MouseAdapter() {}) - val line = editor.getCaretModel().logicalPosition.line val point = HintManagerImpl.getHintPosition(hint, editor, LogicalPosition(line, 0), HintManager.UNDER) if (mousePosition != null) { // show right after the nearest line @@ -63,9 +82,7 @@ internal class LineStatusMarkerPopupService { point.x -= panel.editorTextOffset // align a main editor with the one in popup trackInnerEditorResizing(panel, hint, popupDisposable) - setupEditorListeners(editor, popupDisposable, hint) - - beforeShowNewHint(hint) + setupEditorListeners(editor, popupDisposable) showHint(hint, editor, point) if (!hint.isVisible()) { @@ -73,22 +90,6 @@ internal class LineStatusMarkerPopupService { } } - internal fun hidePopup() { - lastKnownHint?.hide() - } - - private fun beforeShowNewHint(newHint: LightweightHint) { - if (lastKnownHint != null) { - lastKnownHint!!.hide() - resetLastHint() - } - lastKnownHint = newHint - } - - private fun resetLastHint() { - lastKnownHint = null - } - private fun showHint(hint: LightweightHint, editor: Editor, point: Point) { HintManagerImpl.doShowInGivenLocation(hint, editor, point, HintHint(editor, point), true) } @@ -121,26 +122,26 @@ internal class LineStatusMarkerPopupService { }) } - private fun setupEditorListeners(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { - trackFileEditorChange(popupDisposable, hint) - trackDocumentChange(editor, popupDisposable, hint) - trackSelection(editor, popupDisposable, hint) - trackCaretPosition(editor, popupDisposable, hint) - trackScrolling(editor, popupDisposable, hint) - trackMouseClick(editor, popupDisposable, hint) - trackEditorLookup(editor, popupDisposable, hint) + private fun setupEditorListeners(editor: Editor, popupDisposable: Disposable) { + trackFileEditorChange(popupDisposable) + trackDocumentChange(editor, popupDisposable) + trackSelection(editor, popupDisposable) + trackCaretPosition(editor, popupDisposable) + trackScrolling(editor, popupDisposable) + trackMouseClick(editor, popupDisposable) + trackEditorLookup(editor, popupDisposable) } - private fun trackFileEditorChange(popupDisposable: Disposable, hint: LightweightHint) { + private fun trackFileEditorChange(popupDisposable: Disposable) { ApplicationManager.getApplication().getMessageBus().connect(popupDisposable) .subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener { override fun selectionChanged(event: FileEditorManagerEvent) { - hint.hide() + closeActivePopup() } }) } - private fun trackDocumentChange(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackDocumentChange(editor: Editor, popupDisposable: Disposable) { editor.getDocument().addDocumentListener(object : BulkAwareDocumentListener { override fun documentChangedNonBulk(event: DocumentEvent) { if (event.getOldLength() != 0 || event.getNewLength() != 0) onDocumentChange() @@ -151,48 +152,48 @@ internal class LineStatusMarkerPopupService { } fun onDocumentChange() { - hint.hide() + closeActivePopup() } }, popupDisposable) } - private fun trackSelection(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackSelection(editor: Editor, popupDisposable: Disposable) { editor.getSelectionModel().addSelectionListener(object : SelectionListener { override fun selectionChanged(e: SelectionEvent) { - hint.hide() + closeActivePopup() } }, popupDisposable) } - private fun trackCaretPosition(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackCaretPosition(editor: Editor, popupDisposable: Disposable) { editor.getCaretModel().addCaretListener(object : CaretListener { override fun caretPositionChanged(event: CaretEvent) { - hint.hide() + closeActivePopup() } }, popupDisposable) } - private fun trackScrolling(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackScrolling(editor: Editor, popupDisposable: Disposable) { editor.getScrollingModel().addVisibleAreaListener(object : VisibleAreaListener { override fun visibleAreaChanged(e: VisibleAreaEvent) { val old = e.oldRectangle val new = e.newRectangle if (old != null && old.x == new.x && old.y == new.y) return - hint.hide() + closeActivePopup() } }, popupDisposable) } - private fun trackMouseClick(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackMouseClick(editor: Editor, popupDisposable: Disposable) { editor.addEditorMouseListener(object : EditorMouseListener { override fun mousePressed(event: EditorMouseEvent) { - hint.hide() + closeActivePopup() } }, popupDisposable) } - private fun trackEditorLookup(editor: Editor, popupDisposable: Disposable, hint: LightweightHint) { + private fun trackEditorLookup(editor: Editor, popupDisposable: Disposable) { val project = editor.project if (project != null) LookupManager.hideActiveLookup(project) // reset current @@ -201,7 +202,7 @@ internal class LineStatusMarkerPopupService { override fun hintShown(sourceEditor: Editor, editorHint: LightweightHint, flags: Int, hintInfo: HintHint) { if (sourceEditor !== editor) return if (editorHint is Lookup) { - hint.hide() + closeActivePopup() } } }) @@ -214,13 +215,17 @@ internal class LineStatusMarkerPopupService { } } +private fun closeActivePopup() { + LineStatusMarkerPopupService.instance.closeActivePopup() +} + private class LineStatusMakerEscEditorHandler(private val delegate: EditorActionHandler) : EditorActionHandler() { override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext?): Boolean { return delegate.isEnabled(editor, caret, dataContext) } override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) { - LineStatusMarkerPopupService.instance.hidePopup() + closeActivePopup() delegate.execute(editor, caret, dataContext) } } \ No newline at end of file diff --git a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerRendererWithPopup.kt b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerRendererWithPopup.kt index 7d6e5e67cb30..bf0fd69f0f32 100644 --- a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerRendererWithPopup.kt +++ b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerRendererWithPopup.kt @@ -14,9 +14,7 @@ import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.editor.markup.LineMarkerRenderer import com.intellij.openapi.editor.markup.MarkupEditorFilter import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.NlsContexts -import com.intellij.openapi.vcs.ex.LineStatusMarkerPopupPanel.showPopupAt import java.awt.Graphics import java.awt.Point import java.awt.Rectangle @@ -57,9 +55,9 @@ abstract class LineStatusMarkerRendererWithPopup( override fun showHintAt(editor: Editor, range: Range, mousePosition: Point?) { if (!rangesSource.isValid()) return - val popupDisposable = Disposer.newDisposable(disposable) - val popup = createPopupPanel(editor, range, mousePosition, popupDisposable) - showPopupAt(editor, popup, mousePosition, popupDisposable) + LineStatusMarkerPopupService.instance.buildAndShowPopup(disposable, editor, mousePosition) { popupDisposable -> + createPopupPanel(editor, range, mousePosition, popupDisposable) + } } protected open fun getTooltipText(): @NlsContexts.Tooltip String? = null diff --git a/plugins/git4idea/src/git4idea/index/GitStageLineStatusTracker.kt b/plugins/git4idea/src/git4idea/index/GitStageLineStatusTracker.kt index e06c34daf0fb..e2ef40246ec5 100644 --- a/plugins/git4idea/src/git4idea/index/GitStageLineStatusTracker.kt +++ b/plugins/git4idea/src/git4idea/index/GitStageLineStatusTracker.kt @@ -34,7 +34,6 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vcs.ex.* -import com.intellij.openapi.vcs.ex.LineStatusMarkerPopupPanel.showPopupAt import com.intellij.openapi.vcs.ex.Range import com.intellij.openapi.vfs.VirtualFile import com.intellij.ui.EditorTextField @@ -541,22 +540,22 @@ class GitStageLineStatusTracker( return } - val popupDisposable = Disposer.newDisposable(tracker.disposable) + LineStatusMarkerPopupService.instance.buildAndShowPopup(tracker.disposable, editor, mousePosition) { popupDisposable-> + val stagedTextField = createTextField(editor, tracker.stagedDocument, range.stagedLine1, range.stagedLine2) + val vcsTextField = createTextField(editor, tracker.vcsDocument, range.vcsLine1, range.vcsLine2) + installWordDiff(editor, stagedTextField, vcsTextField, range, popupDisposable) - val stagedTextField = createTextField(editor, tracker.stagedDocument, range.stagedLine1, range.stagedLine2) - val vcsTextField = createTextField(editor, tracker.vcsDocument, range.vcsLine1, range.vcsLine2) - installWordDiff(editor, stagedTextField, vcsTextField, range, popupDisposable) + val editorsPanel = createEditorComponent(editor, stagedTextField, vcsTextField) - val editorsPanel = createEditorComponent(editor, stagedTextField, vcsTextField) + val actions = createToolbarActions(editor, range, mousePosition) + val toolbar = LineStatusMarkerPopupPanel.buildToolbar(editor, actions, popupDisposable) - val actions = createToolbarActions(editor, range, mousePosition) - val toolbar = LineStatusMarkerPopupPanel.buildToolbar(editor, actions, popupDisposable) + val additionalPanel = createStageLinksPanel(editor, range, mousePosition, popupDisposable) - val additionalPanel = createStageLinksPanel(editor, range, mousePosition, popupDisposable) - - val popupPanel = LineStatusMarkerPopupPanel.create(editor, toolbar, editorsPanel, additionalPanel) - toolbar.setTargetComponent(popupPanel) - showPopupAt(editor, popupPanel, mousePosition, popupDisposable) + val popupPanel = LineStatusMarkerPopupPanel.create(editor, toolbar, editorsPanel, additionalPanel) + toolbar.setTargetComponent(popupPanel) + popupPanel + } } fun createEditorComponent(editor: Editor, stagedTextField: EditorTextField, vcsTextField: EditorTextField): JComponent {