change modality deterministically in progress indicators

namely, on EDT, before ProgressWindow is started and whenever its dialog is closed

previously, the modality was entered at some later moment (invokeLater from start() method), and some runnables could sneak before that
This commit is contained in:
peter
2017-05-02 13:31:40 +02:00
parent 9064b5006e
commit 0da7b86817
5 changed files with 21 additions and 59 deletions
@@ -22,8 +22,6 @@ import org.jetbrains.annotations.NotNull;
public interface ProgressIndicatorEx extends ProgressIndicatorStacked {
void addStateDelegate(@NotNull ProgressIndicatorEx delegate);
boolean isModalityEntered();
void finish(@NotNull TaskInfo task);
boolean isFinished(@NotNull TaskInfo task);
@@ -15,13 +15,10 @@
*/
package com.intellij.openapi.progress.util;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.TaskInfo;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.ui.GuiUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.WeakList;
import org.jetbrains.annotations.NotNull;
@@ -31,7 +28,6 @@ import java.util.List;
public class AbstractProgressIndicatorExBase extends AbstractProgressIndicatorBase implements ProgressIndicatorEx {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.util.ProgressIndicatorBase");
private final boolean myReusable;
private volatile boolean myModalityEntered;
private volatile List<ProgressIndicatorEx> myStateDelegates;
private volatile WeakList<TaskInfo> myFinished;
private volatile boolean myWasStarted;
@@ -52,48 +48,13 @@ public class AbstractProgressIndicatorExBase extends AbstractProgressIndicatorBa
delegateRunningChange(ProgressIndicator::start);
}
myWasStarted = true;
enterModality();
}
protected final void enterModality() {
if (myModalityProgress == this) {
ModalityState modalityState = ModalityState.defaultModalityState();
if (!myModalityEntered &&
!ApplicationManager.getApplication().isDispatchThread() &&
!((TransactionGuardImpl)TransactionGuard.getInstance()).isWriteSafeModality(modalityState)) {
// exceptions here should be assigned to Peter
LOG.error("Non-modal progress should be started in a write-safe context: an action or modality-aware invokeLater. See also TransactionGuard documentation.");
}
GuiUtils.invokeLaterIfNeeded(this::doEnterModality, modalityState);
}
}
private void doEnterModality() {
if (!myModalityEntered) {
LaterInvocator.enterModal(this);
myModalityEntered = true;
}
}
@Override
public void stop() {
super.stop();
delegateRunningChange(ProgressIndicator::stop);
exitModality();
}
protected final void exitModality() {
if (myModalityProgress == this) {
GuiUtils.invokeLaterIfNeeded(this::doExitModality, ModalityState.defaultModalityState());
}
}
private void doExitModality() {
if (myModalityEntered) {
myModalityEntered = false;
LaterInvocator.leaveModal(this);
}
}
@Override
@@ -246,19 +207,6 @@ public class AbstractProgressIndicatorExBase extends AbstractProgressIndicatorBa
}
@Override
public boolean isModalityEntered() {
return myModalityEntered;
}
@Override
public synchronized void initStateFrom(@NotNull final ProgressIndicator indicator) {
super.initStateFrom(indicator);
if (indicator instanceof ProgressIndicatorEx) {
myModalityEntered = ((ProgressIndicatorEx)indicator).isModalityEntered();
}
}
@Override
public boolean wasStarted() {
return myWasStarted;
@@ -18,6 +18,8 @@ package com.intellij.openapi.progress.util;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.DialogWrapperDialog;
@@ -25,6 +27,7 @@ import com.intellij.openapi.ui.DialogWrapperPeer;
import com.intellij.openapi.ui.impl.DialogWrapperPeerImpl;
import com.intellij.openapi.ui.impl.FocusTrackbackProvider;
import com.intellij.openapi.ui.impl.GlassPaneDialogWrapperPeer;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
@@ -322,6 +325,8 @@ class ProgressDialog implements Disposable {
}
});
Disposer.register(myPopup.getDisposable(), () -> myProgressWindow.exitModality());
myPopup.show();
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.progress.util;
import com.intellij.ide.IdeEventQueue;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
@@ -62,6 +63,7 @@ public class ProgressWindow extends ProgressIndicatorBase implements BlockingPro
private String myProcessId = "<unknown>";
@Nullable private volatile Runnable myBackgroundHandler;
protected int myDelayInMillis = DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS;
private boolean myModalityEntered;
@FunctionalInterface
public interface Listener {
@@ -181,6 +183,20 @@ public class ProgressWindow extends ProgressIndicatorBase implements BlockingPro
timer.start();
}
final void enterModality() {
if (myModalityProgress == this && !myModalityEntered) {
LaterInvocator.enterModal(this);
myModalityEntered = true;
}
}
final void exitModality() {
if (myModalityProgress == this && myModalityEntered) {
myModalityEntered = false;
LaterInvocator.leaveModal(this);
}
}
@Override
public void startBlocking() {
startBlocking(EmptyRunnable.getInstance());
@@ -422,11 +422,6 @@ public class ProgressIndicatorTest extends LightPlatformTestCase {
throw new RuntimeException();
}
@Override
public boolean isModalityEntered() {
throw new RuntimeException();
}
@Override
public void finish(@NotNull TaskInfo task) {
}