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