001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.GraphicsEnvironment; 008import java.io.IOException; 009import java.util.Collections; 010import java.util.List; 011 012import javax.swing.JOptionPane; 013import javax.swing.SwingUtilities; 014 015import org.openstreetmap.josm.Main; 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.JosmUserIdentityManager; 021import org.openstreetmap.josm.gui.PleaseWaitRunnable; 022import org.openstreetmap.josm.gui.util.GuiHelper; 023import org.openstreetmap.josm.io.ChangesetQuery; 024import org.openstreetmap.josm.io.OsmServerChangesetReader; 025import org.openstreetmap.josm.io.OsmServerUserInfoReader; 026import org.openstreetmap.josm.io.OsmTransferException; 027import org.xml.sax.SAXException; 028 029/** 030 * This is a task for downloading the open changesets of the current user 031 * from the OSM server. 032 */ 033public class DownloadOpenChangesetsTask extends PleaseWaitRunnable { 034 035 private boolean canceled; 036 private OsmServerChangesetReader reader; 037 private List<Changeset> changesets; 038 private Exception lastException; 039 private final Component parent; 040 041 /** 042 * Constructs the task 043 * @param parent is a component to show error messages 044 */ 045 public DownloadOpenChangesetsTask(Component parent) { 046 super(parent, tr("Downloading open changesets ..."), false /* don't ignore exceptions */); 047 this.parent = parent; 048 } 049 050 @Override 051 protected void cancel() { 052 this.canceled = true; 053 synchronized (this) { 054 if (reader != null) { 055 reader.cancel(); 056 } 057 } 058 } 059 060 @Override 061 protected void finish() { 062 if (JosmUserIdentityManager.getInstance().isAnonymous()) { 063 String msg = tr("Could not retrieve the list of your open changesets because<br>" 064 + "JOSM does not know your identity.<br>" 065 + "You have either chosen to work anonymously or you are not entitled<br>" 066 + "to know the identity of the user on whose behalf you are working."); 067 Main.warn(msg); 068 if (!GraphicsEnvironment.isHeadless()) { 069 JOptionPane.showMessageDialog(GuiHelper.getFrameForComponent(parent), 070 "<html>" + msg + "</html>", tr("Missing user identity"), JOptionPane.ERROR_MESSAGE); 071 } 072 return; 073 } 074 if (canceled) return; 075 if (lastException != null) { 076 ExceptionDialogUtil.explainException(lastException); 077 return; 078 } 079 if (changesets.isEmpty()) { 080 JOptionPane.showMessageDialog( 081 Main.parent, 082 tr("There are no open changesets"), 083 tr("No open changesets"), 084 JOptionPane.INFORMATION_MESSAGE 085 ); 086 return; 087 } 088 SwingUtilities.invokeLater(() -> ChangesetCache.getInstance().update(changesets)); 089 } 090 091 /** 092 * Refreshes the user info from the server. This is necessary if we don't know the users id yet. 093 */ 094 protected void refreshUserIdentity() { 095 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance(); 096 try { 097 OsmServerUserInfoReader infoReader = new OsmServerUserInfoReader(); 098 UserInfo info = infoReader.fetchUserInfo(getProgressMonitor().createSubTaskMonitor(1, false)); 099 im.setFullyIdentified(info.getDisplayName(), info); 100 } catch (OsmTransferException e) { 101 // retrieving the user info can fail if the current user is not authorised to 102 // retrieve it, i.e. if he is working with an OAuth Access Token which doesn't 103 // have the respective privileges or if he didn't or he can't authenticate with 104 // a username/password-pair. 105 // 106 // Downgrade your knowlege about its identity if we've assumed that he was fully 107 // identified. Otherwise, if he is anonymous or partially identified, keep our level 108 // of knowlege. 109 // 110 if (im.isFullyIdentified()) { 111 im.setPartiallyIdentified(im.getUserName()); 112 } 113 Main.warn(e, tr("Failed to retrieve user infos for the current JOSM user. Exception was: {0}", e.toString())); 114 } 115 } 116 117 @Override 118 protected void realRun() throws SAXException, IOException, OsmTransferException { 119 try { 120 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance(); 121 if (im.isAnonymous()) { 122 refreshUserIdentity(); 123 } else if (im.isFullyIdentified()) { 124 // do nothing 125 } else if (im.isPartiallyIdentified()) { 126 refreshUserIdentity(); 127 } 128 if (canceled) return; 129 synchronized (this) { 130 reader = new OsmServerChangesetReader(); 131 } 132 ChangesetQuery query = new ChangesetQuery().beingOpen(true); 133 if (im.isAnonymous()) 134 // we still don't know anything about the current user. Can't retrieve 135 // its changesets 136 return; 137 else if (im.isFullyIdentified()) { 138 query = query.forUser(im.getUserId()); 139 } else { 140 // we only know the users name, not its id. Nevermind, try to read 141 // its open changesets anyway. 142 // 143 query = query.forUser(im.getUserName()); 144 } 145 changesets = reader.queryChangesets( 146 query, 147 getProgressMonitor().createSubTaskMonitor(1, false /* not internal */) 148 ); 149 } catch (OsmTransferException e) { 150 if (canceled) 151 return; 152 lastException = e; 153 } 154 } 155 156 /** 157 * Determines if this task has been cancelled. 158 * @return {@code true} if this task has been cancelled 159 */ 160 public boolean isCanceled() { 161 return canceled; 162 } 163 164 /** 165 * Returns the changesets. 166 * @return the changesets, or {@code null} 167 * @since 11110 168 */ 169 public final List<Changeset> getChangesets() { 170 return changesets != null ? Collections.unmodifiableList(changesets) : null; 171 } 172}