Ticket #10700: note_upload.patch

File note_upload.patch, 13.9 KB (added by ToeBee, 11 years ago)
  • src/org/openstreetmap/josm/actions/UploadNotesAction.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.event.ActionEvent;
     7import java.util.List;
     8
     9import org.openstreetmap.josm.Main;
     10import org.openstreetmap.josm.actions.upload.UploadNotesTask;
     11import org.openstreetmap.josm.data.osm.NoteData;
     12import org.openstreetmap.josm.gui.layer.NoteLayer;
     13import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
     14import org.openstreetmap.josm.tools.ImageProvider;
     15
     16/**
     17 * Action to initiate uploading changed notes to the OSM server.
     18 * On click, it finds the note layer and fires off an upload task
     19 * with the note data contained in the layer.
     20 *
     21 */
     22public class UploadNotesAction extends JosmAction {
     23
     24    /** Create a new action to upload notes */
     25    public UploadNotesAction () {
     26        putValue(SHORT_DESCRIPTION,tr("Upload note changes to server"));
     27        putValue(NAME, tr("Upload notes"));
     28        putValue(SMALL_ICON, ImageProvider.get("upload"));
     29    }
     30
     31    @Override
     32    public void actionPerformed(ActionEvent e) {
     33        List<NoteLayer> noteLayers = null;
     34        if (Main.map != null) {
     35            noteLayers = Main.map.mapView.getLayersOfType(NoteLayer.class);
     36        }
     37        NoteLayer layer;
     38        if (noteLayers != null && noteLayers.size() > 0) {
     39            layer = noteLayers.get(0);
     40        } else {
     41            Main.error("No note layer found");
     42            return;
     43        }
     44        Main.debug("uploading note changes");
     45        NoteData noteData = layer.getNoteData();
     46
     47        if(noteData == null || !noteData.isModified()) {
     48            Main.debug("No changed notes to upload");
     49            return;
     50        }
     51        UploadNotesTask uploadTask = new UploadNotesTask();
     52        uploadTask.uploadNotes(noteData, new PleaseWaitProgressMonitor(tr("Uploading notes to server")));
     53    }
     54}
  • src/org/openstreetmap/josm/actions/upload/UploadNotesTask.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.actions.upload;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.io.IOException;
     7import java.util.HashMap;
     8import java.util.Map;
     9
     10import javax.swing.JOptionPane;
     11
     12import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.data.notes.Note;
     14import org.openstreetmap.josm.data.notes.NoteComment;
     15import org.openstreetmap.josm.data.osm.NoteData;
     16import org.openstreetmap.josm.gui.PleaseWaitRunnable;
     17import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     18import org.openstreetmap.josm.io.OsmApi;
     19import org.openstreetmap.josm.io.OsmTransferException;
     20import org.xml.sax.SAXException;
     21
     22/**
     23 * Class for uploading note changes to the server
     24 */
     25public class UploadNotesTask {
     26
     27    private UploadTask uploadTask;
     28    private NoteData noteData;
     29
     30    /**
     31     * Upload notes with modifications to the server
     32     * @param noteData Note dataset with changes to upload
     33     * @param progressMonitor progress monitor for user feedback
     34     */
     35    public void uploadNotes(NoteData noteData, ProgressMonitor progressMonitor) {
     36        this.noteData = noteData;
     37        uploadTask = new UploadTask("Uploading modified notes", progressMonitor);
     38        Main.worker.submit(uploadTask);
     39    }
     40
     41    private class UploadTask extends PleaseWaitRunnable {
     42
     43        private boolean isCanceled = false;
     44        Map<Note, Note> updatedNotes = new HashMap<>();
     45        Map<Note, Exception> failedNotes = new HashMap<>();
     46
     47        public UploadTask(String title, ProgressMonitor monitor) {
     48            super(title, monitor, false);
     49        }
     50
     51        @Override
     52        protected void cancel() {
     53            Main.debug("note upload canceled");
     54            isCanceled = true;
     55        }
     56
     57        @Override
     58        protected void realRun() throws SAXException, IOException, OsmTransferException {
     59            ProgressMonitor monitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
     60            OsmApi api = OsmApi.getOsmApi();
     61            for (Note note : noteData.getNotes()) {
     62                if(isCanceled) {
     63                    Main.info("Note upload interrupted by user");
     64                    break;
     65                }
     66                for (NoteComment comment : note.getComments()) {
     67                    if (comment.getIsNew()) {
     68                        Main.debug("found note change to upload");
     69                        try {
     70                            Note newNote;
     71                            switch (comment.getNoteAction()) {
     72                            case opened:
     73                                Main.debug("opening new note");
     74                                newNote = api.createNote(note.getLatLon(), comment.getText(), monitor);
     75                                note.setId(newNote.getId());
     76                                break;
     77                            case closed:
     78                                Main.debug("closing note " + note.getId());
     79                                newNote = api.closeNote(note, comment.getText(), monitor);
     80                                break;
     81                            case commented:
     82                                Main.debug("adding comment to note " + note.getId());
     83                                newNote = api.addCommentToNote(note, comment.getText(), monitor);
     84                                break;
     85                            case reopened:
     86                                Main.debug("reopening note " + note.getId());
     87                                newNote = api.reopenNote(note, comment.getText(), monitor);
     88                                break;
     89                            default:
     90                                newNote = null;
     91                            }
     92                            updatedNotes.put(note, newNote);
     93                        } catch (Exception e) {
     94                            Main.error("Failed to upload note to server: " + note.getId());
     95                            failedNotes.put(note, e);
     96                        }
     97                    }
     98                }
     99            }
     100        }
     101
     102        /** Updates the note layer with uploaded notes and notifies the user of any upload failures */
     103        @Override
     104        protected void finish() {
     105            Main.debug("finish called in notes upload task. Notes to update: " + updatedNotes.size());
     106            noteData.updateNotes(updatedNotes);
     107            if (!failedNotes.isEmpty()) {
     108                Main.error("Some notes failed to upload");
     109                StringBuilder sb = new StringBuilder();
     110                for (Map.Entry<Note, Exception> entry : failedNotes.entrySet()) {
     111                    sb.append(tr("Note {0} failed: {1}", entry.getKey().getId(), entry.getValue().getMessage()));
     112                    sb.append("\n");
     113                }
     114                Main.error("Notes failed to upload: " + sb.toString());
     115                JOptionPane.showMessageDialog(Main.map, sb.toString(), tr("Notes failed to upload"), JOptionPane.ERROR_MESSAGE);
     116            }
     117        }
     118
     119    }
     120
     121}
  • src/org/openstreetmap/josm/data/osm/NoteData.java

     
    44import java.util.ArrayList;
    55import java.util.Date;
    66import java.util.List;
     7import java.util.Map;
    78
    89import org.openstreetmap.josm.Main;
    910import org.openstreetmap.josm.data.coor.LatLon;
     
    6364    }
    6465
    6566    /**
     67     * Return whether or not there are any changes in the note data set.
     68     * These changes may need to be either uploaded or saved.
     69     * @return true if local modifications have been made to the note data set. False otherwise.
     70     */
     71    public synchronized boolean isModified() {
     72        for (Note note : noteList) {
     73            if (note.getId() < 0) { //notes with negative IDs are new
     74                return true;
     75            }
     76            for (NoteComment comment : note.getComments()) {
     77                if (comment.getIsNew()) {
     78                    return true;
     79                }
     80            }
     81        }
     82        return false;
     83    }
     84
     85    /**
    6686     * Add notes to the data set. It only adds a note if the ID is not already present
    6787     * @param newNotes A list of notes to add
    6888     */
    69     public void addNotes(List<Note> newNotes) {
     89    public synchronized void addNotes(List<Note> newNotes) {
    7090        for (Note newNote : newNotes) {
    7191            if (!noteList.contains(newNote)) {
    7292                noteList.add(newNote);
     
    84104     * @param location Location of note
    85105     * @param text Required comment with which to open the note
    86106     */
    87     public void createNote(LatLon location, String text) {
     107    public synchronized void createNote(LatLon location, String text) {
    88108        if(text == null || text.isEmpty()) {
    89109            throw new IllegalArgumentException("Comment can not be blank when creating a note");
    90110        }
     
    104124     * @param note Note to add comment to. Must already exist in the layer
    105125     * @param text Comment to add
    106126     */
    107     public void addCommentToNote(Note note, String text) {
     127    public synchronized void addCommentToNote(Note note, String text) {
    108128        if (!noteList.contains(note)) {
    109129            throw new IllegalArgumentException("Note to modify must be in layer");
    110130        }
     
    122142     * @param note Note to close. Must already exist in the layer
    123143     * @param text Comment to attach to close action, if desired
    124144     */
    125     public void closeNote(Note note, String text) {
     145    public synchronized void closeNote(Note note, String text) {
    126146        if (!noteList.contains(note)) {
    127147            throw new IllegalArgumentException("Note to close must be in layer");
    128148        }
     
    142162     * @param note Note to reopen. Must already exist in the layer
    143163     * @param text Comment to attach to the reopen action, if desired
    144164     */
    145     public void reOpenNote(Note note, String text) {
     165    public synchronized void reOpenNote(Note note, String text) {
    146166        if (!noteList.contains(note)) {
    147167            throw new IllegalArgumentException("Note to reopen must be in layer");
    148168        }
     
    165185        JosmUserIdentityManager userMgr = JosmUserIdentityManager.getInstance();
    166186        return User.createOsmUser(userMgr.getUserId(), userMgr.getUserName());
    167187    }
     188
     189    /**
     190     * Updates notes with new state. Primarily to be used when updating the
     191     * note layer after uploading note changes to the server.
     192     * @param updatedNotes Map containing the original note as the key and the updated note as the value
     193     */
     194    public synchronized void updateNotes(Map<Note, Note> updatedNotes) {
     195        for (Map.Entry<Note, Note> entry : updatedNotes.entrySet()) {
     196            Note oldNote = entry.getKey();
     197            Note newNote = entry.getValue();
     198            oldNote.updateWith(newNote);
     199        }
     200        dataUpdated();
     201    }
    168202}
  • src/org/openstreetmap/josm/gui/dialogs/NoteDialog.java

     
    2727import javax.swing.event.ListSelectionListener;
    2828
    2929import org.openstreetmap.josm.Main;
     30import org.openstreetmap.josm.actions.UploadNotesAction;
    3031import org.openstreetmap.josm.actions.mapmode.AddNoteAction;
    3132import org.openstreetmap.josm.data.notes.Note;
    3233import org.openstreetmap.josm.data.notes.Note.State;
     
    7273    private final CloseAction closeAction;
    7374    private final NewAction newAction;
    7475    private final ReopenAction reopenAction;
     76    private final UploadNotesAction uploadAction;
    7577
    7678    private NoteData noteData;
    7779
     
    8486        closeAction = new CloseAction();
    8587        newAction = new NewAction();
    8688        reopenAction = new ReopenAction();
     89        uploadAction = new UploadNotesAction();
    8790        buildDialog();
    8891    }
    8992
     
    113116                new SideButton(newAction, false),
    114117                new SideButton(addCommentAction, false),
    115118                new SideButton(closeAction, false),
    116                 new SideButton(reopenAction, false)}));
     119                new SideButton(reopenAction, false),
     120                new SideButton(uploadAction, false)}));
    117121        updateButtonStates();
    118122    }
    119123
     
    131135            addCommentAction.setEnabled(false);
    132136            reopenAction.setEnabled(true);
    133137        }
     138        if(noteData == null || !noteData.isModified()) {
     139            uploadAction.setEnabled(false);
     140        } else {
     141            uploadAction.setEnabled(true);
     142        }
    134143    }
    135144
    136145    @Override
  • src/org/openstreetmap/josm/gui/layer/NoteLayer.java

     
    7272
    7373    @Override
    7474    public boolean isModified() {
    75         for (Note note : noteData.getNotes()) {
    76             if (note.getId() < 0) { //notes with negative IDs are new
    77                 return true;
    78             }
    79             for (NoteComment comment : note.getComments()) {
    80                 if (comment.getIsNew()) {
    81                     return true;
    82                 }
    83             }
    84         }
    85         return false;
     75        return noteData.isModified();
    8676    }
    8777
    8878    @Override