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;
008
009import javax.swing.JOptionPane;
010
011import org.openstreetmap.josm.Main;
012import org.openstreetmap.josm.data.osm.UserInfo;
013import org.openstreetmap.josm.gui.JosmUserIdentityManager;
014import org.openstreetmap.josm.gui.util.GuiHelper;
015import org.openstreetmap.josm.io.ChangesetQuery;
016import org.openstreetmap.josm.io.OsmServerUserInfoReader;
017import org.openstreetmap.josm.io.OsmTransferCanceledException;
018import org.openstreetmap.josm.io.OsmTransferException;
019import org.openstreetmap.josm.tools.CheckParameterUtil;
020import org.openstreetmap.josm.tools.ExceptionUtil;
021import org.xml.sax.SAXException;
022
023/**
024 * Asynchronous task to send a changeset query to the OSM API.
025 * @since 2689
026 */
027public class ChangesetQueryTask extends AbstractChangesetDownloadTask {
028
029    class DownloadTask extends RunnableDownloadTask {
030        /** the changeset query */
031        private ChangesetQuery query;
032        /** the reader object used to read information about the current user from the API */
033        private final OsmServerUserInfoReader userInfoReader = new OsmServerUserInfoReader();
034
035        DownloadTask(Component parent, ChangesetQuery query) {
036            super(parent, tr("Querying and downloading changesets"));
037            this.query = query;
038        }
039
040        /**
041         * Tries to fully identify the current JOSM user
042         *
043         * @throws OsmTransferException if something went wrong
044         */
045        protected void fullyIdentifyCurrentUser() throws OsmTransferException {
046            getProgressMonitor().indeterminateSubTask(tr("Determine user id for current user..."));
047
048            UserInfo info = userInfoReader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false));
049            JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
050            im.setFullyIdentified(im.getUserName(), info);
051        }
052
053        @Override
054        protected void realRun() throws SAXException, IOException, OsmTransferException {
055            try {
056                JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
057                if (query.isRestrictedToPartiallyIdentifiedUser() && im.isCurrentUser(query.getUserName())) {
058                    // if we query changesets for the current user, make sure we query against
059                    // its user id, not its user name. If necessary, determine the user id first.
060                    //
061                    if (im.isPartiallyIdentified()) {
062                        fullyIdentifyCurrentUser();
063                    }
064                    query = query.forUser(JosmUserIdentityManager.getInstance().getUserId());
065                }
066                if (isCanceled())
067                    return;
068                getProgressMonitor().indeterminateSubTask(tr("Query and download changesets ..."));
069                downloadedChangesets.addAll(reader.queryChangesets(query, getProgressMonitor().createSubTaskMonitor(0, false)));
070            } catch (OsmTransferCanceledException e) {
071                // thrown if user cancel the authentication dialog
072                setCanceled(true);
073                Main.trace(e);
074            } catch (OsmTransferException e) {
075                if (isCanceled())
076                    return;
077                rememberLastException(e);
078            }
079        }
080
081        @Override
082        protected void finish() {
083            rememberDownloadedData(downloadedChangesets);
084            if (isCanceled())
085                return;
086            if (lastException != null) {
087                GuiHelper.runInEDTAndWait(new Runnable() {
088                    private final Component parent = progressMonitor != null ? progressMonitor.getWindowParent() : null;
089                    @Override
090                    public void run() {
091                        JOptionPane.showMessageDialog(
092                                parent != null ? parent : Main.parent,
093                                ExceptionUtil.explainException(lastException),
094                                tr("Errors during download"),
095                                JOptionPane.ERROR_MESSAGE);
096                    }
097                });
098                return;
099            }
100            updateChangesets();
101        }
102
103        @Override
104        protected void cancel() {
105            super.cancel();
106            synchronized (this) {
107                if (userInfoReader != null) {
108                    userInfoReader.cancel();
109                }
110            }
111        }
112    }
113
114    /**
115     * Creates the task.
116     *
117     * @param query the query to submit to the OSM server. Must not be null.
118     * @throws IllegalArgumentException if query is null.
119     */
120    public ChangesetQueryTask(ChangesetQuery query) {
121        this(Main.parent, query);
122    }
123
124    /**
125     * Creates the task.
126     *
127     * @param parent the parent component relative to which the {@link org.openstreetmap.josm.gui.PleaseWaitDialog} is displayed.
128     * Must not be null.
129     * @param query the query to submit to the OSM server. Must not be null.
130     * @throws IllegalArgumentException if query is null.
131     * @throws IllegalArgumentException if parent is null
132     */
133    public ChangesetQueryTask(Component parent, ChangesetQuery query) {
134        CheckParameterUtil.ensureParameterNotNull(query, "query");
135        setDownloadTask(new DownloadTask(parent, query));
136    }
137}