Changeset 19152 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2024-07-25T20:56:22+02:00 (4 months ago)
Author:
taylor.smock
Message:

See #23821: Refactor LoadAndZoomHandler and add tests

This fixes some lint issues, specifically in regard to method complexity.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java

    r18871 r19152  
    66import java.awt.geom.Area;
    77import java.awt.geom.Rectangle2D;
    8 import java.util.Arrays;
    98import java.util.Collection;
    109import java.util.Collections;
     
    1817import java.util.concurrent.TimeoutException;
    1918import java.util.stream.Collectors;
     19import java.util.stream.Stream;
    2020
    2121import javax.swing.JOptionPane;
     
    6565    public static final String command2 = "zoom";
    6666    private static final String CURRENT_SELECTION = "currentselection";
     67    private static final String SELECT = "select";
     68    private static final String ADDTAGS = "addtags";
     69    private static final String CHANGESET_COMMENT = "changeset_comment";
     70    private static final String CHANGESET_SOURCE = "changeset_source";
     71    private static final String CHANGESET_HASHTAGS = "changeset_hashtags";
     72    private static final String CHANGESET_TAGS = "changeset_tags";
     73    private static final String SEARCH = "search";
    6774
    6875    // Mandatory arguments
     
    8188        String msg = tr("Remote Control has been asked to load data from the API.") +
    8289                "<br>" + tr("Bounding box: ") + new BBox(minlon, minlat, maxlon, maxlat).toStringCSV(", ");
    83         if (args.containsKey("select") && !toSelect.isEmpty()) {
     90        if (args.containsKey(SELECT) && !toSelect.isEmpty()) {
    8491            msg += "<br>" + tr("Selection: {0}", toSelect.size());
    8592        }
     
    94101    @Override
    95102    public String[] getOptionalParams() {
    96         return new String[] {"new_layer", "layer_name", "addtags", "select", "zoom_mode",
    97                 "changeset_comment", "changeset_source", "changeset_hashtags", "changeset_tags",
    98                 "search", "layer_locked", "download_policy", "upload_policy"};
     103        return new String[] {"new_layer", "layer_name", ADDTAGS, SELECT, "zoom_mode",
     104                CHANGESET_COMMENT, CHANGESET_SOURCE, CHANGESET_HASHTAGS, CHANGESET_TAGS,
     105                SEARCH, "layer_locked", "download_policy", "upload_policy"};
    99106    }
    100107
     
    127134    @Override
    128135    protected void handleRequest() throws RequestHandlerErrorException {
     136        download();
     137        /*
     138         * deselect objects if parameter addtags given
     139         */
     140        if (args.containsKey(ADDTAGS) && !isKeepingCurrentSelection) {
     141            GuiHelper.executeByMainWorkerInEDT(() -> {
     142                DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     143                if (ds == null) // e.g. download failed
     144                    return;
     145                ds.clearSelection();
     146            });
     147        }
     148
     149        Collection<OsmPrimitive> forTagAdd = performSearchZoom();
     150
     151        // This comes before the other changeset tags, so that they can be overridden
     152        parseChangesetTags(args);
     153
     154        // add changeset tags after download if necessary
     155        addChangesetTags();
     156
     157        // add tags to objects
     158        addTags(forTagAdd);
     159    }
     160
     161    private void download() throws RequestHandlerErrorException {
    129162        DownloadOsmTask osmTask = new DownloadOsmTask();
    130163        try {
     
    137170                    Area toDownload = null;
    138171                    if (!settings.isNewLayer()) {
    139                         // find out whether some data has already been downloaded
    140                         Area present = null;
    141                         DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    142                         if (ds != null) {
    143                             present = ds.getDataSourceArea();
    144                         }
    145                         if (present != null && !present.isEmpty()) {
    146                             toDownload = new Area(new Rectangle2D.Double(minlon, minlat, maxlon-minlon, maxlat-minlat));
    147                             toDownload.subtract(present);
    148                             if (!toDownload.isEmpty()) {
    149                                 // the result might not be a rectangle (L shaped etc)
    150                                 Rectangle2D downloadBounds = toDownload.getBounds2D();
    151                                 minlat = downloadBounds.getMinY();
    152                                 minlon = downloadBounds.getMinX();
    153                                 maxlat = downloadBounds.getMaxY();
    154                                 maxlon = downloadBounds.getMaxX();
    155                             }
    156                         }
     172                        toDownload = removeAlreadyDownloadedArea();
    157173                    }
    158174                    if (toDownload != null && toDownload.isEmpty()) {
    159175                        Logging.info("RemoteControl: no download necessary");
    160176                    } else {
    161                         Future<?> future = MainApplication.worker.submit(
    162                                 new PostDownloadHandler(osmTask, osmTask.download(settings, new Bounds(minlat, minlon, maxlat, maxlon),
    163                                         null /* let the task manage the progress monitor */)));
    164                         GuiHelper.executeByMainWorkerInEDT(() -> {
    165                             try {
    166                                 future.get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS);
    167                                 if (osmTask.isFailed()) {
    168                                     Object error = osmTask.getErrorObjects().get(0);
    169                                     if (error instanceof OsmApiException) {
    170                                         throw (OsmApiException) error;
    171                                     }
    172                                     List<Throwable> exceptions = osmTask.getErrorObjects().stream()
    173                                                     .filter(Throwable.class::isInstance).map(Throwable.class::cast)
    174                                                     .collect(Collectors.toList());
    175                                     OsmTransferException osmTransferException =
    176                                             new OsmTransferException(String.join(", ", osmTask.getErrorMessages()));
    177                                     if (!exceptions.isEmpty()) {
    178                                         osmTransferException.initCause(exceptions.get(0));
    179                                         exceptions.remove(0);
    180                                         exceptions.forEach(osmTransferException::addSuppressed);
    181                                     }
    182                                     throw osmTransferException;
    183                                 }
    184                             } catch (InterruptedException | ExecutionException | TimeoutException |
    185                                     OsmTransferException | RuntimeException ex) { // NOPMD
    186                                 ExceptionDialogUtil.explainException(ex);
    187                             }
    188                         });
     177                        performDownload(osmTask, settings);
    189178                    }
    190179                }
     
    195184            throw new RequestHandlerErrorException(ex);
    196185        }
    197 
    198         /*
    199          * deselect objects if parameter addtags given
    200          */
    201         if (args.containsKey("addtags") && !isKeepingCurrentSelection) {
    202             GuiHelper.executeByMainWorkerInEDT(() -> {
    203                 DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    204                 if (ds == null) // e.g. download failed
    205                     return;
    206                 ds.clearSelection();
    207             });
    208         }
    209 
     186    }
     187
     188    /**
     189     * Remove areas that has already been downloaded
     190     * @return The area to download
     191     */
     192    private Area removeAlreadyDownloadedArea() {
     193        // find out whether some data has already been downloaded
     194        Area toDownload = null;
     195        Area present = null;
     196        DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     197        if (ds != null) {
     198            present = ds.getDataSourceArea();
     199        }
     200        if (present != null && !present.isEmpty()) {
     201            toDownload = new Area(new Rectangle2D.Double(minlon, minlat, maxlon-minlon, maxlat-minlat));
     202            toDownload.subtract(present);
     203            if (!toDownload.isEmpty()) {
     204                // the result might not be a rectangle (L shaped etc)
     205                Rectangle2D downloadBounds = toDownload.getBounds2D();
     206                minlat = downloadBounds.getMinY();
     207                minlon = downloadBounds.getMinX();
     208                maxlat = downloadBounds.getMaxY();
     209                maxlon = downloadBounds.getMaxX();
     210            }
     211        }
     212        return toDownload;
     213    }
     214
     215    private void performDownload(DownloadOsmTask osmTask, DownloadParams settings) {
     216        Future<?> future = MainApplication.worker.submit(
     217                new PostDownloadHandler(osmTask, osmTask.download(settings, new Bounds(minlat, minlon, maxlat, maxlon),
     218                        null /* let the task manage the progress monitor */)));
     219        GuiHelper.executeByMainWorkerInEDT(() -> {
     220            try {
     221                future.get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS);
     222                if (osmTask.isFailed()) {
     223                    Object error = osmTask.getErrorObjects().get(0);
     224                    if (error instanceof OsmApiException) {
     225                        throw (OsmApiException) error;
     226                    }
     227                    List<Throwable> exceptions = osmTask.getErrorObjects().stream()
     228                            .filter(Throwable.class::isInstance).map(Throwable.class::cast)
     229                            .collect(Collectors.toList());
     230                    OsmTransferException osmTransferException =
     231                            new OsmTransferException(String.join(", ", osmTask.getErrorMessages()));
     232                    if (!exceptions.isEmpty()) {
     233                        osmTransferException.initCause(exceptions.get(0));
     234                        exceptions.remove(0);
     235                        exceptions.forEach(osmTransferException::addSuppressed);
     236                    }
     237                    throw osmTransferException;
     238                }
     239            } catch (InterruptedException ex) {
     240                Thread.currentThread().interrupt();
     241                ExceptionDialogUtil.explainException(ex);
     242            } catch (ExecutionException | TimeoutException |
     243                     OsmTransferException | RuntimeException ex) { // NOPMD
     244                ExceptionDialogUtil.explainException(ex);
     245            }
     246        });
     247    }
     248
     249    private Collection<OsmPrimitive> performSearchZoom() throws RequestHandlerErrorException {
    210250        final Collection<OsmPrimitive> forTagAdd = new LinkedHashSet<>();
    211251        final Bounds bbox = new Bounds(minlat, minlon, maxlat, maxlon);
    212         if (args.containsKey("select") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
     252        if (args.containsKey(SELECT) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
    213253            // select objects after downloading, zoom to selection.
    214             GuiHelper.executeByMainWorkerInEDT(() -> {
    215                 Set<OsmPrimitive> newSel = new LinkedHashSet<>();
    216                 DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    217                 if (ds == null) // e.g. download failed
    218                     return;
    219                 for (SimplePrimitiveId id : toSelect) {
    220                     final OsmPrimitive p = ds.getPrimitiveById(id);
    221                     if (p != null) {
    222                         newSel.add(p);
    223                         forTagAdd.add(p);
    224                     }
    225                 }
    226                 if (isKeepingCurrentSelection) {
    227                     Collection<OsmPrimitive> sel = ds.getSelected();
    228                     newSel.addAll(sel);
    229                     forTagAdd.addAll(sel);
    230                 }
    231                 toSelect.clear();
    232                 ds.setSelected(newSel);
    233                 zoom(newSel, bbox);
    234                 MapFrame map = MainApplication.getMap();
    235                 if (MainApplication.isDisplayingMapView() && map.relationListDialog != null) {
    236                     map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342
    237                     map.relationListDialog.dataChanged(null);
    238                     map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class));
    239                 }
    240             });
    241         } else if (args.containsKey("search") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
    242             try {
    243                 final SearchCompiler.Match search = SearchCompiler.compile(args.get("search"));
    244                 MainApplication.worker.submit(() -> {
    245                     final DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    246                     final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search);
    247                     ds.setSelected(filteredPrimitives);
    248                     forTagAdd.addAll(filteredPrimitives);
    249                     zoom(filteredPrimitives, bbox);
    250                 });
    251             } catch (SearchParseError ex) {
    252                 Logging.error(ex);
    253                 throw new RequestHandlerErrorException(ex);
    254             }
     254            GuiHelper.executeByMainWorkerInEDT(() -> selectAndZoom(forTagAdd, bbox));
     255        } else if (args.containsKey(SEARCH) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
     256            searchAndZoom(forTagAdd, bbox);
    255257        } else {
    256258            // after downloading, zoom to downloaded area.
    257             zoom(Collections.<OsmPrimitive>emptySet(), bbox);
    258         }
    259 
    260         // This comes before the other changeset tags, so that they can be overridden
    261         parseChangesetTags(args);
    262 
    263         // add changeset tags after download if necessary
    264         if (args.containsKey("changeset_comment") || args.containsKey("changeset_source") || args.containsKey("changeset_hashtags")) {
     259            zoom(Collections.emptySet(), bbox);
     260        }
     261        return forTagAdd;
     262    }
     263
     264    private void selectAndZoom(Collection<OsmPrimitive> forTagAdd, Bounds bbox) {
     265        Set<OsmPrimitive> newSel = new LinkedHashSet<>();
     266        DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     267        if (ds == null) // e.g. download failed
     268            return;
     269        for (SimplePrimitiveId id : toSelect) {
     270            final OsmPrimitive p = ds.getPrimitiveById(id);
     271            if (p != null) {
     272                newSel.add(p);
     273                forTagAdd.add(p);
     274            }
     275        }
     276        if (isKeepingCurrentSelection) {
     277            Collection<OsmPrimitive> sel = ds.getSelected();
     278            newSel.addAll(sel);
     279            forTagAdd.addAll(sel);
     280        }
     281        toSelect.clear();
     282        ds.setSelected(newSel);
     283        zoom(newSel, bbox);
     284        MapFrame map = MainApplication.getMap();
     285        if (MainApplication.isDisplayingMapView() && map.relationListDialog != null) {
     286            map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342
     287            map.relationListDialog.dataChanged(null);
     288            map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class));
     289        }
     290    }
     291
     292    private void searchAndZoom(Collection<OsmPrimitive> forTagAdd, Bounds bbox) throws RequestHandlerErrorException {
     293        try {
     294            final SearchCompiler.Match search = SearchCompiler.compile(args.get(SEARCH));
    265295            MainApplication.worker.submit(() -> {
    266                 DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    267                 if (ds != null) {
    268                     for (String tag : Arrays.asList("changeset_comment", "changeset_source", "changeset_hashtags")) {
    269                         if (args.containsKey(tag)) {
    270                             final String tagKey = tag.substring("changeset_".length());
    271                             final String value = args.get(tag);
    272                             if (!Utils.isStripEmpty(value)) {
    273                                 ds.addChangeSetTag(tagKey, value);
    274                             } else {
    275                                 ds.addChangeSetTag(tagKey, null);
    276                             }
    277                         }
    278                     }
    279                 }
     296                final DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     297                final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search);
     298                ds.setSelected(filteredPrimitives);
     299                forTagAdd.addAll(filteredPrimitives);
     300                zoom(filteredPrimitives, bbox);
    280301            });
    281         }
    282 
    283         // add tags to objects
    284         if (args.containsKey("addtags")) {
     302        } catch (SearchParseError ex) {
     303            Logging.error(ex);
     304            throw new RequestHandlerErrorException(ex);
     305        }
     306    }
     307
     308    private void addChangesetTags() {
     309        List<String> values = Stream.of(CHANGESET_COMMENT, CHANGESET_SOURCE, CHANGESET_HASHTAGS)
     310                .filter(args::containsKey).collect(Collectors.toList());
     311        if (values.isEmpty()) {
     312            return;
     313        }
     314        MainApplication.worker.submit(() -> {
     315            DataSet ds = MainApplication.getLayerManager().getEditDataSet();
     316            if (ds != null) {
     317                for (String tag : values) {
     318                    final String tagKey = tag.substring("changeset_".length());
     319                    final String value = args.get(tag);
     320                    if (!Utils.isStripEmpty(value)) {
     321                        ds.addChangeSetTag(tagKey, value);
     322                    } else {
     323                        ds.addChangeSetTag(tagKey, null);
     324                    }
     325                }
     326            }
     327        });
     328    }
     329
     330    private void addTags(Collection<OsmPrimitive> forTagAdd) {
     331        if (args.containsKey(ADDTAGS)) {
    285332            // needs to run in EDT since forTagAdd is updated in EDT as well
    286333            GuiHelper.executeByMainWorkerInEDT(() -> {
     
    290337                    new Notification(isKeepingCurrentSelection
    291338                            ? tr("You clicked on a JOSM remotecontrol link that would apply tags onto selected objects.\n"
    292                                     + "Since no objects have been selected before this click, no tags were added.\n"
    293                                     + "Select one or more objects and click the link again.")
     339                            + "Since no objects have been selected before this click, no tags were added.\n"
     340                            + "Select one or more objects and click the link again.")
    294341                            : tr("You clicked on a JOSM remotecontrol link that would apply tags onto objects.\n"
    295                                     + "Unfortunately that link seems to be broken.\n"
    296                                     + "Technical explanation: the URL query parameter ''select='' or ''search='' has an invalid value.\n"
    297                                     + "Ask someone at the origin of the clicked link to fix this.")
    298                         ).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_LONG).show();
     342                            + "Unfortunately that link seems to be broken.\n"
     343                            + "Technical explanation: the URL query parameter ''select='' or ''search='' has an invalid value.\n"
     344                            + "Ask someone at the origin of the clicked link to fix this.")
     345                    ).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_LONG).show();
    299346                }
    300347            });
     
    303350
    304351    static void parseChangesetTags(Map<String, String> args) {
    305         if (args.containsKey("changeset_tags")) {
     352        if (args.containsKey(CHANGESET_TAGS)) {
    306353            MainApplication.worker.submit(() -> {
    307354                DataSet ds = MainApplication.getLayerManager().getEditDataSet();
    308355                if (ds != null) {
    309                     AddTagsDialog.parseUrlTagsToKeyValues(args.get("changeset_tags")).forEach(ds::addChangeSetTag);
     356                    AddTagsDialog.parseUrlTagsToKeyValues(args.get(CHANGESET_TAGS)).forEach(ds::addChangeSetTag);
    310357                }
    311358            });
     
    366413
    367414        // Process optional argument 'select'
    368         if (args != null && args.containsKey("select")) {
     415        validateSelect();
     416    }
     417
     418    private void validateSelect() {
     419        if (args != null && args.containsKey(SELECT)) {
    369420            toSelect.clear();
    370             for (String item : args.get("select").split(",", -1)) {
     421            for (String item : args.get(SELECT).split(",", -1)) {
    371422                if (!item.isEmpty()) {
    372423                    if (CURRENT_SELECTION.equalsIgnoreCase(item)) {
Note: See TracChangeset for help on using the changeset viewer.