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;
* 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<T> result = Ref.create();
final Ref<Throwable> error = Ref.create();
- Future<T> future = ApplicationManager.getApplication().executeOnPooledThread(new Callable<T>() {
+ Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
- public T call() throws Exception {
- try {
- return callable.call();
- }
- catch (Throwable t) {
- error.set(t);
- return null;
- }
+ public void run() {
+ ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ result.set(callable.call());
+ }
+ catch (Throwable t) {
+ error.set(t);
+ }
+ }
+ }, indicator);
}
});
while (true) {
try {
- ProgressManager.checkCanceled();
+ indicator.checkCanceled();
}
catch (ProcessCanceledException e) {
future.cancel(true);
}
try {
- T result = future.get(200, TimeUnit.MILLISECONDS);
+ future.get(200, TimeUnit.MILLISECONDS);
ExceptionUtil.rethrowAll(error.get());
- return result;
+ return result.get();
}
catch (TimeoutException ignored) { }
}
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 final Map<VirtualFile, ProgressIndicator> myProgress = ContainerUtil.newConcurrentMap();
public IdeaDecompiler() {
myOptions.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "0");
return ClsFileImpl.decompile(file);
}
+ ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
+ if (indicator != null) myProgress.put(file, indicator);
+
try {
Map<String, VirtualFile> files = ContainerUtil.newLinkedHashMap();
files.put(file.getPath(), file);
throw new CannotDecompileException(e);
}
}
+ finally {
+ myProgress.remove(file);
+ }
+ }
+
+ @TestOnly
+ @Nullable
+ public ProgressIndicator getProgress(@NotNull VirtualFile file) {
+ return myProgress.get(file);
}
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() {
+ final 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(file);
+ 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) { }
+ }
}