From 2390fe7eccc08eae1de588bb2611299796f20ef8 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 28 Sep 2012 11:38:24 +0200 Subject: [PATCH] differently-colored tail text fragments --- .../completion/MemberLookupHelper.java | 6 +- .../GlobalMemberNameCompletionTest.groovy | 15 ++- .../lookup/LookupElementPresentation.java | 104 +++++++++++++++--- .../lookup/impl/LookupCellRenderer.java | 48 ++++---- 4 files changed, 130 insertions(+), 43 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java index 812fa657537a..c0afe6988a42 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java @@ -66,10 +66,12 @@ public class MemberLookupHelper { PsiFormatUtil.SHOW_PARAMETERS, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE) : ""; + presentation.clearTail(); + presentation.appendTailText(params, false); if (myShouldImport && StringUtil.isNotEmpty(className)) { - presentation.setTailText(params + " in " + className + location); + presentation.appendTailText(" in " + className + location, true); } else { - presentation.setTailText(params + location, !(myMember instanceof PsiMethod)); + presentation.appendTailText(location, true); } final PsiType type = myMember instanceof PsiMethod ? ((PsiMethod)myMember).getReturnType() : ((PsiField) myMember).getType(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index bf0ace141eac..61339b1568ac 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -67,8 +67,7 @@ public class Foo { """) myFixture.configureByText "a.java", "class Bar {{ abcf }}" def element = complete()[0] - def presentation = new LookupElementPresentation() - element.renderElement(presentation) + def presentation = LookupElementPresentation.renderElement(element) assert 'Foo.abcfield' == presentation.itemText assert ' (foo)' == presentation.tailText assert 'int' == presentation.typeText @@ -162,7 +161,14 @@ class Bar {{ abcmethod1() }}""" """) myFixture.configureByText("a.java", "class Bar {{ abcm }}") - complete() + def element = complete()[0] + + def tail = LookupElementPresentation.renderElement(element).tailFragments + assert tail[0].text == '(...)' + assert !tail[0].grayed + assert tail[1].text == ' (foo)' + assert tail[1].grayed + assertOrderedEquals myFixture.lookupElementStrings, "abcmethod", "abcmethod1" } @@ -177,8 +183,7 @@ class A { } """) def element = complete()[0] - def presentation = new LookupElementPresentation() - element.renderElement(presentation) + def presentation = LookupElementPresentation.renderElement(element) assert 'foo' == presentation.itemText myFixture.type '\n' myFixture.checkResult ''' diff --git a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java index e8552d0191e2..8c3fd139f5d4 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java +++ b/platform/lang-api/src/com/intellij/codeInsight/lookup/LookupElementPresentation.java @@ -15,11 +15,16 @@ */ package com.intellij.codeInsight.lookup; -import org.jetbrains.annotations.Nullable; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.util.Collections; +import java.util.List; /** * @author peter @@ -28,15 +33,13 @@ public class LookupElementPresentation { private Icon myIcon; private Icon myTypeIcon; private String myItemText; - private String myTailText; private String myTypeText; private boolean myStrikeout; - private boolean myTailGrayed; - private Color myTailForeground; private Color myItemTextForeground = Color.black; private boolean myItemTextBold; private boolean myItemTextUnderlined; private boolean myTypeGrayed; + @Nullable private List myTail; public void setIcon(@Nullable Icon icon) { myIcon = icon; @@ -58,14 +61,33 @@ public class LookupElementPresentation { setTailText(text, false); } + public void clearTail() { + myTail = null; + } + + public void appendTailText(@NotNull String text, boolean grayed) { + appendTailText(new TextFragment(text, grayed, null)); + } + + private void appendTailText(@NotNull TextFragment fragment) { + if (myTail == null) { + myTail = new SmartList(); + } + myTail.add(fragment); + } + public void setTailText(@Nullable String text, boolean grayed) { - myTailText = text; - myTailGrayed = grayed; + clearTail(); + if (text != null) { + appendTailText(new TextFragment(text, grayed, null)); + } } public void setTailText(@Nullable String text, @Nullable Color foreground) { - myTailText = text; - myTailForeground = foreground; + clearTail(); + if (text != null) { + appendTailText(new TextFragment(text, false, foreground)); + } } public void setTypeText(@Nullable String text) { @@ -102,9 +124,21 @@ public class LookupElementPresentation { return myItemText; } + @NotNull + public List getTailFragments() { + return myTail == null ? Collections.emptyList() : Collections.unmodifiableList(myTail); + } + @Nullable + @Deprecated public String getTailText() { - return myTailText; + if (myTail == null) return null; + return StringUtil.join(myTail, new Function() { + @Override + public String fun(TextFragment fragment) { + return fragment.text; + } + }, ""); } @Nullable @@ -116,13 +150,15 @@ public class LookupElementPresentation { return myStrikeout; } + @Deprecated public boolean isTailGrayed() { - return myTailGrayed; + return myTail != null && myTail.get(0).grayed; } @Nullable + @Deprecated public Color getTailForeground() { - return myTailForeground; + return myTail != null ? myTail.get(0).fgColor : null; } public boolean isItemTextBold() { @@ -149,11 +185,12 @@ public class LookupElementPresentation { myIcon = presentation.myIcon; myTypeIcon = presentation.myTypeIcon; myItemText = presentation.myItemText; - myTailText = presentation.myTailText; + + List thatTail = presentation.myTail; + myTail = thatTail == null ? null : new SmartList(thatTail); + myTypeText = presentation.myTypeText; myStrikeout = presentation.myStrikeout; - myTailGrayed = presentation.myTailGrayed; - myTailForeground = presentation.myTailForeground; myItemTextBold = presentation.myItemTextBold; myTypeGrayed = presentation.myTypeGrayed; myItemTextUnderlined = presentation.myItemTextUnderlined; @@ -173,4 +210,43 @@ public class LookupElementPresentation { element.renderElement(presentation); return presentation; } + + @Override + public String toString() { + return "LookupElementPresentation{" + + ", itemText='" + myItemText + '\'' + + ", tail=" + myTail + + ", typeText='" + myTypeText + '\'' + + '}'; + } + + public static class TextFragment { + public final String text; + private final boolean grayed; + @Nullable private final Color fgColor; + + public TextFragment(String text, boolean grayed, @Nullable Color fgColor) { + this.text = text; + this.grayed = grayed; + this.fgColor = fgColor; + } + + @Override + public String toString() { + return "TextFragment{" + + "text='" + text + '\'' + + ", grayed=" + grayed + + ", fgColor=" + fgColor + + '}'; + } + + public boolean isGrayed() { + return grayed; + } + + @Nullable + public Color getForegroundColor() { + return fgColor; + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index 2d2547d9be3f..f13ca83b24ec 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -193,21 +193,17 @@ public class LookupCellRenderer implements ListCellRenderer { } private void setTailTextLabel(boolean isSelected, LookupElementPresentation presentation, Color foreground, int allowedWidth) { - final Color fg = getTailTextColor(isSelected, presentation, foreground); + int style = getStyle(false, presentation.isStrikeout(), false); - final String tailText = StringUtil.notNullize(presentation.getTailText()); + for (LookupElementPresentation.TextFragment fragment : presentation.getTailFragments()) { + if (allowedWidth < 0) { + return; + } - int style = SimpleTextAttributes.STYLE_PLAIN; - if (presentation.isStrikeout()) { - style |= SimpleTextAttributes.STYLE_STRIKEOUT; + String trimmed = trimLabelText(fragment.text, allowedWidth, myNormalMetrics); + myTailComponent.append(trimmed, new SimpleTextAttributes(style, getTailTextColor(isSelected, fragment, foreground))); + allowedWidth -= RealLookupElementPresentation.getStringWidth(trimmed, myNormalMetrics); } - - SimpleTextAttributes attributes = new SimpleTextAttributes(style, fg); - if (allowedWidth < 0) { - return; - } - - myTailComponent.append(trimLabelText(tailText, allowedWidth, myNormalMetrics), attributes); } private String trimLabelText(@Nullable String text, int maxWidth, FontMetrics metrics) { @@ -240,13 +236,13 @@ public class LookupCellRenderer implements ListCellRenderer { return text.substring(0, i) + ELLIPSIS; } - public static Color getTailTextColor(boolean isSelected, LookupElementPresentation presentation, Color defaultForeground) { - if (presentation.isTailGrayed()) { + public static Color getTailTextColor(boolean isSelected, LookupElementPresentation.TextFragment fragment, Color defaultForeground) { + if (fragment.isGrayed()) { return getGrayedForeground(isSelected); } if (!isSelected) { - final Color tailForeground = presentation.getTailForeground(); + final Color tailForeground = fragment.getForegroundColor(); if (tailForeground != null) { return tailForeground; } @@ -264,13 +260,7 @@ public class LookupCellRenderer implements ListCellRenderer { myNameComponent.setFont(bold ? myBoldFont : myNormalFont); - int style = bold ? SimpleTextAttributes.STYLE_BOLD : SimpleTextAttributes.STYLE_PLAIN; - if (presentation.isStrikeout()) { - style |= SimpleTextAttributes.STYLE_STRIKEOUT; - } - if (presentation.isItemTextUnderlined()) { - style |= SimpleTextAttributes.STYLE_UNDERLINE; - } + int style = getStyle(bold, presentation.isStrikeout(), presentation.isItemTextUnderlined()); final FontMetrics metrics = bold ? myBoldMetrics : myNormalMetrics; final String name = trimLabelText(presentation.getItemText(), allowedWidth, metrics); @@ -280,6 +270,18 @@ public class LookupCellRenderer implements ListCellRenderer { return used; } + @SimpleTextAttributes.StyleAttributeConstant + private static int getStyle(boolean bold, boolean strikeout, boolean underlined) { + int style = bold ? SimpleTextAttributes.STYLE_BOLD : SimpleTextAttributes.STYLE_PLAIN; + if (strikeout) { + style |= SimpleTextAttributes.STYLE_STRIKEOUT; + } + if (underlined) { + style |= SimpleTextAttributes.STYLE_UNDERLINE; + } + return style; + } + private void renderItemName(LookupElement item, Color foreground, boolean selected, @@ -321,7 +323,9 @@ public class LookupCellRenderer implements ListCellRenderer { Color sampleBackground = background; Object o = item.getObject(); + //noinspection deprecation if (o instanceof LookupValueWithUIHint && StringUtil.isEmpty(labelText)) { + //noinspection deprecation Color proposedBackground = ((LookupValueWithUIHint)o).getColorHint(); if (proposedBackground != null) { sampleBackground = proposedBackground;