mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] IJPL-207638 Perform scroll when editor is loaded
GitOrigin-RevId: 1a96cfec52405b77dd471f14b36a802f30bd625b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
81d2497974
commit
b3bd8aa4e0
+56
@@ -4,18 +4,23 @@ package com.intellij.diff.tools.util.base;
|
||||
import com.intellij.diff.requests.DiffRequest;
|
||||
import com.intellij.diff.util.*;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
|
||||
import com.intellij.ide.IdeEventQueue;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diff.DiffNavigationContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.progress.impl.PlatformTaskSupportKt;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.ui.ComponentUtil;
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -123,6 +128,13 @@ public final class InitialScrollPositionSupport {
|
||||
public void onRediff() {
|
||||
if (wasScrolled(getEditors())) myShouldScroll = false;
|
||||
|
||||
if (myShouldScroll) {
|
||||
new DelayedScrollDispatcher(() -> performDelayedSyncScroll()).schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private void performDelayedSyncScroll() {
|
||||
if (wasScrolled(getEditors())) myShouldScroll = false;
|
||||
ensureEditorSizeIsUpToDate(getEditors());
|
||||
if (myShouldScroll) myShouldScroll = !doScrollToChange();
|
||||
if (myShouldScroll) myShouldScroll = !doScrollToLine(false);
|
||||
@@ -172,6 +184,13 @@ public final class InitialScrollPositionSupport {
|
||||
public void onRediff() {
|
||||
if (wasScrolled(getEditors())) myShouldScroll = false;
|
||||
|
||||
if (myShouldScroll) {
|
||||
new DelayedScrollDispatcher(() -> performDelayedSyncScroll()).schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private void performDelayedSyncScroll() {
|
||||
if (wasScrolled(getEditors())) myShouldScroll = false;
|
||||
ensureEditorSizeIsUpToDate(getEditors());
|
||||
if (myShouldScroll) myShouldScroll = !doScrollToChange();
|
||||
if (myShouldScroll) myShouldScroll = !doScrollToLine();
|
||||
@@ -237,6 +256,7 @@ public final class InitialScrollPositionSupport {
|
||||
public static boolean wasScrolled(@NotNull List<? extends Editor> editors) {
|
||||
for (Editor editor : editors) {
|
||||
if (editor == null) continue;
|
||||
if (editor.isDisposed()) return true;
|
||||
if (editor.getCaretModel().getOffset() != 0) return true;
|
||||
if (editor.getScrollingModel().getVerticalScrollOffset() != 0) return true;
|
||||
if (editor.getScrollingModel().getHorizontalScrollOffset() != 0) return true;
|
||||
@@ -276,4 +296,40 @@ public final class InitialScrollPositionSupport {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #onRediff()} can be called synchronously from {@link JComponent#addNotify()} when creating the Diff viewer
|
||||
* to reduce UI flicker - see the {@link DiffViewerBase#init()}.
|
||||
* <p>
|
||||
* To scroll the diff properly, its component and Editors inside need to have correct sizes.
|
||||
* <p>
|
||||
* {@link #ensureEditorSizeIsUpToDate} tries to ensure the sizes are correct, but doing so inside the `addNotify` callback
|
||||
* does not work well, because {@link LayoutManager} constraints are being updated only after the `addNotify` event in {@link Container#addImpl}.
|
||||
* For example, a component added as {@link BorderLayout#CENTER} can report `isValid == true` afterwards but have size (0, 0).
|
||||
* <p>
|
||||
* To ensure correct initial scrolling, we delay it until the end of the current AWT event using an {@link IdeEventQueue} postprocessor.
|
||||
* By then, layout can be performed safely. Thus, we achieve a 'delayed but effectively synchronous' scrolling.
|
||||
* <p>
|
||||
* The callback may be triggered by another AWT event (e.g., while someone is pumping events synchronously), which is acceptable
|
||||
* for this purpose. {@link PlatformTaskSupportKt#pumpEventsForHierarchy(IdeEventQueue, Function0)}
|
||||
*/
|
||||
private static class DelayedScrollDispatcher implements IdeEventQueue.EventDispatcher {
|
||||
@NotNull private final Runnable myScrollTask;
|
||||
|
||||
private DelayedScrollDispatcher(@NotNull Runnable scrollTask) {
|
||||
myScrollTask = scrollTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatch(@NotNull AWTEvent e) {
|
||||
IdeEventQueue.getInstance().removePostprocessor(this);
|
||||
myScrollTask.run();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void schedule() {
|
||||
IdeEventQueue.getInstance().addPostprocessor(this, (Disposable)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user