do not fire "AAA write action started, everything is lost" listener during continuation execution to fix IDEA-169288 Resource Bundle Editor: Cannot edit text

This commit is contained in:
Alexey Kudravtsev
2017-03-20 15:13:22 +03:00
parent 4e2d25d1b9
commit 8555019c44
2 changed files with 32 additions and 6 deletions
@@ -82,7 +82,7 @@ public class ProgressIndicatorUtils {
}
/**
* Same as {@link #runInReadActionWithWriteActionPriority(Runnable)}, optionally allowing to pass a {@link ProgressIndicatorUtils}
* Same as {@link #runInReadActionWithWriteActionPriority(Runnable)}, optionally allowing to pass a {@link ProgressIndicator}
* instance, which can be used to cancel action externally.
*/
public static boolean runInReadActionWithWriteActionPriority(@NotNull final Runnable action,
@@ -161,7 +161,6 @@ public class ProgressIndicatorUtils {
public static CompletableFuture<?> scheduleWithWriteActionPriority(@NotNull final ProgressIndicator progressIndicator,
@NotNull final Executor executor,
@NotNull final ReadTask readTask) {
final Application application = ApplicationManager.getApplication();
// invoke later even if on EDT
// to avoid tasks eagerly restarting immediately, allocating many pooled threads
// which get cancelled too soon when a next write action arrives in the same EDT batch
@@ -171,8 +170,8 @@ public class ProgressIndicatorUtils {
// to tolerate any immediate modality changes (e.g. https://youtrack.jetbrains.com/issue/IDEA-135180)
CompletableFuture<?> future = new CompletableFuture<>();
//noinspection SSBasedInspection
EdtInvocationManager.getInstance().invokeLater(() -> {
final Application application = ApplicationManager.getApplication();
if (application.isDisposed() || progressIndicator.isCanceled()) {
future.complete(null);
return;
@@ -207,6 +206,7 @@ public class ProgressIndicatorUtils {
application.invokeLater(new Runnable() {
@Override
public void run() {
application.removeApplicationListener(listener); // remove listener early to prevent firing it during continuation execution
try {
if (!progressIndicator.isCanceled()) {
continuation.getAction().run();
@@ -232,7 +232,6 @@ public class ProgressIndicatorUtils {
});
}
catch (RuntimeException | Error e) {
application.removeApplicationListener(listener);
future.completeExceptionally(e);
throw e;
}
@@ -21,6 +21,7 @@ import com.intellij.concurrency.SensitiveProgressWrapper;
import com.intellij.ide.util.DelegatingProgressIndicator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.progress.*;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
@@ -43,14 +44,15 @@ import com.intellij.util.containers.Stack;
import com.intellij.util.ui.UIUtil;
import gnu.trove.TLongArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author yole
@@ -148,7 +150,6 @@ public class ProgressIndicatorTest extends LightPlatformTestCase {
final AtomicBoolean afterContinuation = new AtomicBoolean();
final ProgressIndicatorBase indicator = new ProgressIndicatorBase();
ProgressIndicatorUtils.scheduleWithWriteActionPriority(indicator, new ReadTask() {
@Nullable
@Override
public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
return new Continuation(() -> afterContinuation.set(true));
@@ -660,4 +661,30 @@ public class ProgressIndicatorTest extends LightPlatformTestCase {
});
assertFalse(progressManager.isInNonCancelableSection());
}
public void testProgressIndicatorUtilsScheduleWithWriteActionPriorityMustRemoveListenerBeforeContinuationStartsExecutingInEDT() throws Throwable {
final AtomicBoolean canceled = new AtomicBoolean();
final ProgressIndicatorBase indicator = new ProgressIndicatorBase();
AtomicReference<CompletableFuture<?>> future = new AtomicReference<>();
future.set(ProgressIndicatorUtils.scheduleWithWriteActionPriority(indicator, new ReadTask() {
@Override
public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
return new Continuation(() -> {
assertFalse(future.get().isDone());
WriteAction.run(() -> {
}); // when I start write action from the continuation, the read task must not cancel
});
}
@Override
public void onCanceled(@NotNull ProgressIndicator indicator) {
canceled.set(true);
fail();
}
}));
while (!future.get().isDone()) {
UIUtil.dispatchAllInvocationEvents();
}
assertFalse(canceled.get());
}
}