[platform] modal computational task with result

This commit is contained in:
Roman Shevchenko
2015-12-08 21:32:34 +01:00
parent 2e0b940dd1
commit cd3d671f10
4 changed files with 69 additions and 35 deletions
@@ -176,6 +176,14 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
*/
public abstract void run(@NotNull Task task);
/**
* Runs a specified computation with a modal progress dialog.
*/
public <T, E extends Exception> T run(@NotNull Task.WithResult<T, E> task) throws E {
run((Task)task);
return task.getResult();
}
public abstract void runProcessWithProgressAsynchronously(@NotNull Task.Backgroundable task, @NotNull ProgressIndicator progressIndicator);
protected void indicatorCanceled(@NotNull ProgressIndicator indicator) { }
@@ -270,4 +270,33 @@ public abstract class Task implements TaskInfo, Progressive {
return myShowWhenFocused;
}
}
public abstract static class WithResult<T, E extends Exception> extends Task.Modal {
private final Ref<T> myResult = Ref.create();
private final Ref<Throwable> myError = Ref.create();
public WithResult(@Nullable Project project, @Nls(capitalization = Nls.Capitalization.Title) @NotNull String title, boolean canBeCancelled) {
super(project, title, canBeCancelled);
}
@Override
public final void run(@NotNull ProgressIndicator indicator) {
try {
myResult.set(compute(indicator));
}
catch (Throwable t) {
myError.set(t);
}
}
protected abstract T compute(@NotNull ProgressIndicator indicator) throws E;
@SuppressWarnings("unchecked")
public T getResult() throws E {
Throwable t = myError.get();
ExceptionUtil.rethrowUnchecked(t);
if (t != null) throw (E)t;
return myResult.get();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,21 +52,32 @@ public class ApplicationUtil {
* Allows to interrupt a process which does not performs checkCancelled() calls by itself.
* Note that the process may continue to run in background indefinitely - so <b>avoid using this method unless absolutely needed</b>.
*/
public static <T> T runWithCheckCanceled(@NotNull final Callable<T> callable,
@NotNull final ProgressIndicator indicator) throws Exception {
return runWithCheckCanceled(callable, indicator, PooledThreadExecutor.INSTANCE);
public static <T> T runWithCheckCanceled(@NotNull final Computable<T> computable, @NotNull ProgressIndicator indicator) {
try {
return runWithCheckCanceled(new Callable<T>() {
@Override
public T call() throws Exception {
return computable.compute();
}
}, indicator);
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Allows to interrupt a process which does not performs checkCancelled() calls by itself.
* Note that the process may continue to run in background indefinitely - so <b>avoid using this method unless absolutely needed</b>.
*/
public static <T> T runWithCheckCanceled(@NotNull final Callable<T> callable,
@NotNull final ProgressIndicator indicator, @NotNull ExecutorService executorService) throws Exception {
public static <T> T runWithCheckCanceled(@NotNull final Callable<T> callable, @NotNull final ProgressIndicator indicator) throws Exception {
final Ref<T> result = Ref.create();
final Ref<Throwable> error = Ref.create();
Future<?> future = executorService.submit(new Runnable() {
Future<?> future = PooledThreadExecutor.INSTANCE.submit(new Runnable() {
@Override
public void run() {
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
@@ -108,4 +119,4 @@ public class ApplicationUtil {
return this;
}
}
}
}
@@ -27,9 +27,9 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -38,7 +38,6 @@ import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.Nls;
@@ -50,13 +49,11 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.concurrent.Callable;
public final class LoadTextUtil {
@Nls private static final String AUTO_DETECTED_FROM_BOM = "auto-detected from BOM";
private LoadTextUtil() {
}
private LoadTextUtil() { }
@NotNull
private static Pair<CharSequence, String> convertLineSeparators(@NotNull CharBuffer buffer) {
@@ -248,7 +245,7 @@ public final class LoadTextUtil {
* it is considered to be an external change if <code>requestor</code> is <code>null</code>.
* See {@link com.intellij.openapi.vfs.VirtualFileEvent#getRequestor}
* @param newModificationStamp new modification stamp or -1 if no special value should be set @return <code>Writer</code>
* @throws java.io.IOException if an I/O error occurs
* @throws IOException if an I/O error occurs
* @see VirtualFile#getModificationStamp()
*/
public static void write(@Nullable Project project,
@@ -371,35 +368,23 @@ public final class LoadTextUtil {
Application app = ApplicationManager.getApplication();
if (app != null && app.isDispatchThread() && !app.isWriteAccessAllowed() && !ourDecompileProgressStarted) {
final Ref<CharSequence> result = Ref.create(ArrayUtil.EMPTY_CHAR_SEQUENCE);
final Ref<Throwable> error = Ref.create();
ourDecompileProgressStarted = true;
try {
ProgressManager.getInstance().run(new Task.Modal(null, "Decompiling " + file.getName(), true) {
text = ProgressManager.getInstance().run(new Task.WithResult<CharSequence, RuntimeException>(null, "Decompiling " + file.getName(), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(true);
try {
result.set(ApplicationUtil.runWithCheckCanceled(new Callable<CharSequence>() {
@Override
public CharSequence call() {
return decompiler.decompile(file);
}
}, indicator));
}
catch (Throwable t) {
error.set(t);
}
protected CharSequence compute(@NotNull ProgressIndicator indicator) {
return ApplicationUtil.runWithCheckCanceled(new Computable<CharSequence>() {
@Override
public CharSequence compute() {
return decompiler.decompile(file);
}
}, indicator);
}
});
}
finally {
ourDecompileProgressStarted = false;
}
ExceptionUtil.rethrowUnchecked(error.get());
text = result.get();
}
else {
text = decompiler.decompile(file);
@@ -409,7 +394,8 @@ public final class LoadTextUtil {
return text;
}
throw new IllegalArgumentException("Attempt to load text for binary file which doesn't have a decompiler plugged in: " + file.getPresentableUrl() + ". File type: " + fileType.getName());
throw new IllegalArgumentException("Attempt to load text for binary file which doesn't have a decompiler plugged in: " +
file.getPresentableUrl() + ". File type: " + fileType.getName());
}
try {