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