[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
This commit is contained in:
Nikolay Chashnikov
2024-09-09 13:01:48 +02:00
committed by intellij-monorepo-bot
parent 56df3d0798
commit c603cbb13d
2 changed files with 35 additions and 19 deletions

View File

@@ -144,6 +144,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i
myUiDisposed = true;
myAutoScrollHandler.cancelAllRequests();
myAutoScrollHandler.resetAlarm();
myContext.getDaemonAnalyzer().clear();

View File

@@ -32,21 +32,28 @@ abstract class AutoScrollToSourceHandler {
private var scheduledNavigationData: WeakReference<Component>? = 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()
}
}