diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index bef59f254..b1f3a9bda 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -57,6 +57,7 @@ import org.jetbrains.annotations.Nullable; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CancellationException; import static org.jackhuang.hmcl.ui.FXUtils.runInFX; import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; @@ -166,9 +167,13 @@ public class DownloadPage extends BorderPane implements DecoratorPage { FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(file.getFile().getUrl()), dest.toFile()); task.setName(file.getName()); return task; - }).whenComplete(exception -> { + }).whenComplete(Schedulers.javafx(), exception -> { if (exception != null) { - Controllers.dialog(DownloadProviders.localizeErrorMessage(exception), i18n("install.failed.downloading"), MessageDialogPane.MessageType.ERROR); + if (exception instanceof CancellationException) { + Controllers.showToast(i18n("message.cancelled")); + } else { + Controllers.dialog(DownloadProviders.localizeErrorMessage(exception), i18n("install.failed.downloading"), MessageDialogPane.MessageType.ERROR); + } } else { Controllers.showToast(i18n("install.success")); } diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index f60830277..6dabbe710 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -420,6 +420,7 @@ logwindow.export_game_crash_logs=Export game crash info main_page=Home +message.cancelled=Operation was cancelled message.confirm=Confirm message.copied=Copied to clipboard message.doing=Please wait diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 08aebe143..ce2ad1f32 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -420,6 +420,7 @@ logwindow.export_game_crash_logs=導出遊戲崩潰訊息 main_page=首頁 +message.cancelled=操作被取消 message.confirm=提示 message.copied=已複製到剪貼板 message.doing=請耐心等待 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index e6ec9db69..506bc32f0 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -420,6 +420,7 @@ logwindow.export_game_crash_logs=导出游戏崩溃信息 main_page=主页 +message.cancelled=操作被取消 message.confirm=提示 message.copied=已复制到剪贴板 message.doing=请耐心等待 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java index 1e3e36d3f..99bdb53e4 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/AsyncTaskExecutor.java @@ -95,7 +95,6 @@ public final class AsyncTaskExecutor extends TaskExecutor { } cancelled.set(true); - future.cancel(true); } private CompletableFuture executeTasksExceptionally(Task parentTask, Collection> tasks) { @@ -229,13 +228,15 @@ public final class AsyncTaskExecutor extends TaskExecutor { .thenComposeAsync(dependentsException -> { boolean isDependentsSucceeded = dependentsException == null; - if (!isDependentsSucceeded && task.isRelyingOnDependents()) { - task.setException(dependentsException); - rethrow(dependentsException); - } - - if (isDependentsSucceeded) + if (isDependentsSucceeded) { task.setDependentsSucceeded(); + } else { + task.setException(dependentsException); + + if (task.isRelyingOnDependents()) { + rethrow(dependentsException); + } + } return CompletableFuture.runAsync(wrap(() -> { task.setState(Task.TaskState.RUNNING); @@ -263,10 +264,12 @@ public final class AsyncTaskExecutor extends TaskExecutor { .thenApplyAsync(dependenciesException -> { boolean isDependenciesSucceeded = dependenciesException == null; - if (!isDependenciesSucceeded && task.isRelyingOnDependencies()) { + if (!isDependenciesSucceeded) { Logging.LOG.severe("Subtasks failed for " + task.getName()); task.setException(dependenciesException); - rethrow(dependenciesException); + if (task.isRelyingOnDependencies()) { + rethrow(dependenciesException); + } } checkCancellation(); @@ -285,23 +288,20 @@ public final class AsyncTaskExecutor extends TaskExecutor { .exceptionally(throwable -> { Throwable resolved = resolveException(throwable); if (resolved instanceof Exception) { - Exception e = (Exception) resolved; - if (e instanceof InterruptedException || e instanceof CancellationException) { - task.setException(null); + Exception e = convertInterruptedException((Exception) resolved); + task.setException(e); + exception = e; + if (e instanceof CancellationException) { if (task.getSignificance().shouldLog()) { Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName()); } - task.onDone().fireEvent(new TaskEvent(this, task, true)); - taskListeners.forEach(it -> it.onFailed(task, e)); } else { - task.setException(e); - exception = e; if (task.getSignificance().shouldLog()) { Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e); } - task.onDone().fireEvent(new TaskEvent(this, task, true)); - taskListeners.forEach(it -> it.onFailed(task, e)); } + task.onDone().fireEvent(new TaskEvent(this, task, true)); + taskListeners.forEach(it -> it.onFailed(task, e)); task.setState(Task.TaskState.FAILED); } @@ -331,6 +331,14 @@ public final class AsyncTaskExecutor extends TaskExecutor { } } + private static Exception convertInterruptedException(Exception e) { + if (e instanceof InterruptedException) { + return new CancellationException(e.getMessage()); + } else { + return e; + } + } + private static Thread.UncaughtExceptionHandler uncaughtExceptionHandler = null; public static void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index e18b8ce59..212e70cb2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -665,14 +665,14 @@ public abstract class Task { @Override public void execute() throws Exception { if (isDependentsSucceeded() != (Task.this.getException() == null)) - throw new AssertionError("When dependents succeeded, Task.exception must be nonnull."); + throw new AssertionError("When whenComplete succeeded, Task.exception must be null."); action.execute(Task.this.getException()); if (!isDependentsSucceeded()) { setSignificance(TaskSignificance.MINOR); if (Task.this.getException() == null) - throw new CancellationException(); + throw new AssertionError("When failed, exception cannot be null"); else throw Task.this.getException(); }