/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.openapi.progress.util; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * A computation that needs to be run in background and inside a read action, and canceled whenever a write action is about to occur. * * @see ProgressIndicatorUtils#scheduleWithWriteActionPriority(ReadTask) * */ public abstract class ReadTask { /** * Performs the computation. * Is invoked inside a read action and under a progress indicator that's canceled when a write action is about to occur. * For tasks that have some Swing thread activity afterwards (e.g. applying changes, showing dialogs etc), * use {@link #performInReadAction(ProgressIndicator)} instead */ public void computeInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { throw new UnsupportedOperationException(); } /** * Performs the computation. * Is invoked inside a read action and under a progress indicator that's canceled when a write action is about to occur. * @return an action that should be performed later on Swing thread if no write actions have happened before that */ @Nullable public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { computeInReadAction(indicator); return null; } /** * Is invoked on Swing thread whenever the computation is canceled by a write action. * A likely implementation is to restart the computation, maybe based on the new state of the system. */ public abstract void onCanceled(@NotNull ProgressIndicator indicator); /** * Is invoked on a background thread. The responsibility of this method is to start a read action and * call {@link #computeInReadAction(ProgressIndicator)}. Overriders might also do something else. * For example, use {@link com.intellij.openapi.project.DumbService#runReadActionInSmartMode(Runnable)}. * @param indicator the progress indicator of the background thread */ public Continuation runBackgroundProcess(@NotNull final ProgressIndicator indicator) throws ProcessCanceledException { return ReadAction.compute(() -> performInReadAction(indicator)); } /** * An object representing the action that should be done on Swing thread after the background computation is finished. * It's invoked only if tasks' progress indicator hasn't been canceled since the task has ended. */ public static final class Continuation { private final Runnable myAction; private final ModalityState myModalityState; /** * @param action code to be executed in Swing thread in default modality state * @see ModalityState#defaultModalityState() */ public Continuation(@NotNull Runnable action) { this(action, ModalityState.defaultModalityState()); } /** * @param action code to be executed in Swing thread in default modality state * @param modalityState modality state when the action is to be executed */ public Continuation(@NotNull Runnable action, @NotNull ModalityState modalityState) { myAction = action; myModalityState = modalityState; } /** * @return modality state when {@link #getAction()} is to be executed */ @NotNull public ModalityState getModalityState() { return myModalityState; } /** * @return runnable to be executed in Swing thread in default modality state */ @NotNull public Runnable getAction() { return myAction; } } }