Changeset 2325 in josm


Ignore:
Timestamp:
2009-10-26T16:51:21+01:00 (13 years ago)
Author:
Gubaer
Message:

fixed #3783: does not finish download API
Also improved help

Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/UpdateDataAction.java

    r2323 r2325  
    1010import java.util.ArrayList;
    1111import java.util.List;
     12import java.util.concurrent.Future;
    1213
     14import org.openstreetmap.josm.Main;
    1315import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTaskList;
    1416import org.openstreetmap.josm.data.osm.DataSource;
     
    8183            // bounds defined? => use the bbox downloader
    8284            //
    83             new DownloadOsmTaskList().download(false, areas, new PleaseWaitProgressMonitor(tr("Updating data")));
     85            final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data"));
     86            final Future<?> future = new DownloadOsmTaskList().download(false /* no new layer */, areas, monitor);
     87            Main.worker.submit(
     88                    new Runnable() {
     89                        public void run() {
     90                            try {
     91                                future.get();
     92                            } catch(Exception e) {
     93                                e.printStackTrace();
     94                                return;
     95                            }
     96                            monitor.close();
     97                        }
     98                    }
     99            );
    84100        }
    85101    }
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java

    r2322 r2325  
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
     5import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    56
    67import java.awt.EventQueue;
    7 import java.awt.event.ActionEvent;
    8 import java.awt.event.ActionListener;
    98import java.awt.geom.Area;
    109import java.awt.geom.Rectangle2D;
     
    2423import org.openstreetmap.josm.data.osm.DataSet;
    2524import org.openstreetmap.josm.data.osm.OsmPrimitive;
     25import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     26import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
    2627import org.openstreetmap.josm.gui.layer.Layer;
    2728import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     
    2930import org.openstreetmap.josm.gui.progress.ProgressMonitor.CancelListener;
    3031import org.openstreetmap.josm.tools.ExceptionUtil;
     32import org.openstreetmap.josm.tools.ImageProvider;
    3133
    3234/**
    3335 * This class encapsulates the downloading of several bounding boxes that would otherwise be too
    34  * large to download in one go. Error messages will be collected for all downloads and displayed
    35  * as a list in the end.
     36 * large to download in one go. Error messages will be collected for all downloads and displayed as
     37 * a list in the end.
    3638 * @author xeen
    37  *
     39 * 
    3840 */
    39 public class DownloadOsmTaskList implements Runnable {
     41public class DownloadOsmTaskList {
    4042    private List<DownloadTask> osmTasks = new LinkedList<DownloadTask>();
    4143    private List<Future<?>> osmTaskFutures = new LinkedList<Future<?>>();
     
    4951    public Future<?> download(boolean newLayer, List<Rectangle2D> rects, ProgressMonitor progressMonitor) {
    5052        this.progressMonitor = progressMonitor;
    51         if(newLayer) {
     53        if (newLayer) {
    5254            Layer l = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
    5355            Main.main.addLayer(l);
     
    5759        progressMonitor.beginTask(null, rects.size());
    5860        int i = 0;
    59         for(Rectangle2D td : rects) {
     61        for (Rectangle2D td : rects) {
    6062            i++;
    6163            DownloadTask dt = new DownloadOsmTask();
    6264            ProgressMonitor childProgress = progressMonitor.createSubTaskMonitor(1, false);
    6365            childProgress.setSilent(true);
    64             childProgress.setCustomText(tr("Download {0} of {1} ({2} left)", i, rects.size(), rects.size()-i));
     66            childProgress.setCustomText(tr("Download {0} of {1} ({2} left)", i, rects.size(), rects.size() - i));
    6567            Future<?> future = dt.download(null, td.getMinY(), td.getMinX(), td.getMaxY(), td.getMaxX(), childProgress);
    6668            osmTaskFutures.add(future);
    6769            osmTasks.add(dt);
    6870        }
    69         progressMonitor.addCancelListener(
    70                 new CancelListener() {
    71                     public void operationCanceled() {
    72                         for (DownloadTask dt: osmTasks) {
    73                             dt.cancel();
    74                         }
    75                     }
    76                 }
    77         );
    78         return Main.worker.submit(this);
     71        progressMonitor.addCancelListener(new CancelListener() {
     72            public void operationCanceled() {
     73                for (DownloadTask dt : osmTasks) {
     74                    dt.cancel();
     75                }
     76            }
     77        });
     78        return Main.worker.submit(new PostDownloadProcessor());
    7979    }
    8080
     
    8484     * @param The Collection of Areas to download
    8585     */
    86     public void download(boolean newLayer, Collection<Area> areas, ProgressMonitor progressMonitor) {
     86    public Future<?> download(boolean newLayer, Collection<Area> areas, ProgressMonitor progressMonitor) {
    8787        progressMonitor.beginTask(tr("Updating data"));
    8888        try {
    8989            List<Rectangle2D> rects = new LinkedList<Rectangle2D>();
    90             for(Area a : areas) {
     90            for (Area a : areas) {
    9191                rects.add(a.getBounds2D());
    9292            }
    9393
    94             download(newLayer, rects, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
     94            return download(newLayer, rects, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    9595        } finally {
    9696            progressMonitor.finishTask();
     
    9999
    100100    /**
    101      * Grabs and displays the error messages after all download threads have finished.
    102      */
    103     public void run() {
    104         progressMonitor.finishTask();
    105 
    106         // wait for all tasks to finish
    107         //
    108         for (Future<?> future: osmTaskFutures) {
    109             try {
    110                 future.get();
    111             } catch(Exception e) {
    112                 e.printStackTrace();
    113                 return;
    114             }
    115         }
    116         LinkedHashSet<Object> errors = new LinkedHashSet<Object>();
    117         for(DownloadTask dt : osmTasks) {
    118             errors.addAll(dt.getErrorObjects());
    119         }
    120         if (!errors.isEmpty()) {
    121             StringBuffer sb = new StringBuffer();
    122             for (Object error:errors) {
    123                 if (error instanceof String) {
    124                     sb.append("<li>").append(error).append("</li>").append("<br>");
    125                 } else if (error instanceof Exception) {
    126                     sb.append("<li>").append(ExceptionUtil.explainException((Exception)error)).append("</li>").append("<br>");
    127                 }
    128             }
    129             sb.insert(0, "<ul>");
    130             sb.append("</ul>");
    131 
    132             JOptionPane.showMessageDialog(
    133                     Main.parent,
    134                     "<html>"+tr("The following errors occurred during mass download: {0}", sb.toString())
    135                     +"</html>",
    136                     tr("Errors during Download"),
    137                     JOptionPane.ERROR_MESSAGE);
    138             return;
    139         }
    140 
    141         // FIXME: this is a hack. We assume that the user canceled the whole download if at least
    142         // one task was canceled or if it failed
    143         //
    144         for (DownloadTask task: osmTasks) {
    145             if (task instanceof DownloadOsmTask) {
    146                 DownloadOsmTask osmTask = (DownloadOsmTask)task;
    147                 if (osmTask.isCanceled() || osmTask.isFailed())
    148                     return;
    149             }
    150         }
    151         final OsmDataLayer editLayer = Main.map.mapView.getEditLayer();
    152         if (editLayer != null) {
    153             Set<OsmPrimitive> myPrimitives = getCompletePrimitives(editLayer.data);
    154             for (DownloadTask task : osmTasks) {
    155                 if(task instanceof DownloadOsmTask) {
    156                     DataSet ds = ((DownloadOsmTask)task).getDownloadedData();
    157                     if (ds != null) {
    158                         myPrimitives.removeAll(ds.nodes);
    159                         myPrimitives.removeAll(ds.ways);
    160                         myPrimitives.removeAll(ds.relations);
    161                     }
    162                 }
    163             }
    164             if (! myPrimitives.isEmpty()) {
    165                 handlePotentiallyDeletedPrimitives(myPrimitives);
    166             }
    167         }
    168     }
    169 
    170 
    171     /**
    172      * Replies the set of ids of all complete primitives (i.e. those with
    173      * ! primitive.incomplete)
    174      *
    175      * @return the set of ids of all complete primitives
     101     * Replies the set of ids of all complete, non-new primitives (i.e. those with !
     102     * primitive.incomplete)
     103     *
     104     * @return the set of ids of all complete, non-new primitives
    176105     */
    177106    protected Set<OsmPrimitive> getCompletePrimitives(DataSet ds) {
    178107        HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
    179108        for (OsmPrimitive primitive : ds.nodes) {
    180             if (!primitive.incomplete && primitive.isNew()) {
     109            if (!primitive.incomplete && !primitive.isNew()) {
    181110                ret.add(primitive);
    182111            }
    183112        }
    184113        for (OsmPrimitive primitive : ds.ways) {
    185             if (! primitive.incomplete && primitive.isNew()) {
     114            if (!primitive.incomplete && !primitive.isNew()) {
    186115                ret.add(primitive);
    187116            }
    188117        }
    189118        for (OsmPrimitive primitive : ds.relations) {
    190             if (! primitive.incomplete && primitive.isNew()) {
     119            if (!primitive.incomplete && !primitive.isNew()) {
    191120                ret.add(primitive);
    192121            }
     
    196125
    197126    /**
    198      * Updates the local state of a set of primitives (given by a set of primitive
    199      * ids) with the state currently held on the server.
    200      *
     127     * Updates the local state of a set of primitives (given by a set of primitive ids) with the
     128     * state currently held on the server.
     129     * 
    201130     * @param potentiallyDeleted a set of ids to check update from the server
    202131     */
     
    208137            }
    209138        }
    210         EventQueue.invokeLater(
    211                 new Runnable() {
    212                     public void run() {
    213                         new UpdateSelectionAction().updatePrimitives(toSelect);
    214                     }
    215                 }
     139        EventQueue.invokeLater(new Runnable() {
     140            public void run() {
     141                new UpdateSelectionAction().updatePrimitives(toSelect);
     142            }
     143        });
     144    }
     145
     146    /**
     147     * Processes a set of primitives (given by a set of their ids) which might be deleted on the
     148     * server. First prompts the user whether he wants to check the current state on the server. If
     149     * yes, retrieves the current state on the server and checks whether the primitives are indeed
     150     * deleted on the server.
     151     *
     152     * @param potentiallyDeleted a set of primitives (given by their ids)
     153     */
     154    protected void handlePotentiallyDeletedPrimitives(Set<OsmPrimitive> potentiallyDeleted) {
     155        ButtonSpec[] options = new ButtonSpec[] {
     156                new ButtonSpec(
     157                        tr("Check on the server"),
     158                        ImageProvider.get("ok"),
     159                        tr("Click to check whether objects in your local dataset are deleted on the server"),
     160                        null  /* no specific help topic */
     161                ),
     162                new ButtonSpec(
     163                        tr("Ignore"),
     164                        ImageProvider.get("cancel"),
     165                        tr("Click to abort and to resume editing"),
     166                        null /* no specific help topic */
     167                ),
     168        };
     169
     170        String message = tr("<html>" + "There are {0} primitives in your local dataset which<br>"
     171                + "might be deleted on the server. If you later try to delete or<br>"
     172                + "update them the server is likely to report a<br>" + "conflict.<br>" + "<br>"
     173                + "Click <strong>{1}</strong> to check the state of these primitives<br>" + "on the server.<br>"
     174                + "Click <strong>{2}</strong> to ignore.<br>" + "</html>",
     175                potentiallyDeleted.size(),
     176                options[0].text,
     177                options[1].text
     178                );
     179
     180        int ret = HelpAwareOptionPane.showOptionDialog(
     181                Main.parent,
     182                message,
     183                tr("Deleted or moved primitives"),
     184                JOptionPane.WARNING_MESSAGE,
     185                null,
     186                options,
     187                options[0],
     188                ht("/Action/UpdateData#SyncPotentiallyDeletedObjects")
    216189        );
    217     }
    218 
    219     /**
    220      * Processes a set of primitives (given by a set of their ids) which might be
    221      * deleted on the server. First prompts the user whether he wants to check
    222      * the current state on the server. If yes, retrieves the current state on the server
    223      * and checks whether the primitives are indeed deleted on the server.
    224      *
    225      * @param potentiallyDeleted a set of primitives (given by their ids)
    226      */
    227     protected void handlePotentiallyDeletedPrimitives(Set<OsmPrimitive> potentiallyDeleted) {
    228         String [] options = {
    229                 "Check on the server",
    230                 "Ignore"
    231         };
    232 
    233         String message = tr("<html>"
    234                 +  "There are {0} primitives in your local dataset which<br>"
    235                 + "might be deleted on the server. If you later try to delete or<br>"
    236                 + "update them the server is likely to report a<br>"
    237                 + "conflict.<br>"
    238                 + "<br>"
    239                 + "Click <strong>{1}</strong> to check the state of these primitives<br>"
    240                 + "on the server.<br>"
    241                 + "Click <strong>{2}</strong> to ignore.<br>"
    242                 + "</html>",
    243                 potentiallyDeleted.size(), options[0], options[1]
    244         );
    245 
    246         int ret =JOptionPane.showOptionDialog(
    247                 Main.parent,
    248                 message,
    249                 tr("Deleted or moved primitives"),
    250                 JOptionPane.YES_NO_OPTION,
    251                 JOptionPane.WARNING_MESSAGE,
    252                 null,
    253                 options,
    254                 options[0]
    255         );
    256         switch(ret) {
    257             case JOptionPane.CLOSED_OPTION: return;
    258             case JOptionPane.NO_OPTION: return;
    259             case JOptionPane.YES_OPTION: updatePotentiallyDeletedPrimitives(potentiallyDeleted); break;
    260         }
     190        if (ret != 0 /* OK */)
     191            return;
     192       
     193        updatePotentiallyDeletedPrimitives(potentiallyDeleted);       
    261194    }
    262195
    263196    /**
    264197     * Replies the set of primitive ids which have been downloaded by this task list
    265      *
     198     * 
    266199     * @return the set of primitive ids which have been downloaded by this task list
    267200     */
     
    269202        HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
    270203        for (DownloadTask task : osmTasks) {
    271             if(task instanceof DownloadOsmTask) {
    272                 DataSet ds = ((DownloadOsmTask)task).getDownloadedData();
     204            if (task instanceof DownloadOsmTask) {
     205                DataSet ds = ((DownloadOsmTask) task).getDownloadedData();
    273206                if (ds != null) {
    274207                    ret.addAll(ds.nodes);
     
    280213        return ret;
    281214    }
     215
     216    class PostDownloadProcessor implements Runnable {
     217        /**
     218         * Grabs and displays the error messages after all download threads have finished.
     219         */
     220        public void run() {
     221            progressMonitor.finishTask();
     222
     223            // wait for all download tasks to finish
     224            //
     225            for (Future<?> future : osmTaskFutures) {
     226                try {
     227                    future.get();
     228                } catch (Exception e) {
     229                    e.printStackTrace();
     230                    return;
     231                }
     232            }
     233            LinkedHashSet<Object> errors = new LinkedHashSet<Object>();
     234            for (DownloadTask dt : osmTasks) {
     235                errors.addAll(dt.getErrorObjects());
     236            }
     237            if (!errors.isEmpty()) {
     238                StringBuffer sb = new StringBuffer();
     239                for (Object error : errors) {
     240                    if (error instanceof String) {
     241                        sb.append("<li>").append(error).append("</li>").append("<br>");
     242                    } else if (error instanceof Exception) {
     243                        sb.append("<li>").append(ExceptionUtil.explainException((Exception) error)).append("</li>")
     244                                .append("<br>");
     245                    }
     246                }
     247                sb.insert(0, "<ul>");
     248                sb.append("</ul>");
     249
     250                JOptionPane.showMessageDialog(Main.parent, "<html>"
     251                        + tr("The following errors occurred during mass download: {0}", sb.toString()) + "</html>",
     252                        tr("Errors during Download"), JOptionPane.ERROR_MESSAGE);
     253                return;
     254            }
     255
     256            // FIXME: this is a hack. We assume that the user canceled the whole download if at
     257            // least
     258            // one task was canceled or if it failed
     259            //
     260            for (DownloadTask task : osmTasks) {
     261                if (task instanceof DownloadOsmTask) {
     262                    DownloadOsmTask osmTask = (DownloadOsmTask) task;
     263                    if (osmTask.isCanceled() || osmTask.isFailed())
     264                        return;
     265                }
     266            }
     267            final OsmDataLayer editLayer = Main.map.mapView.getEditLayer();
     268            if (editLayer != null) {
     269                Set<OsmPrimitive> myPrimitives = getCompletePrimitives(editLayer.data);
     270                for (DownloadTask task : osmTasks) {
     271                    if (task instanceof DownloadOsmTask) {
     272                        DataSet ds = ((DownloadOsmTask) task).getDownloadedData();
     273                        if (ds != null) {
     274                            myPrimitives.removeAll(ds.nodes);
     275                            myPrimitives.removeAll(ds.ways);
     276                            myPrimitives.removeAll(ds.relations);
     277                        }
     278                    }
     279                }
     280                if (!myPrimitives.isEmpty()) {
     281                    handlePotentiallyDeletedPrimitives(myPrimitives);
     282                }
     283            }
     284        }
     285    }
    282286}
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r2308 r2325  
    44
    55import static org.openstreetmap.josm.tools.I18n.marktr;
     6import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    67import static org.openstreetmap.josm.tools.I18n.tr;
    78import static org.openstreetmap.josm.tools.I18n.trn;
     
    6263import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
    6364import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
     65import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    6466import org.openstreetmap.josm.gui.MapView;
     67import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
    6568import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    6669import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
     
    334337        );
    335338        String msg2 = trn(
    336                 "{0} object has been purged from the local dataset because it is deleted on the server.",
    337                 "{0} objects have been purged from the local dataset because they are deleted on the server.",
     339                "{0} conflict has been <strong>resolved automatically</strong> by purging {0} object<br>from the local dataset because it is deleted on the server.",
     340                "{0} conflicts have been <strong>resolved automatically</strong> by purging {0} objects<br> from the local dataset because they are deleted on the server.",
    338341                numPurgedPrimitives,
    339342                numPurgedPrimitives
    340343        );
     344        int numRemainingConflicts = numNewConflicts - numPurgedPrimitives;
     345        String msg3 = "";
     346        if (numRemainingConflicts >0) {
     347            msg3 = trn(
     348                    "{0} conflict remains to be resolved.<br><br>Please open the Conflict List Dialog and manually resolve it.",
     349                    "{0} conflicts remain to be resolved.<br><br>Please open the Conflict List Dialog and manually resolve them.",
     350                    numRemainingConflicts,
     351                    numRemainingConflicts
     352            );           
     353        }
     354       
    341355        StringBuffer sb = new StringBuffer();
    342356        sb.append("<html>").append(msg1);
     
    344358            sb.append("<br>").append(msg2);
    345359        }
    346         sb.append("<br>").append(tr("Please consult the Conflict List Dialog<br>and manually resolve them."));
     360        if (numRemainingConflicts > 0) {
     361            sb.append("<br>").append(msg3);
     362        }
    347363        sb.append("</html>");
    348364        if (numNewConflicts > 0) {
    349             JButton[] options = new JButton[] {
    350                     new JButton(tr("OK")),
    351                     new JButton(tr("Help"))
     365            ButtonSpec[] options = new ButtonSpec[] {
     366                    new ButtonSpec(
     367                            tr("OK"),
     368                            ImageProvider.get("ok"),
     369                            tr("Click to close this dialog and continue editing"),
     370                            null /* no specific help */
     371                            )
    352372            };
    353             options[0].setIcon(ImageProvider.get("ok"));
    354             options[1].setIcon(ImageProvider.get("help"));
    355             final JOptionPane pane = new JOptionPane(
     373            HelpAwareOptionPane.showOptionDialog(
     374                    Main.parent,
    356375                    sb.toString(),
     376                    tr("Conflicts detected"),
    357377                    JOptionPane.WARNING_MESSAGE,
    358                     JOptionPane.DEFAULT_OPTION,
    359                     null,
     378                    null, /* no icon */
    360379                    options,
    361                     options[0]
    362             );
    363             final JDialog dialog = new JDialog(
    364                     JOptionPane.getFrameForComponent(Main.parent),
    365                     tr("Conflicts detected"),
    366                     true);
    367             options[0].addActionListener(
    368                     new ActionListener() {
    369                         public void actionPerformed(ActionEvent e) {
    370                             dialog.setVisible(false);
    371                         }
    372                     }
    373             );
    374             options[1].addActionListener(
    375                     new ActionListener() {
    376                         public void actionPerformed(ActionEvent e) {
    377                             HelpBrowser b = new HelpBrowser();
    378                             b.openHelpTopic("Help/Concepts/Conflict");
    379                             b.setVisible(true);
    380                         }
    381                     }
    382             );
    383             dialog.setContentPane(pane);
    384             dialog.pack();
    385             HelpUtil.setHelpContext(dialog.getRootPane(), "/Concepts/Conflict");
    386             WindowGeometry.centerOnScreen(dialog.getSize()).applySafe(dialog);
    387             dialog.setVisible(true);
     380                    options[0],
     381                    ht("/Concepts/Conflict#WarningAboutDetectedConflicts")
     382             );           
    388383        }
    389384    }
Note: See TracChangeset for help on using the changeset viewer.