background task queue: allow to specify modality and custom progress for the task

This commit is contained in:
irengrig
2011-02-17 15:31:23 +03:00
parent 4d6af14ac2
commit 908fc66b20
2 changed files with 61 additions and 12 deletions
@@ -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.*;
/**
* <p>QueueProcessor processes elements which are being added to a queue via {@link #add(Object)} and {@link #addFirst(Object)} methods.</p>
@@ -48,6 +51,7 @@ public class QueueProcessor<T> {
private final ThreadToUse myThreadToUse;
private final Condition<?> myDeathCondition;
private final Map<MyOverrideEquals, ModalityState> myModalityState;
/**
* Constructs a QueueProcessor with the given processor and autostart setting.
@@ -65,6 +69,7 @@ public class QueueProcessor<T> {
myStarted = autostart;
myThreadToUse = threadToUse;
myDeathCondition = deathCondition;
myModalityState = new HashMap<MyOverrideEquals, ModalityState>();
myContinuationContext = new Runnable() {
@Override
@@ -85,6 +90,11 @@ public class QueueProcessor<T> {
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<T> PairConsumer<T, Runnable> wrappingProcessor(final Consumer<T> processor) {
return new PairConsumer<T, Runnable>() {
@Override
@@ -176,7 +186,12 @@ public class QueueProcessor<T> {
};
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<T> {
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;
}
}
}
@@ -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<Task.Backgroundable> myProcessor;
private final QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>> 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<Task.Backgroundable>(headless ?
myProcessor = new QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>>(headless ?
new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project), true,
headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT, new Condition<Object>() {
@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<ProgressIndicator> 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.Backgroundable, Getter<ProgressIndicator>>(task, pi), state);
}
}
private static class BackgroundableHeadlessRunner implements PairConsumer<Task.Backgroundable, Runnable> {
private static class BackgroundableHeadlessRunner implements PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> {
@Override
public void consume(Task.Backgroundable backgroundable, Runnable runnable) {
public void consume(Pair<Task.Backgroundable, Getter<ProgressIndicator>> pair, Runnable runnable) {
final Task.Backgroundable backgroundable = pair.getFirst();
// synchronously
ProgressManager.getInstance().run(backgroundable);
runnable.run();
}
}
private static class BackgroundableUnderProgressRunner implements PairConsumer<Task.Backgroundable, Runnable> {
private static class BackgroundableUnderProgressRunner implements PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, 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<Task.Backgroundable, Getter<ProgressIndicator>> 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);
}