001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions.upload; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.IOException; 007import java.util.HashMap; 008import java.util.Map; 009 010import javax.swing.JOptionPane; 011 012import org.openstreetmap.josm.Main; 013import org.openstreetmap.josm.data.notes.Note; 014import org.openstreetmap.josm.data.notes.NoteComment; 015import org.openstreetmap.josm.data.osm.NoteData; 016import org.openstreetmap.josm.gui.PleaseWaitRunnable; 017import org.openstreetmap.josm.gui.progress.ProgressMonitor; 018import org.openstreetmap.josm.io.OsmApi; 019import org.openstreetmap.josm.io.OsmTransferException; 020import org.xml.sax.SAXException; 021 022/** 023 * Class for uploading note changes to the server 024 */ 025public class UploadNotesTask { 026 027 private NoteData noteData; 028 029 /** 030 * Upload notes with modifications to the server 031 * @param noteData Note dataset with changes to upload 032 * @param progressMonitor progress monitor for user feedback 033 */ 034 public void uploadNotes(NoteData noteData, ProgressMonitor progressMonitor) { 035 this.noteData = noteData; 036 Main.worker.submit(new UploadTask(tr("Uploading modified notes"), progressMonitor)); 037 } 038 039 private class UploadTask extends PleaseWaitRunnable { 040 041 private boolean isCanceled; 042 private final Map<Note, Note> updatedNotes = new HashMap<>(); 043 private final Map<Note, Exception> failedNotes = new HashMap<>(); 044 045 /** 046 * Constructs a new {@code UploadTask}. 047 * @param title message for the user 048 * @param monitor progress monitor 049 */ 050 UploadTask(String title, ProgressMonitor monitor) { 051 super(title, monitor, false); 052 } 053 054 @Override 055 protected void cancel() { 056 if (Main.isDebugEnabled()) { 057 Main.debug("note upload canceled"); 058 } 059 isCanceled = true; 060 } 061 062 @Override 063 protected void realRun() throws SAXException, IOException, OsmTransferException { 064 ProgressMonitor monitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); 065 OsmApi api = OsmApi.getOsmApi(); 066 for (Note note : noteData.getNotes()) { 067 if (isCanceled) { 068 Main.info("Note upload interrupted by user"); 069 break; 070 } 071 for (NoteComment comment : note.getComments()) { 072 if (comment.isNew()) { 073 if (Main.isDebugEnabled()) { 074 Main.debug("found note change to upload"); 075 } 076 processNoteComment(monitor, api, note, comment); 077 } 078 } 079 } 080 } 081 082 private void processNoteComment(ProgressMonitor monitor, OsmApi api, Note note, NoteComment comment) { 083 try { 084 if (updatedNotes.containsKey(note)) { 085 // if note has been created earlier in this task, obtain its real id and not use the placeholder id 086 note = updatedNotes.get(note); 087 } 088 Note newNote; 089 switch (comment.getNoteAction()) { 090 case opened: 091 if (Main.isDebugEnabled()) { 092 Main.debug("opening new note"); 093 } 094 newNote = api.createNote(note.getLatLon(), comment.getText(), monitor); 095 break; 096 case closed: 097 if (Main.isDebugEnabled()) { 098 Main.debug("closing note " + note.getId()); 099 } 100 newNote = api.closeNote(note, comment.getText(), monitor); 101 break; 102 case commented: 103 if (Main.isDebugEnabled()) { 104 Main.debug("adding comment to note " + note.getId()); 105 } 106 newNote = api.addCommentToNote(note, comment.getText(), monitor); 107 break; 108 case reopened: 109 if (Main.isDebugEnabled()) { 110 Main.debug("reopening note " + note.getId()); 111 } 112 newNote = api.reopenNote(note, comment.getText(), monitor); 113 break; 114 default: 115 newNote = null; 116 } 117 updatedNotes.put(note, newNote); 118 } catch (Exception e) { 119 Main.error("Failed to upload note to server: " + note.getId()); 120 failedNotes.put(note, e); 121 } 122 } 123 124 /** Updates the note layer with uploaded notes and notifies the user of any upload failures */ 125 @Override 126 protected void finish() { 127 if (Main.isDebugEnabled()) { 128 Main.debug("finish called in notes upload task. Notes to update: " + updatedNotes.size()); 129 } 130 noteData.updateNotes(updatedNotes); 131 if (!failedNotes.isEmpty()) { 132 Main.error("Some notes failed to upload"); 133 StringBuilder sb = new StringBuilder(); 134 for (Map.Entry<Note, Exception> entry : failedNotes.entrySet()) { 135 sb.append(tr("Note {0} failed: {1}", entry.getKey().getId(), entry.getValue().getMessage())); 136 sb.append('\n'); 137 } 138 Main.error("Notes failed to upload: " + sb.toString()); 139 JOptionPane.showMessageDialog(Main.map, sb.toString(), tr("Notes failed to upload"), JOptionPane.ERROR_MESSAGE); 140 } 141 } 142 } 143}