IDEA-57553 Optimize display of multiple similar editor gutter icons (e.g. Spring autowiring)

This commit is contained in:
Dmitry Avdeev
2014-01-09 15:28:37 +04:00
parent 13fdd3ee05
commit 44fd4639db
7 changed files with 59 additions and 19 deletions
@@ -21,16 +21,20 @@ import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author nik
*/
public class RelatedItemLineMarkerInfo<T extends PsiElement> extends LineMarkerInfo<T> {
public class RelatedItemLineMarkerInfo<T extends PsiElement> extends MergeableLineMarkerInfo<T> {
private final NotNullLazyValue<Collection<? extends GotoRelatedItem>> myTargets;
public RelatedItemLineMarkerInfo(@NotNull T element, @NotNull TextRange range, Icon icon, int updatePass,
@@ -67,6 +71,39 @@ public class RelatedItemLineMarkerInfo<T extends PsiElement> extends LineMarkerI
return new RelatedItemLineMarkerGutterIconRenderer<T>(this);
}
@Override
public boolean canMergeWith(@NotNull MergeableLineMarkerInfo<?> info) {
return myIcon == info.myIcon;
}
@Override
public Icon getCommonIcon(@NotNull List<MergeableLineMarkerInfo> infos) {
return myIcon;
}
@Override
public Function<? super PsiElement, String> getCommonTooltip(@NotNull final List<MergeableLineMarkerInfo> infos) {
return new Function<PsiElement, String>() {
@Override
public String fun(PsiElement element) {
Set<String> tooltips = ContainerUtil.map2Set(infos, new Function<MergeableLineMarkerInfo, String>() {
@Override
public String fun(MergeableLineMarkerInfo info) {
return info.getLineMarkerTooltip();
}
});
StringBuilder tooltip = new StringBuilder();
for (String info : tooltips) {
if (tooltip.length() > 0) {
tooltip.append(UIUtil.BORDER_LINE);
}
tooltip.append(UIUtil.getHtmlBody(info));
}
return "<html><body>" + tooltip.toString() + "</body></html>";
}
};
}
private static class RelatedItemLineMarkerGutterIconRenderer<T extends PsiElement> extends LineMarkerGutterIconRenderer<T> {
public RelatedItemLineMarkerGutterIconRenderer(final RelatedItemLineMarkerInfo<T> markerInfo) {
super(markerInfo);
@@ -135,7 +135,7 @@ public class DaemonTooltipRendererProvider implements ErrorStripTooltipRendererP
@Override
protected boolean dressDescription(@NotNull final Editor editor) {
final List<String> problems = StringUtil.split(UIUtil.getHtmlBody(myText), BORDER_LINE);
final List<String> problems = StringUtil.split(UIUtil.getHtmlBody(myText), UIUtil.BORDER_LINE);
String text = "";
for (String problem : problems) {
final String ref = getLinkRef(problem);
@@ -145,15 +145,15 @@ public class DaemonTooltipRendererProvider implements ErrorStripTooltipRendererP
description = DefaultInspectionToolPresentation.stripUIRefsFromInspectionDescription(UIUtil.getHtmlBody(description));
text += UIUtil.getHtmlBody(problem).replace(DaemonBundle.message("inspection.extended.description"),
DaemonBundle.message("inspection.collapse.description")) +
END_MARKER + "<p>" + description + BORDER_LINE;
END_MARKER + "<p>" + description + UIUtil.BORDER_LINE;
}
}
else {
text += UIUtil.getHtmlBody(problem) + BORDER_LINE;
text += UIUtil.getHtmlBody(problem) + UIUtil.BORDER_LINE;
}
}
if (!text.isEmpty()) { //otherwise do not change anything
myText = "<html><body>" + StringUtil.trimEnd(text, BORDER_LINE) + "</body></html>";
myText = "<html><body>" + StringUtil.trimEnd(text, UIUtil.BORDER_LINE) + "</body></html>";
return true;
}
return false;
@@ -175,14 +175,14 @@ public class DaemonTooltipRendererProvider implements ErrorStripTooltipRendererP
@Override
protected void stripDescription() {
final List<String> problems = StringUtil.split(UIUtil.getHtmlBody(myText), BORDER_LINE);
final List<String> problems = StringUtil.split(UIUtil.getHtmlBody(myText), UIUtil.BORDER_LINE);
myText = "<html><body>";
for (int i = 0, size = problems.size(); i < size; i++) {
final String problem = StringUtil.split(problems.get(i), END_MARKER).get(0);
myText += UIUtil.getHtmlBody(problem).replace(DaemonBundle.message("inspection.collapse.description"),
DaemonBundle.message("inspection.extended.description")) + BORDER_LINE;
DaemonBundle.message("inspection.extended.description")) + UIUtil.BORDER_LINE;
}
myText = StringUtil.trimEnd(myText, BORDER_LINE) + "</body></html>";
myText = StringUtil.trimEnd(myText, UIUtil.BORDER_LINE) + "</body></html>";
}
@Override
@@ -122,10 +122,10 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM
collectLineMarkersForInjected(lineMarkers, elements, this, myFile, progress);
}
myMarkers = mergeLineMarkers(lineMarkers);
myMarkers = mergeLineMarkers(lineMarkers, myEditor);
}
private List<LineMarkerInfo> mergeLineMarkers(@NotNull List<LineMarkerInfo> markers) {
static List<LineMarkerInfo> mergeLineMarkers(@NotNull List<LineMarkerInfo> markers, Editor editor) {
List<MergeableLineMarkerInfo> forMerge = new ArrayList<MergeableLineMarkerInfo>();
final Iterator<LineMarkerInfo> iterator = markers.iterator();
while (iterator.hasNext()) {
@@ -137,12 +137,12 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM
}
}
if (forMerge.isEmpty() || myEditor == null) return markers;
if (forMerge.isEmpty() || editor == null) return markers;
final List<LineMarkerInfo> result = new ArrayList<LineMarkerInfo>(markers);
TIntObjectHashMap<List<MergeableLineMarkerInfo>> sameLineMarkers = new TIntObjectHashMap<List<MergeableLineMarkerInfo>>();
for (MergeableLineMarkerInfo info : forMerge) {
final LogicalPosition position = myEditor.offsetToLogicalPosition(info.startOffset);
final LogicalPosition position = editor.offsetToLogicalPosition(info.startOffset);
List<MergeableLineMarkerInfo> infos = sameLineMarkers.get(position.line);
if (infos == null) {
infos = new ArrayList<MergeableLineMarkerInfo>();
@@ -21,7 +21,7 @@ import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.DumbAware;
@@ -39,14 +39,16 @@ import java.util.Set;
public class SlowLineMarkersPass extends TextEditorHighlightingPass implements LineMarkersProcessor, DumbAware {
private final PsiFile myFile;
@NotNull private final Editor myEditor;
private final int myStartOffset;
private final int myEndOffset;
private volatile Collection<LineMarkerInfo> myMarkers = Collections.emptyList();
public SlowLineMarkersPass(@NotNull Project project, @NotNull PsiFile file, @NotNull Document document, int startOffset, int endOffset) {
super(project, document, false);
public SlowLineMarkersPass(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor, int startOffset, int endOffset) {
super(project, editor.getDocument(), false);
myFile = file;
myEditor = editor;
myStartOffset = startOffset;
myEndOffset = endOffset;
}
@@ -65,7 +67,7 @@ public class SlowLineMarkersPass extends TextEditorHighlightingPass implements L
LineMarkersPass.collectLineMarkersForInjected(markers, elements, this, myFile, progress);
}
myMarkers = markers;
myMarkers = LineMarkersPass.mergeLineMarkers(markers, myEditor);
}
@Override
@@ -47,7 +47,7 @@ public class SlowLineMarkersPassFactory extends AbstractProjectComponent impleme
public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull final Editor editor) {
TextRange textRange = calculateRangeToProcess(editor);
if (textRange == null) return null;
return new SlowLineMarkersPass(myProject, file, editor.getDocument(), textRange.getStartOffset(), textRange.getEndOffset());
return new SlowLineMarkersPass(myProject, file, editor, textRange.getStartOffset(), textRange.getEndOffset());
}
private static TextRange calculateRangeToProcess(Editor editor) {
@@ -45,7 +45,6 @@ import java.net.URL;
* @author cdr
*/
public class LineTooltipRenderer extends ComparableObject.Impl implements TooltipRenderer {
@NonNls protected static final String BORDER_LINE = "<hr size=1 noshade>";
@NonNls protected String myText;
@@ -323,7 +322,7 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
else {
String html1 = UIUtil.getHtmlBody(myText);
String html2 = UIUtil.getHtmlBody(text);
newBody = html1 + BORDER_LINE + html2;
newBody = html1 + UIUtil.BORDER_LINE + html2;
}
myText = "<html><body>" + newBody + "</body></html>";
}
@@ -70,6 +70,8 @@ import java.util.regex.Pattern;
@SuppressWarnings("StaticMethodOnlyUsedInOneClass")
public class UIUtil {
@NonNls public static final String BORDER_LINE = "<hr size=1 noshade>";
private static final AtomicNotNullLazyValue<Boolean> X_RENDER_ACTIVE = new AtomicNotNullLazyValue<Boolean>() {
@NotNull
@Override