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


Ignore:
Timestamp:
2020-05-16T00:08:03+02:00 (4 years ago)
Author:
simon04
Message:

fix #19099 - PlaceSelection: search for more results (Nominatim)

After the initial search, the button changes to "Search more..."

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

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/download/PlaceSelection.java

    r16418 r16419  
    1616import java.text.DecimalFormat;
    1717import java.util.ArrayList;
     18import java.util.Collection;
    1819import java.util.Collections;
    1920import java.util.List;
     21import java.util.Objects;
    2022import java.util.StringTokenizer;
     23import java.util.function.BiFunction;
     24import java.util.function.Consumer;
    2125
    2226import javax.swing.AbstractAction;
     
    5761import org.openstreetmap.josm.tools.ImageProvider;
    5862import org.openstreetmap.josm.tools.Logging;
    59 import org.openstreetmap.josm.tools.Utils;
    6063import org.xml.sax.SAXException;
    6164import org.xml.sax.SAXParseException;
     
    7477    private DownloadDialog parent;
    7578    private static final Server[] SERVERS = {
    76         new Server("Nominatim", NameFinder.NOMINATIM_URL, tr("Class Type"), tr("Bounds"))
     79        new Server("Nominatim", NameFinder::buildNominatimURL, tr("Class Type"), tr("Bounds"))
    7780    };
    78     private final JosmComboBox<Server> server = new JosmComboBox<>(SERVERS);
     81    private final JosmComboBox<Server> serverComboBox = new JosmComboBox<>(SERVERS);
    7982
    8083    private static class Server {
    8184        public final String name;
    82         public final String url;
     85        public final BiFunction<String, Collection<SearchResult>, URL> urlFunction;
    8386        public final String thirdcol;
    8487        public final String fourthcol;
    8588
    86         Server(String n, String u, String t, String f) {
     89        Server(String n, BiFunction<String, Collection<SearchResult>, URL> u, String t, String f) {
    8790            name = n;
    88             url = u;
     91            urlFunction = u;
    8992            thirdcol = t;
    9093            fourthcol = f;
     
    102105
    103106        lpanel.add(new JLabel(tr("Choose the server for searching:")), GBC.std(0, 0).weight(0, 0).insets(0, 0, 5, 0));
    104         lpanel.add(server, GBC.std(1, 0).fill(GBC.HORIZONTAL));
     107        lpanel.add(serverComboBox, GBC.std(1, 0).fill(GBC.HORIZONTAL));
    105108        String s = Config.getPref().get("namefinder.server", SERVERS[0].name);
    106109        for (int i = 0; i < SERVERS.length; ++i) {
    107110            if (SERVERS[i].name.equals(s)) {
    108                 server.setSelectedIndex(i);
     111                serverComboBox.setSelectedIndex(i);
    109112            }
    110113        }
     
    171174    }
    172175
     176    /**
     177     * Action to perform initial search, and (if query is unchanged) load more results.
     178     */
    173179    class SearchAction extends AbstractAction implements DocumentListener {
    174180
     181        String lastSearchExpression;
     182        boolean isSearchMore;
     183
    175184        SearchAction() {
    176             putValue(NAME, tr("Search..."));
    177185            new ImageProvider("dialogs", "search").getResource().attachImageIcon(this, true);
    178             putValue(SHORT_DESCRIPTION, tr("Click to start searching for places"));
    179             updateEnabledState();
     186            updateState();
    180187        }
    181188
    182189        @Override
    183190        public void actionPerformed(ActionEvent e) {
    184             if (!isEnabled() || cbSearchExpression.getText().trim().isEmpty())
     191            String searchExpression = cbSearchExpression.getText();
     192            if (!isEnabled() || searchExpression.trim().isEmpty())
    185193                return;
    186194            cbSearchExpression.addCurrentItemToHistory();
    187195            Config.getPref().putList(HISTORY_KEY, cbSearchExpression.getHistory());
    188             NameQueryTask task = new NameQueryTask(cbSearchExpression.getText());
     196            Server server = (Server) serverComboBox.getSelectedItem();
     197            URL url = server.urlFunction.apply(searchExpression, isSearchMore ? model.getData() : Collections.emptyList());
     198            NameQueryTask task = new NameQueryTask(url, data -> {
     199                if (isSearchMore) {
     200                    model.addData(data);
     201                } else {
     202                    model.setData(data);
     203                }
     204                Config.getPref().put("namefinder.server", server.name);
     205                columnmodel.setHeadlines(server.thirdcol, server.fourthcol);
     206                lastSearchExpression = searchExpression;
     207                updateState();
     208            });
    189209            MainApplication.worker.submit(task);
    190210        }
    191211
    192         protected final void updateEnabledState() {
    193             setEnabled(!cbSearchExpression.getText().trim().isEmpty());
     212        protected final void updateState() {
     213            String searchExpression = cbSearchExpression.getText();
     214            setEnabled(!searchExpression.trim().isEmpty());
     215            isSearchMore = Objects.equals(lastSearchExpression, searchExpression) && !model.getData().isEmpty();
     216            if (isSearchMore) {
     217                putValue(NAME, tr("Search more..."));
     218                putValue(SHORT_DESCRIPTION, tr("Click to search for more places"));
     219            } else {
     220                putValue(NAME, tr("Search..."));
     221                putValue(SHORT_DESCRIPTION, tr("Click to start searching for places"));
     222            }
    194223        }
    195224
    196225        @Override
    197226        public void changedUpdate(DocumentEvent e) {
    198             updateEnabledState();
     227            updateState();
    199228        }
    200229
    201230        @Override
    202231        public void insertUpdate(DocumentEvent e) {
    203             updateEnabledState();
     232            updateState();
    204233        }
    205234
    206235        @Override
    207236        public void removeUpdate(DocumentEvent e) {
    208             updateEnabledState();
    209         }
    210     }
    211 
    212     class NameQueryTask extends PleaseWaitRunnable {
    213 
    214         private final String searchExpression;
     237            updateState();
     238        }
     239    }
     240
     241    static class NameQueryTask extends PleaseWaitRunnable {
     242
     243        private final URL url;
     244        private final Consumer<List<SearchResult>> dataConsumer;
    215245        private HttpClient connection;
    216246        private List<SearchResult> data;
    217247        private boolean canceled;
    218         private final Server useserver;
    219248        private Exception lastException;
    220249
    221         NameQueryTask(String searchExpression) {
     250        NameQueryTask(URL url, Consumer<List<SearchResult>> dataConsumer) {
    222251            super(tr("Querying name server"), false /* don't ignore exceptions */);
    223             this.searchExpression = searchExpression;
    224             useserver = (Server) server.getSelectedItem();
    225             Config.getPref().put("namefinder.server", useserver.name);
     252            this.url = url;
     253            this.dataConsumer = dataConsumer;
    226254        }
    227255
     
    244272                return;
    245273            }
    246             columnmodel.setHeadlines(useserver.thirdcol, useserver.fourthcol);
    247             model.setData(this.data);
     274            dataConsumer.accept(data);
    248275        }
    249276
    250277        @Override
    251278        protected void realRun() throws SAXException, IOException, OsmTransferException {
    252             String urlString = useserver.url+Utils.encodeUrl(searchExpression);
    253 
    254279            try {
    255280                getProgressMonitor().indeterminateSubTask(tr("Querying name server ..."));
    256                 URL url = new URL(urlString);
    257281                synchronized (this) {
    258282                    connection = HttpClient.create(url);
     
    265289                if (!canceled) {
    266290                    // Nominatim sometimes returns garbage, see #5934, #10643
    267                     Logging.log(Logging.LEVEL_WARN, tr("Error occurred with query ''{0}'': ''{1}''", urlString, e.getMessage()), e);
     291                    Logging.log(Logging.LEVEL_WARN, tr("Error occurred with query ''{0}'': ''{1}''", url, e.getMessage()), e);
    268292                    GuiHelper.runInEDTAndWait(() -> HelpAwareOptionPane.showOptionDialog(
    269293                            MainApplication.getMainFrame(),
     
    276300                if (!canceled) {
    277301                    OsmTransferException ex = new OsmTransferException(e);
    278                     ex.setUrl(urlString);
     302                    ex.setUrl(url.toString());
    279303                    lastException = ex;
    280304                }
     
    309333            }
    310334            fireTableDataChanged();
     335        }
     336
     337        public void addData(List<SearchResult> data) {
     338            this.data.addAll(data);
     339            fireTableDataChanged();
     340        }
     341
     342        public List<SearchResult> getData() {
     343            return Collections.unmodifiableList(data);
    311344        }
    312345
  • trunk/src/org/openstreetmap/josm/io/NameFinder.java

    r15969 r16419  
    66import java.io.IOException;
    77import java.io.Reader;
     8import java.io.UncheckedIOException;
     9import java.net.MalformedURLException;
    810import java.net.URL;
     11import java.util.Collection;
    912import java.util.Collections;
    1013import java.util.LinkedList;
    1114import java.util.List;
     15import java.util.Optional;
     16import java.util.stream.Collectors;
    1217
    1318import javax.xml.parsers.ParserConfigurationException;
     
    5156
    5257    /**
     58     * Builds the Nominatim URL for performing the given search
     59     * @param searchExpression the Nominatim query
     60     * @return the Nominatim URL
     61     */
     62    public static URL buildNominatimURL(String searchExpression) {
     63        return buildNominatimURL(searchExpression, Collections.emptyList());
     64    }
     65
     66    /**
     67     * Builds the Nominatim URL for performing the given search and excluding the results (of a previous search)
     68     * @param searchExpression the Nominatim query
     69     * @param excludeResults the results to exclude
     70     * @return the Nominatim URL
     71     * @see <a href="https://nominatim.org/release-docs/develop/api/Search/#result-limitation">Result limitation in Nominatim Documentation</a>
     72     */
     73    public static URL buildNominatimURL(String searchExpression, Collection<SearchResult> excludeResults) {
     74        try {
     75            final String excludeString = excludeResults.isEmpty()
     76                    ? ""
     77                    : excludeResults.stream()
     78                    .map(SearchResult::getPlaceId)
     79                    .map(String::valueOf)
     80                    .collect(Collectors.joining(",", "&exclude_place_ids=", ""));
     81            return new URL(NOMINATIM_URL_PROP.get() + Utils.encodeUrl(searchExpression) + excludeString);
     82        } catch (MalformedURLException ex) {
     83            throw new UncheckedIOException(ex);
     84        }
     85    }
     86
     87    /**
    5388     * Performs a Nominatim search.
    5489     * @param searchExpression Nominatim search expression
     
    5792     */
    5893    public static List<SearchResult> queryNominatim(final String searchExpression) throws IOException {
    59         return query(new URL(NOMINATIM_URL_PROP.get() + Utils.encodeUrl(searchExpression)));
     94        return query(buildNominatimURL(searchExpression));
    6095    }
    6196
     
    108143        private Bounds bounds;
    109144        private PrimitiveId osmId;
     145        private long placeId;
    110146
    111147        /**
     
    179215        public final PrimitiveId getOsmId() {
    180216            return osmId;
     217        }
     218
     219        /**
     220         * Returns the Nominatim place id.
     221         * @return the Nominatim place id
     222         */
     223        public long getPlaceId() {
     224            return placeId;
    181225        }
    182226
     
    249293                        currentResult.osmId = new SimplePrimitiveId(Long.parseLong(osmId), OsmPrimitiveType.from(osmType));
    250294                    }
     295                    currentResult.placeId = Optional.ofNullable(atts.getValue("place_id")).filter(s -> !s.isEmpty())
     296                            .map(Long::parseLong).orElse(0L);
    251297                    data.add(currentResult);
    252298                }
Note: See TracChangeset for help on using the changeset viewer.