From 7bd1718cf52ff4f8b0bd41d67336a53fbba9dc36 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Fri, 9 Oct 2009 17:47:52 +0400 Subject: [PATCH] Deferred class icons for project view --- .../psi/impl/ElementPresentationUtil.java | 16 +++++- .../intellij/psi/impl/PsiClassImplUtil.java | 51 +++++++++++++++++-- .../impl/nodes/AbstractPsiBasedNode.java | 6 +-- .../src/com/intellij/ui/DeferredIconImpl.java | 25 ++++++++- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java b/java/java-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java index a7635b356aaa..2849b320a223 100644 --- a/java/java-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/ElementPresentationUtil.java @@ -27,6 +27,7 @@ public class ElementPresentationUtil { public static final Icon JUNIT_TEST_MARK = IconLoader.getIcon("/nodes/junitTestMark.png"); private static final Icon RUNNABLE_MARK = IconLoader.getIcon("/nodes/runnableMark.png"); + private ElementPresentationUtil() { } @@ -83,6 +84,18 @@ public class ElementPresentationUtil { && CompilerConfiguration.getInstance(project).isExcludedFromCompilation(vFile); } + public static int getBasicClassKind(PsiClass aClass) { + if (!aClass.isValid()) return CLASS_KIND_CLASS; + + if (aClass.isAnnotationType()) return CLASS_KIND_ANNOTATION; + if (aClass.isEnum()) return CLASS_KIND_ENUM; + if (aClass.isInterface()) return CLASS_KIND_INTERFACE; + if (aClass instanceof JspClass) return CLASS_KIND_JSP; + if (aClass instanceof PsiAnonymousClass) return CLASS_KIND_ANONYMOUS; + + return CLASS_KIND_CLASS; + } + public static int getClassKind(final PsiClass aClass) { if (!aClass.isValid()) { aClass.putUserData(CLASS_KIND_KEY, null); @@ -162,8 +175,7 @@ public class ElementPresentationUtil { BASE_ICON.put(CLASS_KIND_RUNNABLE, Icons.CLASS_ICON); } - public static Icon getClassBaseIcon(final PsiClass aClass) { - final int classKind = getClassKind(aClass); + public static Icon getClassIconOfKind(PsiClass aClass, int classKind) { final boolean isAbstract = aClass.hasModifierProperty(PsiModifier.ABSTRACT); return BASE_ICON.get(classKind | (isAbstract ? FLAGS_ABSTRACT : 0)); } diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 14c300586ff6..5b73413dbc99 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -24,7 +24,9 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.PackageScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.*; +import com.intellij.ui.IconDeferrer; import com.intellij.ui.RowIcon; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ReflectionCache; import com.intellij.util.SmartList; @@ -267,11 +269,52 @@ public class PsiClassImplUtil { return (Map>>)value.getValue().get(memberClazz); } + private static class ClassIconRequest { + public PsiClass psiClass; + public int flags; + + private ClassIconRequest(PsiClass psiClass, int flags) { + this.psiClass = psiClass; + this.flags = flags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClassIconRequest)) return false; + + ClassIconRequest that = (ClassIconRequest)o; + + if (flags != that.flags) return false; + if (psiClass != null ? !psiClass.equals(that.psiClass) : that.psiClass != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = psiClass != null ? psiClass.hashCode() : 0; + result = 31 * result + flags; + return result; + } + } + + private static final Function FULL_ICON_EVALUATOR = new Function() { + public Icon fun(ClassIconRequest r) { + final boolean isLocked = (r.flags & Iconable.ICON_FLAG_READ_STATUS) != 0 && !r.psiClass.isWritable(); + Icon symbolIcon = ElementPresentationUtil.getClassIconOfKind(r.psiClass, ElementPresentationUtil.getClassKind(r.psiClass)); + RowIcon baseIcon = ElementBase.createLayeredIcon(symbolIcon, ElementPresentationUtil.getFlags(r.psiClass, isLocked)); + return ElementPresentationUtil.addVisibilityIcon(r.psiClass, r.flags, baseIcon); + } + }; + public static Icon getClassIcon(final int flags, final PsiClass aClass) { - final boolean isLocked = (flags & Iconable.ICON_FLAG_READ_STATUS) != 0 && !aClass.isWritable(); - Icon symbolIcon = ElementPresentationUtil.getClassBaseIcon(aClass); - RowIcon baseIcon = ElementBase.createLayeredIcon(symbolIcon, ElementPresentationUtil.getFlags(aClass, isLocked)); - return ElementPresentationUtil.addVisibilityIcon(aClass, flags, baseIcon); + Icon symbolIcon = ElementPresentationUtil.getClassIconOfKind(aClass, ElementPresentationUtil.getBasicClassKind(aClass)); + RowIcon baseIcon = ElementBase.createLayeredIcon(symbolIcon, 0); + + return IconDeferrer.getInstance().defer(ElementPresentationUtil.addVisibilityIcon(aClass, flags, baseIcon), + new ClassIconRequest(aClass, flags), + FULL_ICON_EVALUATOR); } public static SearchScope getClassUseScope(final PsiClass aClass) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java index ad8a46064e63..ebf4686b3ae3 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java @@ -123,11 +123,7 @@ public abstract class AbstractPsiBasedNode extends ProjectViewNode catch (IndexNotReadyException ignored) { } data.setPresentableText(myName); - try { - data.setTooltip(calcTooltip()); - } - catch (IndexNotReadyException ignored) { - } + try { if (isDeprecated()) { data.setAttributesKey(CodeInsightColors.DEPRECATED_ATTRIBUTES); diff --git a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java index 569532ebd8a8..06897f15b3b3 100644 --- a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java @@ -7,6 +7,7 @@ import com.intellij.concurrency.Job; import com.intellij.concurrency.JobScheduler; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.ui.EmptyIcon; @@ -15,8 +16,11 @@ import javax.swing.plaf.TreeUI; import javax.swing.plaf.basic.BasicTreeUI; import java.awt.*; import java.lang.ref.WeakReference; +import java.util.LinkedHashSet; +import java.util.Set; public class DeferredIconImpl implements DeferredIcon { + private static final RepaintScheduler ourRepaintScheduler = new RepaintScheduler(); private volatile Icon myDelegateIcon; private final Function myEvaluator; private volatile boolean myIsScheduled = false; @@ -96,7 +100,7 @@ public class DeferredIconImpl implements DeferredIcon { c.repaint(x, y, getIconWidth(), getIconHeight()); } else { - target.repaint(); + ourRepaintScheduler.pushDirtyComponent(target); } } }); @@ -171,4 +175,23 @@ public class DeferredIconImpl implements DeferredIcon { lastTarget.repaint(); } } + + private static class RepaintScheduler { + private final Alarm myAlarm = new Alarm(); + private final Set myQueue = new LinkedHashSet(); + + public void pushDirtyComponent(Component c) { + myAlarm.cancelAllRequests(); + myAlarm.addRequest(new Runnable() { + public void run() { + for (Component component : myQueue) { + component.repaint(); + } + myQueue.clear(); + } + }, 50); + + myQueue.add(c); + } + } }