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    @Override
051    public void actionPerformed(ActionEvent e) {
052        Main.worker.submit(new DownloadOpenChangesetsTask());
053    }
054
055    protected void onPostDownloadOpenChangesets() {
056        List<Changeset> openChangesets = ChangesetCache.getInstance().getOpenChangesets();
057        if (openChangesets.isEmpty()) {
058            JOptionPane.showMessageDialog(
059                    Main.parent,
060                    tr("There are no open changesets"),
061                    tr("No open changesets"),
062                    JOptionPane.INFORMATION_MESSAGE
063            );
064            return;
065        }
066
067        CloseChangesetDialog dialog = new CloseChangesetDialog();
068        dialog.setChangesets(openChangesets);
069        dialog.setVisible(true);
070        if (dialog.isCanceled())
071            return;
072
073        Collection<Changeset> changesetsToClose = dialog.getSelectedChangesets();
074        CloseChangesetTask closeChangesetTask = new CloseChangesetTask(changesetsToClose);
075        Main.worker.submit(closeChangesetTask);
076    }
077
078    private class DownloadOpenChangesetsTask extends PleaseWaitRunnable {
079
080        private boolean canceled;
081        private OsmServerChangesetReader reader;
082        private List<Changeset> changesets;
083        private Exception lastException;
084        private UserInfo userInfo;
085
086        public 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                    new Runnable() {
100                        @Override
101                        public void run() {
102                            if (lastException != null) {
103                                ExceptionDialogUtil.explainException(lastException);
104                            }
105                            ChangesetCache.getInstance().update(changesets);
106                            if (!canceled && lastException == null) {
107                                onPostDownloadOpenChangesets();
108                            }
109                        }
110                    }
111            );
112        }
113
114        /**
115         * Fetch the user info from the server. This is necessary if we don't know
116         * the users id yet
117         *
118         * @return the user info
119         * @throws OsmTransferException thrown in case of any communication exception
120         */
121        protected UserInfo fetchUserInfo() throws OsmTransferException {
122            OsmServerUserInfoReader reader = new OsmServerUserInfoReader();
123            return reader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false));
124        }
125
126        @Override
127        protected void realRun() throws SAXException, IOException, OsmTransferException {
128            try {
129                userInfo = fetchUserInfo();
130                if (canceled)
131                    return;
132                reader = new OsmServerChangesetReader();
133                ChangesetQuery query = new ChangesetQuery().forUser(userInfo.getId()).beingOpen(true);
134                changesets = reader.queryChangesets(
135                        query,
136                        getProgressMonitor().createSubTaskMonitor(1, false /* not internal */)
137                );
138            } catch(Exception e) {
139                if (canceled)
140                    return;
141                lastException = e;
142            }
143        }
144
145        public boolean isCanceled() {
146            return canceled;
147        }
148
149        public Exception getLastException() {
150            return lastException;
151        }
152    }
153}