mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
IDEA-270099 Spring: compute event targets in gutter lazily
Support asynchronous mode for NavigationGutterIconRenderer popup calculation GitOrigin-RevId: 69dc72c71b9c3e6b80bc64ec70fc219c2e409d1f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
557da2e0bb
commit
a79bb806ad
@@ -53,7 +53,7 @@ public class NavigationGutterIconBuilder<T> {
|
||||
private final NotNullFunction<? super T, ? extends Collection<? extends PsiElement>> myConverter;
|
||||
|
||||
protected NotNullLazyValue<Collection<? extends T>> myTargets;
|
||||
private boolean myLazy;
|
||||
protected boolean myLazy;
|
||||
protected @Tooltip String myTooltipText;
|
||||
protected @PopupTitle String myPopupTitle;
|
||||
protected @PopupContent String myEmptyText;
|
||||
@@ -288,11 +288,18 @@ public class NavigationGutterIconBuilder<T> {
|
||||
|
||||
@NotNull
|
||||
protected NavigationGutterIconRenderer createGutterIconRenderer(@NotNull NotNullLazyValue<List<SmartPsiElementPointer<?>>> pointers,
|
||||
@NotNull Computable<PsiElementListCellRenderer<?>> renderer,
|
||||
boolean empty) {
|
||||
@NotNull Computable<PsiElementListCellRenderer<?>> renderer,
|
||||
boolean empty) {
|
||||
return new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers, renderer, empty);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected NavigationGutterIconRenderer createLazyGutterIconRenderer(@NotNull NotNullLazyValue<List<SmartPsiElementPointer<?>>> pointers,
|
||||
@NotNull Computable<PsiElementListCellRenderer<?>> renderer,
|
||||
boolean empty) {
|
||||
return new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers, renderer, empty, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <T> NotNullLazyValue<List<SmartPsiElementPointer<?>>> createPointersThunk(boolean lazy,
|
||||
final Project project,
|
||||
@@ -363,6 +370,21 @@ public class NavigationGutterIconBuilder<T> {
|
||||
myEmpty = empty;
|
||||
}
|
||||
|
||||
MyNavigationGutterIconRenderer(@NotNull NavigationGutterIconBuilder<?> builder,
|
||||
@NotNull Alignment alignment,
|
||||
Icon icon,
|
||||
@Nullable @Tooltip String tooltipText,
|
||||
@NotNull NotNullLazyValue<List<SmartPsiElementPointer<?>>> pointers,
|
||||
@NotNull Computable<PsiElementListCellRenderer<?>> cellRenderer,
|
||||
boolean empty,
|
||||
boolean computeTargetsInBackground) {
|
||||
super(builder.myPopupTitle, builder.myEmptyText, cellRenderer, pointers, computeTargetsInBackground);
|
||||
myAlignment = alignment;
|
||||
myIcon = icon;
|
||||
myTooltipText = tooltipText;
|
||||
myEmpty = empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNavigateAction() {
|
||||
return !myEmpty;
|
||||
|
||||
@@ -20,8 +20,11 @@ import com.intellij.codeInsight.hint.HintUtil;
|
||||
import com.intellij.ide.util.PsiElementListCellRenderer;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -32,23 +35,32 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.NlsContexts.PopupContent;
|
||||
import com.intellij.openapi.util.NlsContexts.PopupTitle;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.Segment;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.SmartPsiElementPointer;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.AnimatedIcon;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.intellij.util.concurrency.EdtScheduledExecutorService;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.intellij.openapi.progress.util.ProgressIndicatorUtils.runInReadActionWithWriteActionPriority;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -59,15 +71,25 @@ public abstract class NavigationGutterIconRenderer extends GutterIconRenderer
|
||||
private final @PopupContent String myEmptyText;
|
||||
protected final Computable<? extends PsiElementListCellRenderer> myCellRenderer;
|
||||
private final NotNullLazyValue<? extends List<SmartPsiElementPointer<?>>> myPointers;
|
||||
private final boolean myComputeTargetsInBackground;
|
||||
|
||||
protected NavigationGutterIconRenderer(final @PopupTitle String popupTitle,
|
||||
final @PopupContent String emptyText,
|
||||
protected NavigationGutterIconRenderer(@PopupTitle String popupTitle,
|
||||
@PopupContent String emptyText,
|
||||
@NotNull Computable<? extends PsiElementListCellRenderer<?>> cellRenderer,
|
||||
@NotNull NotNullLazyValue<? extends List<SmartPsiElementPointer<?>>> pointers) {
|
||||
this(popupTitle, emptyText, cellRenderer, pointers, true);
|
||||
}
|
||||
|
||||
protected NavigationGutterIconRenderer(@PopupTitle String popupTitle,
|
||||
@PopupContent String emptyText,
|
||||
Computable<? extends PsiElementListCellRenderer> cellRenderer,
|
||||
NotNullLazyValue<? extends List<SmartPsiElementPointer<?>>> pointers,
|
||||
boolean computeTargetsInBackground) {
|
||||
myPopupTitle = popupTitle;
|
||||
myEmptyText = emptyText;
|
||||
myCellRenderer = cellRenderer;
|
||||
myPointers = pointers;
|
||||
myComputeTargetsInBackground = computeTargetsInBackground;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,13 +139,43 @@ public abstract class NavigationGutterIconRenderer extends GutterIconRenderer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigate(@Nullable final MouseEvent event, @Nullable final PsiElement elt) {
|
||||
List<PsiElement> list = getTargetElements();
|
||||
if (list.isEmpty()) {
|
||||
public void navigate(@Nullable MouseEvent event, @Nullable PsiElement elt) {
|
||||
if (event != null && myComputeTargetsInBackground && event.getComponent() != null) {
|
||||
navigateTargetsAsync(event);
|
||||
}
|
||||
else {
|
||||
navigateTargets(event, getTargetElements());
|
||||
}
|
||||
}
|
||||
|
||||
private void navigateTargetsAsync(@NotNull MouseEvent event) {
|
||||
RelativePoint relativePoint = new RelativePoint(event);
|
||||
Runnable removeIcon = addLoadingIcon(relativePoint);
|
||||
|
||||
AppExecutorUtil.getAppExecutorService().execute(() -> {
|
||||
ProgressManager.getInstance().computePrioritized(() -> {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(() -> {
|
||||
Ref<List<PsiElement>> targets = Ref.create();
|
||||
boolean success = runInReadActionWithWriteActionPriority(() -> targets.set(getTargetElements()));
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
removeIcon.run();
|
||||
if (success) {
|
||||
navigateTargets(event, targets.get());
|
||||
}
|
||||
});
|
||||
}, new EmptyProgressIndicator());
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void navigateTargets(@Nullable MouseEvent event, List<PsiElement> targets) {
|
||||
if (targets.isEmpty()) {
|
||||
if (myEmptyText != null) {
|
||||
if (event != null) {
|
||||
final JComponent label = HintUtil.createErrorLabel(myEmptyText);
|
||||
label.setBorder(JBUI.Borders.empty(2, 7, 2, 7));
|
||||
JComponent label = HintUtil.createErrorLabel(myEmptyText);
|
||||
label.setBorder(JBUI.Borders.empty(2, 7));
|
||||
JBPopupFactory.getInstance().createBalloonBuilder(label)
|
||||
.setFadeoutTime(3000)
|
||||
.setFillColor(HintUtil.getErrorColor())
|
||||
@@ -140,7 +192,7 @@ public abstract class NavigationGutterIconRenderer extends GutterIconRenderer
|
||||
protected void navigateToItems(@Nullable MouseEvent event) {
|
||||
List<Navigatable> navigatables = new ArrayList<>();
|
||||
for (SmartPsiElementPointer<?> pointer : myPointers.getValue()) {
|
||||
ContainerUtil.addIfNotNull(navigatables, getNavigatable(pointer));
|
||||
ContainerUtil.addIfNotNull(navigatables, getNavigatable(pointer));
|
||||
}
|
||||
if (navigatables.size() == 1) {
|
||||
navigatables.get(0).navigate(true);
|
||||
@@ -173,4 +225,30 @@ public abstract class NavigationGutterIconRenderer extends GutterIconRenderer
|
||||
final PsiElement navigationElement = element.getNavigationElement();
|
||||
return navigationElement instanceof Navigatable ? (Navigatable)navigationElement : null;
|
||||
}
|
||||
|
||||
private static @NotNull Runnable addLoadingIcon(@Nullable RelativePoint point) {
|
||||
JRootPane rootPane = point == null ? null : UIUtil.getRootPane(point.getComponent());
|
||||
JComponent glassPane = rootPane == null ? null : (JComponent)rootPane.getGlassPane();
|
||||
if (glassPane == null) return () -> {};
|
||||
|
||||
JLabel icon = new JLabel(AnimatedIcon.Big.INSTANCE);
|
||||
Dimension size = icon.getPreferredSize();
|
||||
icon.setSize(size);
|
||||
Point location = point.getPoint(glassPane);
|
||||
location.x -= size.width / 2;
|
||||
location.y -= size.height / 2;
|
||||
icon.setLocation(location);
|
||||
EdtScheduledExecutorService.getInstance().schedule(() -> {
|
||||
if (!icon.isVisible()) return;
|
||||
glassPane.add(icon);
|
||||
}, 500, TimeUnit.MILLISECONDS);
|
||||
return () -> {
|
||||
if (icon.getParent() != null) {
|
||||
glassPane.remove(icon);
|
||||
}
|
||||
else {
|
||||
icon.setVisible(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user