mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
make isInNonCancelableSection() an instance method to open possibilities for optimisations; test added
This commit is contained in:
@@ -141,9 +141,9 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
|
||||
@Nullable JComponent parentComponent);
|
||||
|
||||
/**
|
||||
* Runs a specified <code>process</code> in a background thread and shows a progress dialog, which can be made non-modal by pressing
|
||||
* background button. Upon successful termination of the process a <code>successRunnable</code> will be called in Swing UI thread and
|
||||
* <code>canceledRunnable</code> will be called if terminated on behalf of the user by pressing either cancel button, while running in
|
||||
* Runs a specified {@code process} in a background thread and shows a progress dialog, which can be made non-modal by pressing
|
||||
* background button. Upon successful termination of the process a {@code successRunnable} will be called in Swing UI thread and
|
||||
* {@code canceledRunnable} will be called if terminated on behalf of the user by pressing either cancel button, while running in
|
||||
* a modal state or stop button if running in background.
|
||||
*
|
||||
* @param project the project in the context of which the operation is executed.
|
||||
@@ -159,9 +159,9 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
|
||||
@Nullable Runnable successRunnable,
|
||||
@Nullable Runnable canceledRunnable);
|
||||
/**
|
||||
* Runs a specified <code>process</code> in a background thread and shows a progress dialog, which can be made non-modal by pressing
|
||||
* background button. Upon successful termination of the process a <code>successRunnable</code> will be called in Swing UI thread and
|
||||
* <code>canceledRunnable</code> will be called if terminated on behalf of the user by pressing either cancel button, while running in
|
||||
* Runs a specified {@code process} in a background thread and shows a progress dialog, which can be made non-modal by pressing
|
||||
* background button. Upon successful termination of the process a {@code successRunnable} will be called in Swing UI thread and
|
||||
* {@code canceledRunnable} will be called if terminated on behalf of the user by pressing either cancel button, while running in
|
||||
* a modal state or stop button if running in background.
|
||||
*
|
||||
* @param project the project in the context of which the operation is executed.
|
||||
@@ -180,7 +180,7 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
|
||||
@NotNull PerformInBackgroundOption option);
|
||||
|
||||
/**
|
||||
* Runs a specified <code>task</code> in either background/foreground thread and shows a progress dialog.
|
||||
* Runs a specified {@code task} in either background/foreground thread and shows a progress dialog.
|
||||
*
|
||||
* @param task task to run (either {@link Task.Modal} or {@link Task.Backgroundable}).
|
||||
*/
|
||||
@@ -226,7 +226,7 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
|
||||
* This method attempts to run provided action synchronously in a read action, so that, if possible, it wouldn't impact any pending,
|
||||
* executing or future write actions (for this to work effectively the action should invoke {@link ProgressManager#checkCanceled()} or
|
||||
* {@link ProgressIndicator#checkCanceled()} often enough).
|
||||
* It returns <code>true</code> if action was executed successfully. It returns <code>false</code> if the action was not
|
||||
* It returns {@code true} if action was executed successfully. It returns {@code false} if the action was not
|
||||
* executed successfully, i.e. if:
|
||||
* <ul>
|
||||
* <li>write action was in progress when the method was called</li>
|
||||
@@ -240,17 +240,5 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
|
||||
*/
|
||||
public abstract boolean runInReadActionWithWriteActionPriority(@NotNull final Runnable action);
|
||||
|
||||
public static boolean isInNonCancelableSection() {
|
||||
ProgressIndicator indicator = getGlobalProgressIndicator();
|
||||
while (indicator != null) {
|
||||
if (indicator instanceof NonCancelableSection) return true;
|
||||
if (indicator instanceof WrappedProgressIndicator) {
|
||||
indicator = ((WrappedProgressIndicator)indicator).getOriginalProgressIndicator();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public abstract boolean isInNonCancelableSection();
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.ex.ApplicationEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
@@ -50,6 +51,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.impl.CoreProgressManager");
|
||||
|
||||
static final int CHECK_CANCELED_DELAY_MILLIS = 10;
|
||||
final AtomicInteger myCurrentUnsafeProgressCount = new AtomicInteger(0);
|
||||
private final AtomicInteger myCurrentModalProgressCount = new AtomicInteger(0);
|
||||
@@ -76,6 +79,11 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
// multiset here (instead of a set) is for simplifying add/remove indicators on process-with-progress start/end with possibly identical indicators.
|
||||
private static final Collection<ProgressIndicator> nonStandardIndicators = ConcurrentHashMultiset.create();
|
||||
|
||||
/** true if running in non-cancelable section started with
|
||||
* {@link #startNonCancelableSection()} or {@link #executeNonCancelableSection(Runnable)} in this thread
|
||||
*/
|
||||
private static final ThreadLocal<Boolean> isInNonCancelableSection = new ThreadLocal<Boolean>(); // do not supply initial value to conserve memory
|
||||
|
||||
public CoreProgressManager() {
|
||||
HeavyProcessLatch.INSTANCE.addUIActivityListener(new HeavyProcessLatch.HeavyProcessListener() {
|
||||
@Override
|
||||
@@ -206,7 +214,18 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
|
||||
@Override
|
||||
public void executeNonCancelableSection(@NotNull Runnable runnable) {
|
||||
executeProcessUnderProgress(runnable, NonCancelableIndicator.INSTANCE);
|
||||
if (isInNonCancelableSection()) {
|
||||
runnable.run();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
isInNonCancelableSection.set(Boolean.TRUE);
|
||||
executeProcessUnderProgress(runnable, NonCancelableIndicator.INSTANCE);
|
||||
}
|
||||
finally {
|
||||
isInNonCancelableSection.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -656,19 +675,28 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
@NotNull
|
||||
@Override
|
||||
public final NonCancelableSection startNonCancelableSection() {
|
||||
LOG.warn("Use executeNonCancelableSection() instead");
|
||||
if (isInNonCancelableSection()) return NonCancelableSection.EMPTY;
|
||||
final ProgressIndicator myOld = getProgressIndicator();
|
||||
|
||||
final Thread currentThread = Thread.currentThread();
|
||||
NonCancelableIndicator nonCancelor = new NonCancelableIndicator() {
|
||||
final NonCancelableIndicator nonCancelor = new NonCancelableIndicator() {
|
||||
@Override
|
||||
public void done() {
|
||||
setCurrentIndicator(currentThread, myOld);
|
||||
isInNonCancelableSection.remove();
|
||||
}
|
||||
};
|
||||
isInNonCancelableSection.set(Boolean.TRUE);
|
||||
setCurrentIndicator(currentThread, nonCancelor);
|
||||
return nonCancelor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInNonCancelableSection() {
|
||||
return isInNonCancelableSection.get() != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ModalityState getCurrentThreadProgressModality() {
|
||||
ProgressIndicator indicator = threadTopLevelIndicators.get(Thread.currentThread().getId());
|
||||
@@ -710,15 +738,16 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
return myTask.toString();
|
||||
}
|
||||
}
|
||||
protected static class TaskRunnable extends TaskContainer {
|
||||
|
||||
static class TaskRunnable extends TaskContainer {
|
||||
private final ProgressIndicator myIndicator;
|
||||
private final Runnable myContinuation;
|
||||
|
||||
public TaskRunnable(@NotNull Task task, @NotNull ProgressIndicator indicator) {
|
||||
TaskRunnable(@NotNull Task task, @NotNull ProgressIndicator indicator) {
|
||||
this(task, indicator, null);
|
||||
}
|
||||
|
||||
public TaskRunnable(@NotNull Task task, @NotNull ProgressIndicator indicator, @Nullable Runnable continuation) {
|
||||
TaskRunnable(@NotNull Task task, @NotNull ProgressIndicator indicator, @Nullable Runnable continuation) {
|
||||
super(task);
|
||||
myIndicator = indicator;
|
||||
myContinuation = continuation;
|
||||
|
||||
+1
-1
@@ -386,7 +386,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
|
||||
}
|
||||
|
||||
private static boolean canCancelProjectLoading() {
|
||||
return !ProgressManager.isInNonCancelableSection();
|
||||
return !ProgressManager.getInstance().isInNonCancelableSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+26
@@ -635,4 +635,30 @@ public class ProgressIndicatorTest extends LightPlatformTestCase {
|
||||
ApplicationManager.getApplication().invokeLater(semaphore::up);
|
||||
assertTrue("invokeAndWait would deadlock", semaphore.waitFor(1000));
|
||||
}
|
||||
|
||||
public void testNonCancelableSectionDetectedCorrectly() {
|
||||
ProgressManager progressManager = ProgressManager.getInstance();
|
||||
assertFalse(progressManager.isInNonCancelableSection());
|
||||
progressManager.run(new Task.Modal(getProject(), "", false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
assertFalse(indicator instanceof NonCancelableIndicator);
|
||||
assertFalse(progressManager.isInNonCancelableSection());
|
||||
progressManager.executeNonCancelableSection(() -> {
|
||||
assertTrue(progressManager.getProgressIndicator() instanceof NonCancelableIndicator);
|
||||
assertTrue(progressManager.isInNonCancelableSection());
|
||||
|
||||
progressManager.executeProcessUnderProgress(() -> {
|
||||
assertFalse(progressManager.getProgressIndicator() instanceof NonCancelableIndicator);
|
||||
assertTrue(progressManager.isInNonCancelableSection());
|
||||
}, new DaemonProgressIndicator());
|
||||
|
||||
assertTrue(progressManager.isInNonCancelableSection());
|
||||
});
|
||||
|
||||
assertFalse(progressManager.isInNonCancelableSection());
|
||||
}
|
||||
});
|
||||
assertFalse(progressManager.isInNonCancelableSection());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user