001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.event.ActionEvent;
008import java.awt.event.KeyEvent;
009import java.io.IOException;
010import java.util.Collection;
011import java.util.List;
012
013import javax.swing.JOptionPane;
014import javax.swing.SwingUtilities;
015
016import org.openstreetmap.josm.Main;
017import org.openstreetmap.josm.data.osm.Changeset;
018import org.openstreetmap.josm.data.osm.ChangesetCache;
019import org.openstreetmap.josm.data.osm.UserInfo;
020import org.openstreetmap.josm.gui.ExceptionDialogUtil;
021import org.openstreetmap.josm.gui.PleaseWaitRunnable;
022import org.openstreetmap.josm.gui.io.CloseChangesetDialog;
023import org.openstreetmap.josm.gui.io.CloseChangesetTask;
024import org.openstreetmap.josm.io.ChangesetQuery;
025import org.openstreetmap.josm.io.OnlineResource;
026import org.openstreetmap.josm.io.OsmServerChangesetReader;
027import org.openstreetmap.josm.io.OsmServerUserInfoReader;
028import org.openstreetmap.josm.io.OsmTransferException;
029import org.openstreetmap.josm.tools.Shortcut;
030import org.xml.sax.SAXException;
031
032public class CloseChangesetAction extends JosmAction {
033
034    /**
035     * Constructs a new {@code CloseChangesetAction}.
036     */
037    public CloseChangesetAction() {
038        super(tr("Close open changesets"),
039            "closechangeset",
040            tr("Closes open changesets"),
041            Shortcut.registerShortcut("system:closechangeset",
042                tr("File: {0}", tr("Closes open changesets")),
043                KeyEvent.VK_Q, Shortcut.ALT_CTRL),
044            true
045        );
046        putValue("help", ht("/Action/CloseChangeset"));
047        setEnabled(!Main.isOffline(OnlineResource.OSM_API));
048
049    }
050
051    @Override
052    public void actionPerformed(ActionEvent e) {
053        Main.worker.submit(new DownloadOpenChangesetsTask());
054    }
055
056    protected void onPostDownloadOpenChangesets() {
057        List<Changeset> openChangesets = ChangesetCache.getInstance().getOpenChangesetsForCurrentUser();
058        if (openChangesets.isEmpty()) {
059            JOptionPane.showMessageDialog(
060                    Main.parent,
061                    tr("There are no open changesets"),
062                    tr("No open changesets"),
063                    JOptionPane.INFORMATION_MESSAGE
064            );
065            return;
066        }
067
068        CloseChangesetDialog dialog = new CloseChangesetDialog();
069        dialog.setChangesets(openChangesets);
070        dialog.setVisible(true);
071        if (dialog.isCanceled())
072            return;
073
074        Collection<Changeset> changesetsToClose = dialog.getSelectedChangesets();
075        CloseChangesetTask closeChangesetTask = new CloseChangesetTask(changesetsToClose);
076        Main.worker.submit(closeChangesetTask);
077    }
078
079    private final class DownloadOpenChangesetsTask extends PleaseWaitRunnable {
080
081        private boolean canceled;
082        private OsmServerChangesetReader reader;
083        private List<Changeset> changesets;
084        private Exception lastException;
085
086        private DownloadOpenChangesetsTask() {
087            super(tr("Downloading open changesets ..."), false /* don't ignore exceptions */);
088        }
089
090        @Override
091        protected void cancel() {
092            this.canceled = true;
093            reader.cancel();
094        }
095
096        @Override
097        protected void finish() {
098            SwingUtilities.invokeLater(() -> {
099                            if (lastException != null) {
100                                ExceptionDialogUtil.explainException(lastException);
101                            }
102                            ChangesetCache.getInstance().update(changesets);
103                            if (!canceled && lastException == null) {
104                                onPostDownloadOpenChangesets();
105                            }
106                        });
107        }
108
109        /**
110         * Fetch the user info from the server. This is necessary if we don't know the users id yet
111         *
112         * @return the user info
113         * @throws OsmTransferException in case of any communication exception
114         */
115        private UserInfo fetchUserInfo() throws OsmTransferException {
116            return new OsmServerUserInfoReader().fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false));
117        }
118
119        @Override
120        protected void realRun() throws SAXException, IOException, OsmTransferException {
121            try {
122                UserInfo userInfo = fetchUserInfo();
123                if (canceled)
124                    return;
125                reader = new OsmServerChangesetReader();
126                ChangesetQuery query = new ChangesetQuery().forUser(userInfo.getId()).beingOpen(true);
127                changesets = reader.queryChangesets(
128                        query,
129                        getProgressMonitor().createSubTaskMonitor(1, false /* not internal */)
130                );
131            } catch (OsmTransferException | IllegalArgumentException e) {
132                if (canceled)
133                    return;
134                lastException = e;
135            }
136        }
137
138        public boolean isCanceled() {
139            return canceled;
140        }
141
142        public Exception getLastException() {
143            return lastException;
144        }
145    }
146}