mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
IJPL-165414: vcs marker: Rework the popup opening
Delegate the popup building and opening to the `LineStatusMarkerPopupService` and control that opened popup is disposed before creating the new marker panel (cherry picked from commit fff881f00d75ce4d4b9fa0fc5fa2e2407f7e8813) IJ-CR-149651 GitOrigin-RevId: 3458a2e0f1e7830d5c67aa539839182840e9d64c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
814318fa18
commit
6901adc6dc
@@ -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);
|
||||
|
||||
@@ -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>(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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user