From c603cbb13d3af79bdcdc1f461d3c5340d4ba470b Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Mon, 9 Sep 2024 13:01:48 +0200 Subject: [PATCH] [project structure dialog] properly handle selection changes after reopening the dialog (IJPL-161905) After e7b38952621668, AutoScrollToSourceHandler remembers the modality state which it uses for processing events on the first invocation. However, it's used in BaseStructureConfigurable instances, which are reused each time the Project Structure dialog is opened (see IJPL-21800). And then the dialog is opened for the second time, it stops processing auto-scroll events. It's not that simple to fix IJPL-21800. So as a temporary solution, an internal 'resetAlarm' function was added and called when the dialog is closed to reset the instance and ensure that it'll be recreated with the proper modality state the next time the dialog is opened. GitOrigin-RevId: 68af8a98a7d73a50d8cbc7889e4ab9a229d3ad54 --- .../BaseStructureConfigurable.java | 1 + .../intellij/ui/AutoScrollToSourceHandler.kt | 53 ++++++++++++------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java index 658760b91699..f00631ed2eba 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java @@ -144,6 +144,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i myUiDisposed = true; myAutoScrollHandler.cancelAllRequests(); + myAutoScrollHandler.resetAlarm(); myContext.getDaemonAnalyzer().clear(); diff --git a/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.kt b/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.kt index 3a451c1af1b9..dc671312335b 100644 --- a/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.kt +++ b/platform/platform-api/src/com/intellij/ui/AutoScrollToSourceHandler.kt @@ -32,21 +32,28 @@ abstract class AutoScrollToSourceHandler { private var scheduledNavigationData: WeakReference? = null // access only from EDT - private val autoScrollAlarm = lazy(LazyThreadSafetyMode.NONE) { - SingleAlarm( - task = { - val component = scheduledNavigationData?.get() ?: return@SingleAlarm - scheduledNavigationData = null - // for tests - if (component.isShowing && (!needToCheckFocus() || UIUtil.hasFocus(component))) { - scrollToSource(component) - } - }, - delay = Registry.intValue("ide.autoscroll.to.source.delay", 100), - parentDisposable = null, - threadToUse = Alarm.ThreadToUse.SWING_THREAD, - modalityState = ModalityState.defaultModalityState(), - ) + private var autoScrollAlarm: SingleAlarm? = null + + private fun getOrCreateAutoScrollAlarm(): SingleAlarm { + var alarm = autoScrollAlarm + if (alarm == null) { + alarm = SingleAlarm( + task = { + val component = scheduledNavigationData?.get() ?: return@SingleAlarm + scheduledNavigationData = null + // for tests + if (component.isShowing && (!needToCheckFocus() || UIUtil.hasFocus(component))) { + scrollToSource(component) + } + }, + delay = Registry.intValue("ide.autoscroll.to.source.delay", 100), + parentDisposable = null, + threadToUse = Alarm.ThreadToUse.SWING_THREAD, + modalityState = ModalityState.defaultModalityState(), + ) + autoScrollAlarm = alarm + } + return alarm } fun install(tree: JTree) { @@ -114,9 +121,17 @@ abstract class AutoScrollToSourceHandler { } fun cancelAllRequests() { - if (autoScrollAlarm.isInitialized()) { - autoScrollAlarm.value.cancel() - } + autoScrollAlarm?.cancel() + } + + /** + * Resets the internal instance to ensure that it'll be recreated properly if the component is reused in a different modal dialog. + * This is a temporary solution specifically for the Project Structure dialog, it's better to recreate components instead of reusing them. + */ + @ApiStatus.Internal + @ApiStatus.Obsolete + fun resetAlarm() { + autoScrollAlarm = null } fun onMouseClicked(component: Component) { @@ -129,7 +144,7 @@ abstract class AutoScrollToSourceHandler { private fun onSelectionChanged(component: Component?) { if (component != null && component.isShowing && isAutoScrollMode()) { scheduledNavigationData = WeakReference(component) - autoScrollAlarm.value.cancelAndRequest() + getOrCreateAutoScrollAlarm().cancelAndRequest() } }