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