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.Component;
007import java.io.IOException;
008import java.util.Collection;
009import java.util.Collections;
010import java.util.HashSet;
011import java.util.Objects;
012import java.util.Set;
013import java.util.stream.Collectors;
014
015import org.openstreetmap.josm.data.osm.Changeset;
016import org.openstreetmap.josm.data.osm.ChangesetCache;
017import org.openstreetmap.josm.gui.ExceptionDialogUtil;
018import org.openstreetmap.josm.gui.MainApplication;
019import org.openstreetmap.josm.io.OsmTransferException;
020import org.xml.sax.SAXException;
021
022/**
023 * This is an asynchronous task for downloading a collection of changests from the OSM server.
024 *
025 * The  task only downloads the changeset properties without the changeset content. It
026 * updates the global {@link ChangesetCache}.
027 * @since 2613
028 */
029public class ChangesetHeaderDownloadTask extends AbstractChangesetDownloadTask {
030
031    class DownloadTask extends RunnableDownloadTask {
032        /** the list of changeset ids to download */
033        private final Set<Integer> toDownload = new HashSet<>();
034        /** whether to include discussions or not */
035        private final boolean includeDiscussion;
036
037        DownloadTask(Component parent, Collection<Integer> ids, boolean includeDiscussion) {
038            super(parent, tr("Download changesets"));
039            this.includeDiscussion = includeDiscussion;
040            for (int id: ids != null ? ids : Collections.<Integer>emptyList()) {
041                if (id <= 0) {
042                    continue;
043                }
044                toDownload.add(id);
045            }
046        }
047
048        @Override
049        protected void realRun() throws SAXException, IOException, OsmTransferException {
050            try {
051                downloadedChangesets.addAll(reader.readChangesets(toDownload, includeDiscussion,
052                        getProgressMonitor().createSubTaskMonitor(0, false)));
053            } catch (OsmTransferException e) {
054                if (isCanceled())
055                    // ignore exception if canceled
056                    return;
057                // remember other exceptions
058                rememberLastException(e);
059            }
060        }
061
062        @Override
063        protected void finish() {
064            rememberDownloadedData(downloadedChangesets);
065            if (isCanceled())
066                return;
067            if (lastException != null) {
068                ExceptionDialogUtil.explainException(lastException);
069            }
070            updateChangesets();
071        }
072    }
073
074    /**
075     * Creates the download task for a collection of changeset ids. Uses a {@link org.openstreetmap.josm.gui.PleaseWaitDialog}
076     * whose parent is {@link MainApplication#getMainFrame}.
077     *
078     * Null ids or or ids &lt;= 0 in the id collection are ignored.
079     *
080     * @param ids the collection of ids. Empty collection assumed if null.
081     */
082    public ChangesetHeaderDownloadTask(Collection<Integer> ids) {
083        this(MainApplication.getMainFrame(), ids, false);
084    }
085
086    /**
087     * Creates the download task for a collection of changeset ids. Uses a {@link org.openstreetmap.josm.gui.PleaseWaitDialog}
088     * whose parent is the parent window of <code>dialogParent</code>.
089     *
090     * Null ids or or ids &lt;= 0 in the id collection are ignored.
091     *
092     * @param dialogParent the parent reference component for the {@link org.openstreetmap.josm.gui.PleaseWaitDialog}. Must not be null.
093     * @param ids the collection of ids. Empty collection assumed if null.
094     * @throws IllegalArgumentException if dialogParent is null
095     */
096    public ChangesetHeaderDownloadTask(Component dialogParent, Collection<Integer> ids) {
097        this(dialogParent, ids, false);
098    }
099
100    /**
101     * Creates the download task for a collection of changeset ids, with possibility to download changeset discussion.
102     * Uses a {@link org.openstreetmap.josm.gui.PleaseWaitDialog} whose parent is the parent window of <code>dialogParent</code>.
103     *
104     * Null ids or or ids &lt;= 0 in the id collection are ignored.
105     *
106     * @param dialogParent the parent reference component for the {@link org.openstreetmap.josm.gui.PleaseWaitDialog}. Must not be null.
107     * @param ids the collection of ids. Empty collection assumed if null.
108     * @param includeDiscussion determines if discussion comments must be downloaded or not
109     * @throws IllegalArgumentException if dialogParent is null
110     * @since 7704
111     */
112    public ChangesetHeaderDownloadTask(Component dialogParent, Collection<Integer> ids, boolean includeDiscussion) {
113        setDownloadTask(new DownloadTask(dialogParent, ids, includeDiscussion));
114    }
115
116    /**
117     * Builds a download task from for a collection of changesets.
118     *
119     * Ignores null values and changesets with {@link Changeset#isNew()} == true.
120     *
121     * @param changesets the collection of changesets. Assumes an empty collection if null.
122     * @return the download task
123     */
124    public static ChangesetHeaderDownloadTask buildTaskForChangesets(Collection<Changeset> changesets) {
125        return buildTaskForChangesets(MainApplication.getMainFrame(), changesets);
126    }
127
128    /**
129     * Builds a download task from for a collection of changesets.
130     *
131     * Ignores null values and changesets with {@link Changeset#isNew()} == true.
132     *
133     * @param parent the parent component relative to which the {@link org.openstreetmap.josm.gui.PleaseWaitDialog} is displayed.
134     * Must not be null.
135     * @param changesets the collection of changesets. Assumes an empty collection if null.
136     * @return the download task
137     * @throws NullPointerException if parent is null
138     */
139    public static ChangesetHeaderDownloadTask buildTaskForChangesets(Component parent, Collection<Changeset> changesets) {
140        return new ChangesetHeaderDownloadTask(Objects.requireNonNull(parent, "parent"),
141                changesets == null ? Collections.<Integer>emptySet() :
142                    changesets.stream().filter(cs -> cs != null && !cs.isNew()).map(Changeset::getId).collect(Collectors.toSet()));
143    }
144}