001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions.downloadtasks; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.GraphicsEnvironment; 007import java.util.Collection; 008import java.util.HashSet; 009import java.util.LinkedHashSet; 010import java.util.Set; 011import java.util.concurrent.CancellationException; 012import java.util.concurrent.ExecutionException; 013import java.util.concurrent.Future; 014import java.util.function.Consumer; 015 016import javax.swing.JOptionPane; 017import javax.swing.SwingUtilities; 018 019import org.openstreetmap.josm.gui.ExceptionDialogUtil; 020import org.openstreetmap.josm.gui.MainApplication; 021import org.openstreetmap.josm.gui.Notification; 022import org.openstreetmap.josm.gui.util.GuiHelper; 023import org.openstreetmap.josm.tools.Logging; 024import org.openstreetmap.josm.tools.Utils; 025 026/** 027 * The post-download handler notifies user of potential errors that occurred. 028 * @since 2322 029 */ 030public class PostDownloadHandler implements Runnable { 031 private final DownloadTask task; 032 private final Future<?> future; 033 private Consumer<Collection<Object>> errorReporter; 034 035 private static final Set<String> NO_DATA_ERROR_MESSAGES = new HashSet<>(); 036 037 /** 038 * Creates a new {@link PostDownloadHandler} 039 * @param task the asynchronous download task 040 * @param future the future on which the completion of the download task can be synchronized 041 */ 042 public PostDownloadHandler(DownloadTask task, Future<?> future) { 043 this.task = task; 044 this.future = future; 045 } 046 047 /** 048 * Creates a new {@link PostDownloadHandler} using a custom error reporter 049 * @param task the asynchronous download task 050 * @param future the future on which the completion of the download task can be synchronized 051 * @param errorReporter a callback to inform about the number errors happened during the download 052 * task 053 */ 054 public PostDownloadHandler(DownloadTask task, Future<?> future, Consumer<Collection<Object>> errorReporter) { 055 this(task, future); 056 this.errorReporter = errorReporter; 057 } 058 059 /** 060 * Adds a new translated error message indicating that no data has been downloaded. 061 * @param message new translated error message indicating that no data has been downloaded. 062 * @return {@code true} if the message was not already known 063 * @since 15358 064 */ 065 public static boolean addNoDataErrorMessage(String message) { 066 return NO_DATA_ERROR_MESSAGES.add(message); 067 } 068 069 /** 070 * Determines if a translated error message indicates that no data has been downloaded. 071 * @param message translated error message to check 072 * @return {@code true} if the message indicates that no data has been downloaded 073 * @since 15358 074 */ 075 public static boolean isNoDataErrorMessage(Object message) { 076 return NO_DATA_ERROR_MESSAGES.contains(message); 077 } 078 079 @Override 080 public void run() { 081 // wait for downloads task to finish (by waiting for the future to return a value) 082 // 083 try { 084 future.get(); 085 } catch (InterruptedException | ExecutionException | CancellationException e) { 086 Logging.error(e); 087 return; 088 } 089 090 // make sure errors are reported only once 091 // 092 Set<Object> errors = new LinkedHashSet<>(task.getErrorObjects()); 093 094 if (this.errorReporter != null) { 095 GuiHelper.runInEDT(() -> errorReporter.accept(errors)); 096 } 097 098 if (errors.isEmpty()) { 099 return; 100 } 101 102 // just one error object? 103 // 104 if (errors.size() == 1) { 105 final Object error = errors.iterator().next(); 106 if (!GraphicsEnvironment.isHeadless()) { 107 SwingUtilities.invokeLater(() -> { 108 if (error instanceof Exception) { 109 ExceptionDialogUtil.explainException((Exception) error); 110 } else if (isNoDataErrorMessage(error)) { 111 new Notification(error.toString()).setIcon(JOptionPane.WARNING_MESSAGE).show(); 112 } else { 113 JOptionPane.showMessageDialog( 114 MainApplication.getMainFrame(), 115 error.toString(), 116 tr("Error during download"), 117 JOptionPane.ERROR_MESSAGE); 118 } 119 }); 120 } 121 return; 122 } 123 124 // multiple error object? prepare a HTML list 125 // 126 final Collection<String> items = task.getErrorMessages(); 127 if (!items.isEmpty() && !GraphicsEnvironment.isHeadless()) { 128 SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog( 129 MainApplication.getMainFrame(), 130 "<html>"+Utils.joinAsHtmlUnorderedList(items)+"</html>", 131 tr("Errors during download"), 132 JOptionPane.ERROR_MESSAGE)); 133 } 134 } 135}