From 51ae9fd4ace7ed35e85f6e3b414deca25fc0d8c2 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 15 Nov 2012 11:46:22 +0400 Subject: [PATCH] do not block DeferredIcon in readAction --- .../src/com/intellij/ui/DeferredIcon.java | 3 + .../src/com/intellij/ui/DeferredIconImpl.java | 235 +++++++++--------- .../src/com/intellij/ui/IconDeferrerImpl.java | 15 +- 3 files changed, 127 insertions(+), 126 deletions(-) diff --git a/platform/core-api/src/com/intellij/ui/DeferredIcon.java b/platform/core-api/src/com/intellij/ui/DeferredIcon.java index f184988a0616..80cf3aa57692 100644 --- a/platform/core-api/src/com/intellij/ui/DeferredIcon.java +++ b/platform/core-api/src/com/intellij/ui/DeferredIcon.java @@ -19,8 +19,11 @@ */ package com.intellij.ui; +import org.jetbrains.annotations.NotNull; + import javax.swing.*; public interface DeferredIcon extends Icon { + @NotNull Icon evaluate(); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java index 3de445a996dd..b0cbefe2ca97 100644 --- a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java @@ -21,9 +21,9 @@ package com.intellij.ui; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobLauncher; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.IndexNotReadyException; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.tabs.impl.TabLabel; import com.intellij.util.Alarm; @@ -63,7 +63,7 @@ public class DeferredIconImpl implements DeferredIcon { } private static Icon nonNull(final Icon icon) { - return icon != null ? icon : EMPTY_ICON; + return icon == null ? EMPTY_ICON : icon; } @Override @@ -72,107 +72,128 @@ public class DeferredIconImpl implements DeferredIcon { myDelegateIcon.paintIcon(c, g, x, y); //SOE protection } - if (!myIsScheduled && !isDone()) { - myIsScheduled = true; + if (myIsScheduled || isDone()) { + return; + } + myIsScheduled = true; - final Ref target = new Ref(null); - final Ref paintingParent = new Ref(null); - final Ref paintingParentRec = new Ref(null); + final Component target = getTarget(c); + final Component paintingParent = SwingUtilities.getAncestorOfClass(PaintingParent.class, c); + final Rectangle paintingParentRec = paintingParent == null ? null : ((PaintingParent)paintingParent).getChildRec(c); - final Container list = SwingUtilities.getAncestorOfClass(JList.class, c); - if (list != null) { - target.set(list); - } - else { - final Container tree = SwingUtilities.getAncestorOfClass(JTree.class, c); - if (tree != null) { - target.set(tree); - } - else { - final Container table = SwingUtilities.getAncestorOfClass(JTable.class, c); - if (table != null) { - target.set(table); - } - else { - final Container box = SwingUtilities.getAncestorOfClass(JComboBox.class, c); - if (box != null) { - target.set(box); + JobLauncher.getInstance().submitToJobThread(Job.DEFAULT_PRIORITY, new Runnable() { + @Override + public void run() { + int oldWidth = myDelegateIcon.getIconWidth(); + final Icon[] evaluated = new Icon[1]; + final Runnable evalRunnable = new Runnable() { + @Override + public void run() { + try { + evaluated[0] = nonNull(myEvaluator.fun(myParam)); } - else { - final Container tabLabel = SwingUtilities.getAncestorOfClass(TabLabel.class, c); - if(tabLabel != null) { - target.set(tabLabel); - } - else { - target.set(c); - } + catch (ProcessCanceledException e) { + evaluated[0] = EMPTY_ICON; + } + catch (IndexNotReadyException e) { + evaluated[0] = EMPTY_ICON; } } - } - } + }; - Container pp = SwingUtilities.getAncestorOfClass(PaintingParent.class, c); - paintingParent.set(pp); - if (paintingParent.get() != null) { - paintingParentRec.set(((PaintingParent)pp).getChildRec(c)); - } - - JobLauncher.getInstance().submitToJobThread(Job.DEFAULT_PRIORITY, new Runnable() { - @Override - public void run() { - int oldWidth = myDelegateIcon.getIconWidth(); - final Icon result = evaluate(); - myDelegateIcon = result; - - final boolean shouldRevalidate = - Registry.is("ide.tree.deferred.icon.invalidates.cache") && myDelegateIcon.getIconWidth() != oldWidth; - - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { + if (myNeedReadAction) { + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() { @Override public void run() { - setDone(result); + IconDeferrerImpl.evaluateDeferred(evalRunnable); + } + })) { + System.out.println("Redeferring"); + myIsScheduled = false; + return; + } + } + else { + IconDeferrerImpl.evaluateDeferred(evalRunnable); + } + final Icon result = evaluated[0]; + myDelegateIcon = result; - Component actualTarget = target.get(); - if (actualTarget != null && SwingUtilities.getWindowAncestor(actualTarget) == null) { - actualTarget = paintingParent.get(); - if (actualTarget == null || SwingUtilities.getWindowAncestor(actualTarget) == null) { - actualTarget = null; - } - } + final boolean shouldRevalidate = + Registry.is("ide.tree.deferred.icon.invalidates.cache") && myDelegateIcon.getIconWidth() != oldWidth; - if (actualTarget == null) return; + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setDone(result); - if (shouldRevalidate) { - // revalidate will not work: jtree caches size of nodes - if (actualTarget instanceof JTree) { - final TreeUI ui = ((JTree)actualTarget).getUI(); - if (ui instanceof BasicTreeUI) { - // this call is "fake" and only need to reset tree layout cache - ((BasicTreeUI)ui).setLeftChildIndent(UIUtil.getTreeLeftChildIndent()); - } - } - } - - if (c == actualTarget) { - c.repaint(x, y, getIconWidth(), getIconHeight()); - } - else { - Rectangle rec = null; - if (paintingParentRec.get() != null) { - rec = paintingParentRec.get(); - } - - ourRepaintScheduler.pushDirtyComponent(actualTarget, rec); + Component actualTarget = target; + if (actualTarget != null && SwingUtilities.getWindowAncestor(actualTarget) == null) { + actualTarget = paintingParent; + if (actualTarget == null || SwingUtilities.getWindowAncestor(actualTarget) == null) { + actualTarget = null; } } - }); - } - }); - } + + if (actualTarget == null) return; + + if (shouldRevalidate) { + // revalidate will not work: jtree caches size of nodes + if (actualTarget instanceof JTree) { + final TreeUI ui = ((JTree)actualTarget).getUI(); + if (ui instanceof BasicTreeUI) { + // this call is "fake" and only need to reset tree layout cache + ((BasicTreeUI)ui).setLeftChildIndent(UIUtil.getTreeLeftChildIndent()); + } + } + } + + if (c == actualTarget) { + c.repaint(x, y, getIconWidth(), getIconHeight()); + } + else { + ourRepaintScheduler.pushDirtyComponent(actualTarget, paintingParentRec); + } + } + }); + } + }); } - private void setDone(Icon result) { + private static Component getTarget(Component c) { + final Component target; + + final Container list = SwingUtilities.getAncestorOfClass(JList.class, c); + if (list != null) { + target = list; + } + else { + final Container tree = SwingUtilities.getAncestorOfClass(JTree.class, c); + if (tree != null) { + target = tree; + } + else { + final Container table = SwingUtilities.getAncestorOfClass(JTable.class, c); + if (table != null) { + target = table; + } + else { + final Container box = SwingUtilities.getAncestorOfClass(JComboBox.class, c); + if (box != null) { + target = box; + } + else { + final Container tabLabel = SwingUtilities.getAncestorOfClass(TabLabel.class, c); + target = tabLabel == null ? c : tabLabel; + } + } + } + } + return target; + } + + private void setDone(@NotNull Icon result) { if (myEvalListener != null) { myEvalListener.evalDone(myParam, result); } @@ -182,33 +203,23 @@ public class DeferredIconImpl implements DeferredIcon { myParam = null; } + @NotNull @Override public Icon evaluate() { - final Icon[] evaluated = new Icon[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - try { - evaluated[0] = nonNull(myEvaluator.fun(myParam)); - } - catch (ProcessCanceledException e) { - evaluated[0] = EMPTY_ICON; - } - catch (IndexNotReadyException e) { - evaluated[0] = EMPTY_ICON; - } - } - }; - if (myNeedReadAction) { - IconDeferrerImpl.evaluateDeferredInReadAction(runnable); + Icon result; + try { + result = nonNull(myEvaluator.fun(myParam)); } - else { - IconDeferrerImpl.evaluateDeferred(runnable); + catch (ProcessCanceledException e) { + result = EMPTY_ICON; + } + catch (IndexNotReadyException e) { + result = EMPTY_ICON; } - checkDoesntReferenceThis(evaluated[0]); + checkDoesntReferenceThis(result); - return evaluated[0]; + return result; } private void checkDoesntReferenceThis(final Icon icon) { @@ -290,14 +301,12 @@ public class DeferredIconImpl implements DeferredIcon { } } - - public DeferredIconImpl setDoneListener(IconListener disposer) { + public DeferredIconImpl setDoneListener(@NotNull IconListener disposer) { myEvalListener = disposer; return this; } public interface IconListener { - void evalDone(T key, Icon result); + void evalDone(T key, @NotNull Icon result); } - } diff --git a/platform/lang-impl/src/com/intellij/ui/IconDeferrerImpl.java b/platform/lang-impl/src/com/intellij/ui/IconDeferrerImpl.java index 1be1d296dfc2..33440e790d36 100644 --- a/platform/lang-impl/src/com/intellij/ui/IconDeferrerImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/IconDeferrerImpl.java @@ -19,7 +19,6 @@ */ package com.intellij.ui; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.impl.ProjectLifecycleListener; import com.intellij.psi.util.PsiModificationTracker; @@ -72,7 +71,7 @@ public class IconDeferrerImpl extends IconDeferrer { final long started = myLastClearTimestamp; result = new DeferredIconImpl(base, param, f).setDoneListener(new DeferredIconImpl.IconListener() { @Override - public void evalDone(T key, Icon r) { + public void evalDone(T key, @NotNull Icon r) { synchronized (LOCK) { // check if our results is not outdated yet if (started == myLastClearTimestamp) { @@ -95,17 +94,7 @@ public class IconDeferrerImpl extends IconDeferrer { } }; - public static void evaluateDeferredInReadAction(final Runnable runnable) { - try { - myEvaluationIsInProgress.set(Boolean.TRUE); - ApplicationManager.getApplication().runReadAction(runnable); - } - finally { - myEvaluationIsInProgress.set(Boolean.FALSE); - } - } - - public static void evaluateDeferred(final Runnable runnable) { + public static void evaluateDeferred(@NotNull Runnable runnable) { try { myEvaluationIsInProgress.set(Boolean.TRUE); runnable.run();