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.ArrayList;
008import java.util.Collection;
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.Main;
020import org.openstreetmap.josm.gui.ExceptionDialogUtil;
021import org.openstreetmap.josm.gui.Notification;
022import org.openstreetmap.josm.gui.util.GuiHelper;
023import org.openstreetmap.josm.tools.ExceptionUtil;
024import org.openstreetmap.josm.tools.Logging;
025import org.openstreetmap.josm.tools.Utils;
026
027/**
028 * The post-download handler notifies user of potential errors that occurred.
029 * @since 2322
030 */
031public class PostDownloadHandler implements Runnable {
032    private final DownloadTask task;
033    private final Future<?> future;
034    private Consumer<Collection<Object>> errorReporter;
035
036    /**
037     * Creates a new {@link PostDownloadHandler}
038     * @param task the asynchronous download task
039     * @param future the future on which the completion of the download task can be synchronized
040     */
041    public PostDownloadHandler(DownloadTask task, Future<?> future) {
042        this.task = task;
043        this.future = future;
044    }
045
046    /**
047     * Creates a new {@link PostDownloadHandler} using a custom error reporter
048     * @param task the asynchronous download task
049     * @param future the future on which the completion of the download task can be synchronized
050     * @param errorReporter a callback to inform about the number errors happened during the download
051     *                      task
052     */
053    public PostDownloadHandler(DownloadTask task, Future<?> future, Consumer<Collection<Object>> errorReporter) {
054        this(task, future);
055        this.errorReporter = errorReporter;
056    }
057
058    @Override
059    public void run() {
060        // wait for downloads task to finish (by waiting for the future to return a value)
061        //
062        try {
063            future.get();
064        } catch (InterruptedException | ExecutionException | CancellationException e) {
065            Logging.error(e);
066            return;
067        }
068
069        // make sure errors are reported only once
070        //
071        Set<Object> errors = new LinkedHashSet<>(task.getErrorObjects());
072
073        if (this.errorReporter != null) {
074            GuiHelper.runInEDT(() -> errorReporter.accept(errors));
075        }
076
077        if (errors.isEmpty()) {
078            return;
079        }
080
081        // just one error object?
082        //
083        if (errors.size() == 1) {
084            final Object error = errors.iterator().next();
085            if (!GraphicsEnvironment.isHeadless()) {
086                SwingUtilities.invokeLater(() -> {
087                    if (error instanceof Exception) {
088                        ExceptionDialogUtil.explainException((Exception) error);
089                    } else if (tr("No data found in this area.").equals(error)) {
090                        new Notification(error.toString()).setIcon(JOptionPane.WARNING_MESSAGE).show();
091                    } else {
092                        JOptionPane.showMessageDialog(
093                                Main.parent,
094                                error.toString(),
095                                tr("Error during download"),
096                                JOptionPane.ERROR_MESSAGE);
097                    }
098                });
099            }
100            return;
101        }
102
103        // multiple error object? prepare a HTML list
104        //
105        if (!errors.isEmpty()) {
106            final Collection<String> items = new ArrayList<>();
107            for (Object error : errors) {
108                if (error instanceof String) {
109                    items.add((String) error);
110                } else if (error instanceof Exception) {
111                    items.add(ExceptionUtil.explainException((Exception) error));
112                }
113            }
114
115            if (!GraphicsEnvironment.isHeadless()) {
116                SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(
117                        Main.parent,
118                        "<html>"+Utils.joinAsHtmlUnorderedList(items)+"</html>",
119                        tr("Errors during download"),
120                        JOptionPane.ERROR_MESSAGE));
121            }
122        }
123    }
124}