ProgressManager - always invoke Task callbacks

* add onError() / onFinished() callback
* always trigger one of onSuccess()/onCancel()/onError() and onFinished()
    before this change, callbacks hadling was not guaranteed if Task.run() throwed an exception.
    Task.Modal - runProcessWithProgressSynchronously() would call onCancel()
    Task.Backgroundable - runProcessWithProgressAsynchronously() would do nothing

    thus, previous implementation of onFinished() was not error-prone.

* this change might break implementations, that relied on old behaviour of Task.Modal.
This commit is contained in:
Aleksey Pivovarov
2016-05-24 17:47:40 +03:00
committed by Aleksey Pivovarov
parent 5f33787fb1
commit 5c4046a522
4 changed files with 83 additions and 43 deletions
@@ -61,19 +61,32 @@ public abstract class Task implements TaskInfo, Progressive {
/**
* This callback will be invoked on AWT dispatch thread.
*
* Callback executed when run() throws {@link ProcessCanceledException} or if its {@link ProgressIndicator} was canceled.
*/
public void onCancel() {
onFinished();
}
/**
* This callback will be invoked on AWT dispatch thread.
*/
public void onSuccess() {
onFinished();
}
protected void onFinished() {}
/**
* This callback will be invoked on AWT dispatch thread.
*
* Callback executed when run() throws an exception (except PCE).
*/
public void onError(@NotNull Exception error) {
LOG.error(error);
}
/**
* This callback will be invoked on AWT dispatch thread, after other specific handlers
*/
public void onFinished() {
}
public final Project getProject() {
return myProject;
@@ -344,30 +344,27 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
Runnable action = new TaskContainer(task) {
@Override
public void run() {
boolean canceled = false;
boolean processCanceled = false;
Exception exception = null;
try {
ProgressManager.getInstance().runProcess(process, progressIndicator);
}
catch (ProcessCanceledException e) {
canceled = true;
processCanceled = true;
}
catch (Exception e) {
exception = e;
}
if (canceled || progressIndicator.isCanceled()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
task.onCancel();
}
}, modalityState);
}
else {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
task.onSuccess();
}
}, modalityState);
}
final boolean finalCanceled = processCanceled || progressIndicator.isCanceled();
final Exception finalException = exception;
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
finishTask(task, finalCanceled, finalException);
}
}, modalityState);
}
};
@@ -375,22 +372,47 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
}
protected boolean runProcessWithProgressSynchronously(@NotNull final Task task, @Nullable final JComponent parentComponent) {
final boolean result = ((ApplicationEx)ApplicationManager.getApplication())
.runProcessWithProgressSynchronously(new TaskContainer(task) {
@Override
public void run() {
new TaskRunnable(task, ProgressManager.getInstance().getProgressIndicator()).run();
}
}, task.getTitle(), task.isCancellable(), task.getProject(), parentComponent, task.getCancelText());
if (result) {
task.onSuccess();
}
else {
task.onCancel();
}
final Ref<Exception> exceptionRef = new Ref<Exception>();
TaskContainer taskContainer = new TaskContainer(task) {
@Override
public void run() {
try {
new TaskRunnable(task, ProgressManager.getInstance().getProgressIndicator()).run();
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
exceptionRef.set(e);
}
}
};
ApplicationEx application = (ApplicationEx)ApplicationManager.getApplication();
boolean result = application.runProcessWithProgressSynchronously(taskContainer, task.getTitle(), task.isCancellable(),
task.getProject(), parentComponent, task.getCancelText());
finishTask(task, !result, exceptionRef.get());
return result;
}
protected static void finishTask(@NotNull Task task, boolean canceled, @Nullable Exception exception) {
try {
if (exception != null) {
task.onError(exception);
}
else if (canceled) {
task.onCancel();
}
else {
task.onSuccess();
}
}
finally {
task.onFinished();
}
}
@Override
public void runProcessWithProgressAsynchronously(@NotNull Task.Backgroundable task, @NotNull ProgressIndicator progressIndicator) {
runProcessWithProgressAsynchronously(task, progressIndicator, null);
@@ -136,13 +136,12 @@ public abstract class BackgroundUpdaterTask<T> extends Task.Backgroundable {
@Override
public void onSuccess() {
onFinished();
myPopup.setCaption(getCaption(getCurrentSize()));
paintBusy(false);
}
@Override
protected void onFinished() {
public void onFinished() {
myFinished = true;
}
@@ -120,21 +120,26 @@ public class ProgressManagerImpl extends CoreProgressManager implements Disposab
TaskContainer action = new TaskContainer(task) {
@Override
public void run() {
boolean canceled = false;
boolean processCanceled = false;
Exception exception = null;
final long start = System.currentTimeMillis();
try {
ProgressManager.getInstance().runProcess(process, progressIndicator);
}
catch (ProcessCanceledException e) {
canceled = true;
processCanceled = true;
}
catch (Exception e) {
exception = e;
}
final long end = System.currentTimeMillis();
final long time = end - start;
if (canceled || progressIndicator.isCanceled()) {
ApplicationManager.getApplication().invokeLater(() -> task.onCancel(), modalityState);
}
else {
final boolean finalCanceled = processCanceled || progressIndicator.isCanceled();
final Exception finalException = exception;
if (!finalCanceled) {
final Task.NotificationInfo notificationInfo = task.notifyFinished();
if (notificationInfo != null && time > 5000) { // snow notification if process took more than 5 secs
final Component window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
@@ -142,8 +147,9 @@ public class ProgressManagerImpl extends CoreProgressManager implements Disposab
systemNotify(notificationInfo);
}
}
ApplicationManager.getApplication().invokeLater(() -> task.onSuccess(), modalityState);
}
ApplicationManager.getApplication().invokeLater(() -> finishTask(task, finalCanceled, finalException), modalityState);
}
};