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