diff --git a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java index 60e026f93b3e..b1d095ac5870 100644 --- a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java +++ b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java @@ -17,15 +17,18 @@ package com.intellij.util.concurrency; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Pair; import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** *

QueueProcessor processes elements which are being added to a queue via {@link #add(Object)} and {@link #addFirst(Object)} methods.

@@ -48,6 +51,7 @@ public class QueueProcessor { private final ThreadToUse myThreadToUse; private final Condition myDeathCondition; + private final Map myModalityState; /** * Constructs a QueueProcessor with the given processor and autostart setting. @@ -65,6 +69,7 @@ public class QueueProcessor { myStarted = autostart; myThreadToUse = threadToUse; myDeathCondition = deathCondition; + myModalityState = new HashMap(); myContinuationContext = new Runnable() { @Override @@ -85,6 +90,11 @@ public class QueueProcessor { this(wrappingProcessor(processor), autostart, ThreadToUse.POOLED, deathCondition); } + public void add(T t, ModalityState state) { + myModalityState.put(new MyOverrideEquals(t), state); + doAdd(t, false); + } + private static PairConsumer wrappingProcessor(final Consumer processor) { return new PairConsumer() { @Override @@ -176,7 +186,12 @@ public class QueueProcessor { }; final Application application = ApplicationManager.getApplication(); if (ThreadToUse.AWT.equals(myThreadToUse)) { - application.invokeLater(runnable); + final ModalityState state = myModalityState.remove(new MyOverrideEquals(item)); + if (state != null) { + application.invokeLater(runnable, state); + } else { + application.invokeLater(runnable); + } } else { application.executeOnPooledThread(runnable); } @@ -193,4 +208,22 @@ public class QueueProcessor { AWT, POOLED } + + private static class MyOverrideEquals { + private final Object myDelegate; + + private MyOverrideEquals(Object delegate) { + myDelegate = delegate; + } + + @Override + public int hashCode() { + return myDelegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return ((MyOverrideEquals) obj).myDelegate == myDelegate; + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java index 0b38bee82dd0..dd2c56c12d81 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java @@ -17,16 +17,21 @@ package com.intellij.openapi.progress; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.PairConsumer; import com.intellij.util.concurrency.QueueProcessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** * Runs backgroundable tasks one by one. * To add a task to the queue use {@link #run(com.intellij.openapi.progress.Task.Backgroundable)} @@ -39,7 +44,7 @@ import org.jetbrains.annotations.Nullable; public class BackgroundTaskQueue { private static final Logger LOG = Logger.getInstance(BackgroundTaskQueue.class.getName()); //private final Project myProject; - private final QueueProcessor myProcessor; + private final QueueProcessor>> myProcessor; private Boolean myForcedTestMode; public BackgroundTaskQueue(@Nullable Project project, @NotNull String title) { @@ -48,7 +53,7 @@ public class BackgroundTaskQueue { public BackgroundTaskQueue(@Nullable final Project project, @NotNull String title, final Boolean forcedHeadlessMode) { final boolean headless = forcedHeadlessMode != null ? forcedHeadlessMode : ApplicationManager.getApplication().isHeadlessEnvironment(); - myProcessor = new QueueProcessor(headless ? + myProcessor = new QueueProcessor>>(headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project), true, headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT, new Condition() { @Override @@ -68,23 +73,28 @@ public class BackgroundTaskQueue { } public void run(Task.Backgroundable task) { + run(task, null, null); + } + + public void run(Task.Backgroundable task, final ModalityState state, final Getter pi) { if (isTestMode()) { // test tasks are executed in this thread without the progress manager RunBackgroundable.runIfBackgroundThread(task, new EmptyProgressIndicator(), null); } else { - myProcessor.add(task); + myProcessor.add(new Pair>(task, pi), state); } } - private static class BackgroundableHeadlessRunner implements PairConsumer { + private static class BackgroundableHeadlessRunner implements PairConsumer>, Runnable> { @Override - public void consume(Task.Backgroundable backgroundable, Runnable runnable) { + public void consume(Pair> pair, Runnable runnable) { + final Task.Backgroundable backgroundable = pair.getFirst(); // synchronously ProgressManager.getInstance().run(backgroundable); runnable.run(); } } - private static class BackgroundableUnderProgressRunner implements PairConsumer { + private static class BackgroundableUnderProgressRunner implements PairConsumer>, Runnable> { private final String myTitle; private final Project myProject; @@ -94,7 +104,8 @@ public class BackgroundTaskQueue { } @Override - public void consume(final Task.Backgroundable backgroundable, final Runnable runnable) { + public void consume(final Pair> pair, final Runnable runnable) { + final Task.Backgroundable backgroundable = pair.getFirst(); final ProgressIndicator[] pi = new ProgressIndicator[1]; final boolean taskTitleIsEmpty = StringUtil.isEmptyOrSpaces(backgroundable.getTitle()); @@ -112,7 +123,12 @@ public class BackgroundTaskQueue { pm.runProcessWithProgressSynchronously(wrappedTask, taskTitleIsEmpty ? myTitle : backgroundable.getTitle(), backgroundable.isCancellable(), myProject); } else { - pi[0] = new BackgroundableProcessIndicator(backgroundable); + if (pair.getSecond() != null) { + pi[0] = pair.getSecond().get(); + } + if (pi[0] == null) { + pi[0] = new BackgroundableProcessIndicator(backgroundable); + } if (taskTitleIsEmpty) { ((BackgroundableProcessIndicator) pi[0]).setTitle(myTitle); }