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.data.osm.Changeset; 017import org.openstreetmap.josm.data.osm.ChangesetCache; 018import org.openstreetmap.josm.data.osm.UserInfo; 019import org.openstreetmap.josm.gui.ExceptionDialogUtil; 020import org.openstreetmap.josm.gui.MainApplication; 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.ChangesetUpdater; 026import org.openstreetmap.josm.io.NetworkManager; 027import org.openstreetmap.josm.io.OnlineResource; 028import org.openstreetmap.josm.io.OsmServerChangesetReader; 029import org.openstreetmap.josm.io.OsmServerUserInfoReader; 030import org.openstreetmap.josm.io.OsmTransferException; 031import org.openstreetmap.josm.tools.Shortcut; 032import org.xml.sax.SAXException; 033 034/** 035 * User action to close open changesets. 036 * 037 * The list of open changesets will be downloaded from the server and presented 038 * to the user. 039 */ 040public class CloseChangesetAction extends JosmAction { 041 042 /** 043 * Constructs a new {@code CloseChangesetAction}. 044 */ 045 public CloseChangesetAction() { 046 super(tr("Close open changesets..."), 047 "closechangeset", 048 tr("Close open changesets"), 049 Shortcut.registerShortcut("system:closechangeset", 050 tr("File: {0}", tr("Close open changesets")), 051 KeyEvent.VK_Q, Shortcut.ALT_CTRL), 052 true 053 ); 054 setHelpId(ht("/Action/CloseChangeset")); 055 setEnabled(!NetworkManager.isOffline(OnlineResource.OSM_API)); 056 057 } 058 059 @Override 060 public void actionPerformed(ActionEvent e) { 061 MainApplication.worker.submit(new DownloadOpenChangesetsTask()); 062 } 063 064 protected void onPostDownloadOpenChangesets() { 065 ChangesetUpdater.check(); 066 List<Changeset> openChangesets = ChangesetCache.getInstance().getOpenChangesetsForCurrentUser(); 067 if (openChangesets.isEmpty()) { 068 JOptionPane.showMessageDialog( 069 MainApplication.getMainFrame(), 070 tr("There are no open changesets"), 071 tr("No open changesets"), 072 JOptionPane.INFORMATION_MESSAGE 073 ); 074 return; 075 } 076 077 CloseChangesetDialog dialog = new CloseChangesetDialog(); 078 dialog.setChangesets(openChangesets); 079 dialog.setVisible(true); 080 if (dialog.isCanceled()) 081 return; 082 083 Collection<Changeset> changesetsToClose = dialog.getSelectedChangesets(); 084 CloseChangesetTask closeChangesetTask = new CloseChangesetTask(changesetsToClose); 085 MainApplication.worker.submit(closeChangesetTask); 086 } 087 088 private final class DownloadOpenChangesetsTask extends PleaseWaitRunnable { 089 090 private boolean canceled; 091 private OsmServerChangesetReader reader; 092 private List<Changeset> changesets; 093 private Exception lastException; 094 095 private DownloadOpenChangesetsTask() { 096 super(tr("Downloading open changesets ..."), false /* don't ignore exceptions */); 097 } 098 099 @Override 100 protected void cancel() { 101 this.canceled = true; 102 if (reader != null) { 103 reader.cancel(); 104 } 105 } 106 107 @Override 108 protected void finish() { 109 SwingUtilities.invokeLater(() -> { 110 if (lastException != null) { 111 ExceptionDialogUtil.explainException(lastException); 112 } 113 ChangesetCache.getInstance().update(changesets); 114 if (!canceled && lastException == null) { 115 onPostDownloadOpenChangesets(); 116 } 117 }); 118 } 119 120 /** 121 * Fetch the user info from the server. This is necessary if we don't know the users id yet 122 * 123 * @return the user info 124 * @throws OsmTransferException in case of any communication exception 125 */ 126 private UserInfo fetchUserInfo() throws OsmTransferException { 127 return new OsmServerUserInfoReader().fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false)); 128 } 129 130 @Override 131 protected void realRun() throws SAXException, IOException, OsmTransferException { 132 try { 133 UserInfo userInfo = fetchUserInfo(); 134 if (canceled) 135 return; 136 reader = new OsmServerChangesetReader(); 137 ChangesetQuery query = new ChangesetQuery().forUser(userInfo.getId()).beingOpen(true); 138 changesets = reader.queryChangesets( 139 query, 140 getProgressMonitor().createSubTaskMonitor(1, false /* not internal */) 141 ); 142 } catch (OsmTransferException | IllegalArgumentException e) { 143 if (canceled) 144 return; 145 lastException = e; 146 } 147 } 148 149 /** 150 * Determines if the download task has been canceled. 151 * @return {@code true} if the download task has been canceled 152 */ 153 public boolean isCanceled() { 154 return canceled; 155 } 156 157 /** 158 * Returns the last exception that occurred. 159 * @return the last exception that occurred, or {@code null} 160 */ 161 public Exception getLastException() { 162 return lastException; 163 } 164 } 165}