import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.util.ExceptionUtil;
import org.jetbrains.annotations.NotNull;
-import java.util.concurrent.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
public class ApplicationUtil {
// throws exception if can't grab read action right now
* 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) throws Exception {
+ public static <T> T runWithCheckCanceled(@NotNull final Callable<T> callable, @NotNull final ProgressIndicator indicator) throws Exception {
final Ref<Throwable> error = Ref.create();
Future<T> future = ApplicationManager.getApplication().executeOnPooledThread(new Callable<T>() {
@Override
public T call() throws Exception {
- try {
- return callable.call();
- }
- catch (Throwable t) {
- error.set(t);
- return null;
- }
- };
+ return ProgressManager.getInstance().runProcess(new Computable<T>() {
+ @Override
+ public T compute() {
+ try {
+ return callable.call();
+ }
+ catch (Throwable t) {
+ error.set(t);
+ return null;
+ }
+ }
+ }, indicator);
+ }
});
while (true) {
try {
- ProgressManager.checkCanceled();
+ indicator.checkCanceled();
}
catch (ProcessCanceledException e) {
future.cancel(true);
public CharSequence call() {
return decompiler.decompile(file);
}
- }));
+ }, indicator));
}
catch (Throwable t) {
error.set(t);
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DefaultProjectFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
private final IFernflowerLogger myLogger = new IdeaLogger();
private final Map<String, Object> myOptions = new HashMap<String, Object>();
private boolean myLegalNoticeAccepted;
+ private volatile ProgressIndicator myProgress;
public IdeaDecompiler() {
myOptions.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "0");
return ClsFileImpl.decompile(file);
}
+ myProgress = ProgressManager.getInstance().getProgressIndicator();
+
try {
Map<String, VirtualFile> files = ContainerUtil.newLinkedHashMap();
files.put(file.getPath(), file);
throw new CannotDecompileException(e);
}
}
+ finally {
+ myProgress = null;
+ }
+ }
+
+ @TestOnly
+ @Nullable
+ public ProgressIndicator getProgress() {
+ return myProgress;
}
private static class MyBytecodeProvider implements IBytecodeProvider {
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
import com.intellij.debugger.PositionManager;
+import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.PluginPathManager;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import com.intellij.util.Alarm;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.URLUtil;
}
}).cpuBound().assertTiming();
}
+
+ public void testCancellation() {
+ VirtualFile file = getTestFile(PlatformTestUtil.getRtJarPath() + "!/javax/swing/JTable.class");
+
+ final IdeaDecompiler decompiler = (IdeaDecompiler)ClassFileDecompilers.find(file);
+ assertNotNull(decompiler);
+
+ final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, getProject());
+ alarm.addRequest(new Runnable() {
+ @Override
+ public void run() {
+ ProgressIndicator progress = decompiler.getProgress();
+ if (progress != null) {
+ progress.cancel();
+ }
+ else {
+ alarm.addRequest(this, 200, ModalityState.any());
+ }
+ }
+ }, 750, ModalityState.any());
+
+ try {
+ FileDocumentManager.getInstance().getDocument(file);
+ fail("should have been cancelled");
+ }
+ catch (ProcessCanceledException ignored) { }
+ }
}