367 lines
10 KiB
Java
367 lines
10 KiB
Java
/*
|
|
* Copyright 2013 Hannes Janetzek
|
|
*
|
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.oscim.gdx.client;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.oscim.core.BoundingBox;
|
|
import org.oscim.core.GeometryBuffer;
|
|
import org.oscim.core.MapPosition;
|
|
import org.oscim.layers.PathLayer;
|
|
import org.oscim.map.Map;
|
|
|
|
import com.google.gwt.cell.client.AbstractCell;
|
|
import com.google.gwt.core.client.JavaScriptObject;
|
|
import com.google.gwt.core.client.JsArray;
|
|
import com.google.gwt.core.client.JsArrayNumber;
|
|
import com.google.gwt.dom.client.Style.Visibility;
|
|
import com.google.gwt.event.dom.client.ClickEvent;
|
|
import com.google.gwt.event.dom.client.ClickHandler;
|
|
import com.google.gwt.event.dom.client.FocusEvent;
|
|
import com.google.gwt.event.dom.client.FocusHandler;
|
|
import com.google.gwt.event.dom.client.KeyCodes;
|
|
import com.google.gwt.event.dom.client.KeyUpEvent;
|
|
import com.google.gwt.event.dom.client.KeyUpHandler;
|
|
import com.google.gwt.http.client.URL;
|
|
import com.google.gwt.jsonp.client.JsonpRequestBuilder;
|
|
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
|
import com.google.gwt.user.cellview.client.CellList;
|
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
|
import com.google.gwt.user.client.ui.Button;
|
|
import com.google.gwt.user.client.ui.RootPanel;
|
|
import com.google.gwt.user.client.ui.ScrollPanel;
|
|
import com.google.gwt.user.client.ui.TextBox;
|
|
import com.google.gwt.view.client.ProvidesKey;
|
|
import com.google.gwt.view.client.SelectionChangeEvent;
|
|
import com.google.gwt.view.client.SingleSelectionModel;
|
|
|
|
/**
|
|
* Entry point classes define <code>onModuleLoad()</code>.
|
|
*/
|
|
public class SearchBox {
|
|
|
|
protected static final Logger log = LoggerFactory.getLogger(SearchBox.class);
|
|
|
|
private static final String NOMINATIM_GLOBAL = "http://nominatim.openstreetmap.org/search?polygon_text=1&addressdetails=0&format=json&limit=25&q=";
|
|
|
|
interface PoiData {
|
|
public static final ProvidesKey<PoiData> KEY_PROVIDER = new ProvidesKey<PoiData>() {
|
|
@Override
|
|
public Object getKey(PoiData item) {
|
|
return item == null ? null : item.getId();
|
|
}
|
|
};
|
|
|
|
String getId();
|
|
|
|
String getName();
|
|
|
|
double getLatitude();
|
|
|
|
double getLongitude();
|
|
|
|
String getIcon();
|
|
|
|
BoundingBox getBoundingBox();
|
|
}
|
|
|
|
final static class NominatimData extends JavaScriptObject implements
|
|
PoiData {
|
|
|
|
protected NominatimData() {
|
|
}
|
|
|
|
final static class BBox extends JsArrayNumber {
|
|
protected BBox() {
|
|
}
|
|
}
|
|
|
|
final static class Polygon extends JsArray<JsArrayNumber> {
|
|
protected Polygon() {
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
public final native String getId()
|
|
/*-{
|
|
return this.osm_id;
|
|
}-*/;
|
|
|
|
public final native String name() /*-{
|
|
return this.display_name;
|
|
}-*/;
|
|
|
|
public final native BBox getBBox() /*-{
|
|
return this.boundingbox
|
|
}-*/;
|
|
|
|
public final native String getWkt() /*-{
|
|
return this.geotext;
|
|
}-*/;
|
|
|
|
private final native String latitude() /*-{
|
|
return this.lat;
|
|
}-*/;
|
|
|
|
private final native String longitude() /*-{
|
|
return this.lon;
|
|
}-*/;
|
|
|
|
public final native String getIcon() /*-{
|
|
return this.icon;
|
|
}-*/;
|
|
|
|
@Override
|
|
public double getLatitude() {
|
|
try {
|
|
return Double.parseDouble(latitude());
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public double getLongitude() {
|
|
try {
|
|
return Double.parseDouble(longitude());
|
|
} catch (Exception e) {
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public BoundingBox getBoundingBox() {
|
|
if (getBBox() != null) {
|
|
BBox b = getBBox();
|
|
return new BoundingBox(b.get(0), b.get(2), b.get(1), b.get(3));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
String[] n = name().split(", ");
|
|
if (n != null && n.length > 2)
|
|
return n[0] + ", " + n[1] + " " + n[2];
|
|
else if (n != null && n.length > 1)
|
|
return n[0] + ", " + n[1];
|
|
|
|
return name();
|
|
}
|
|
}
|
|
|
|
class PoiCell extends AbstractCell<PoiData> {
|
|
|
|
@Override
|
|
public void render(com.google.gwt.cell.client.Cell.Context context,
|
|
PoiData value, SafeHtmlBuilder sb) {
|
|
|
|
// Value can be null, so do a null check..
|
|
if (value == null) {
|
|
return;
|
|
}
|
|
|
|
sb.appendHtmlConstant("<table>");
|
|
|
|
if (value.getIcon() != null) {
|
|
// Add the contact image.
|
|
sb.appendHtmlConstant("<tr><td rowspan='3'>");
|
|
sb.appendHtmlConstant("<img border=0 src=" + value.getIcon() + ">");
|
|
sb.appendHtmlConstant("</td>");
|
|
}
|
|
|
|
// Add the name and address.
|
|
sb.appendHtmlConstant("<td style='font-size:95%;'>");
|
|
sb.appendEscaped(value.getName());
|
|
sb.appendHtmlConstant("</td></tr>");
|
|
//sb.appendEscaped("<tr><td>" + value.getId()+ "</td></tr>");
|
|
sb.appendHtmlConstant("</table>");
|
|
sb.appendHtmlConstant("<hline>");
|
|
}
|
|
}
|
|
|
|
public SearchBox(final Map map) {
|
|
final Button searchButton = new Button("Search");
|
|
final TextBox searchField = new TextBox();
|
|
//searchField.setText("Bremen");
|
|
final PathLayer mOverlay = new PathLayer(map, 0xCC0000FF);
|
|
map.getLayers().add(mOverlay);
|
|
|
|
// We can add style names to widgets
|
|
searchButton.addStyleName("sendButton");
|
|
|
|
RootPanel.get("nameFieldContainer").add(searchField);
|
|
RootPanel.get("sendButtonContainer").add(searchButton);
|
|
|
|
// Focus the cursor on the name field when the app loads
|
|
searchField.setFocus(true);
|
|
searchField.selectAll();
|
|
|
|
// Create a cell to render each value in the list.
|
|
PoiCell poiCell = new PoiCell();
|
|
|
|
// Create a CellList that uses the cell.
|
|
final CellList<PoiData> cellList = new CellList<PoiData>(poiCell,
|
|
PoiData.KEY_PROVIDER);
|
|
|
|
final SingleSelectionModel<PoiData> selectionModel = new SingleSelectionModel<PoiData>(
|
|
PoiData.KEY_PROVIDER);
|
|
cellList.setSelectionModel(selectionModel);
|
|
|
|
final ScrollPanel scroller = new ScrollPanel(cellList);
|
|
RootPanel.get("listContainer").add(scroller);
|
|
|
|
scroller.setSize("350px", "300px");
|
|
|
|
RootPanel.get("search").getElement().getStyle().setVisibility(Visibility.VISIBLE);
|
|
scroller.setVisible(false);
|
|
|
|
searchField.addFocusHandler(new FocusHandler() {
|
|
@Override
|
|
public void onFocus(FocusEvent event) {
|
|
scroller.setVisible(true);
|
|
}
|
|
});
|
|
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
|
public void onSelectionChange(SelectionChangeEvent event) {
|
|
final PoiData d = selectionModel.getSelectedObject();
|
|
|
|
mOverlay.clearPath();
|
|
|
|
//log.debug("selected " + d.getName() + " " + d.getLatitude() + " "
|
|
// + d.getLongitude());
|
|
|
|
BoundingBox b = d.getBoundingBox();
|
|
if (b != null) {
|
|
if (b.maxLatitudeE6 - b.minLatitudeE6 < 100 &&
|
|
b.maxLongitudeE6 - b.minLongitudeE6 < 100)
|
|
// for small bbox use zoom=16 to get an overview
|
|
map.getAnimator().animateTo(500, b.getCenterPoint(), 1 << 16, false);
|
|
else
|
|
map.getAnimator().animateTo(b);
|
|
if (d instanceof NominatimData && ((NominatimData) d).getWkt() != null) {
|
|
String wkt = ((NominatimData) d).getWkt();
|
|
|
|
WKTReader r = new WKTReader();
|
|
GeometryBuffer g = new GeometryBuffer(1024, 10);
|
|
try {
|
|
r.parse(wkt, g);
|
|
} catch (Exception e) {
|
|
log.debug(wkt);
|
|
}
|
|
mOverlay.setGeom(g);
|
|
|
|
//log.debug("add polygon " + p.length());
|
|
} else {
|
|
mOverlay.addPoint(b.maxLatitudeE6, b.minLongitudeE6);
|
|
mOverlay.addPoint(b.maxLatitudeE6, b.maxLongitudeE6);
|
|
mOverlay.addPoint(b.minLatitudeE6, b.maxLongitudeE6);
|
|
mOverlay.addPoint(b.minLatitudeE6, b.minLongitudeE6);
|
|
mOverlay.addPoint(b.maxLatitudeE6, b.minLongitudeE6);
|
|
}
|
|
// hide overlay after 5 seconds
|
|
map.postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
mOverlay.clearPath();
|
|
}
|
|
}, 5000);
|
|
} else {
|
|
MapPosition pos = new MapPosition();
|
|
|
|
map.getViewport().setTilt(0);
|
|
map.getViewport().setRotation(0);
|
|
|
|
pos.setZoomLevel(13);
|
|
pos.setPosition(d.getLatitude(), d.getLongitude());
|
|
map.setMapPosition(pos);
|
|
}
|
|
|
|
scroller.setVisible(false);
|
|
}
|
|
|
|
});
|
|
|
|
// Create a handler for the sendButton and nameField
|
|
class MyHandler implements ClickHandler, KeyUpHandler {
|
|
|
|
/**
|
|
* Fired when the user clicks on the sendButton.
|
|
*/
|
|
public void onClick(ClickEvent event) {
|
|
sendRequest();
|
|
}
|
|
|
|
/**
|
|
* Fired when the user types in the nameField.
|
|
*/
|
|
public void onKeyUp(KeyUpEvent event) {
|
|
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
|
|
sendRequest();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send the name from the nameField to the server and wait for a
|
|
* response.
|
|
*/
|
|
private void sendRequest() {
|
|
String textToServer = searchField.getText();
|
|
searchButton.setEnabled(false);
|
|
|
|
String url = URL
|
|
.encode(NOMINATIM_GLOBAL
|
|
+ textToServer);
|
|
|
|
JsonpRequestBuilder builder = new JsonpRequestBuilder();
|
|
builder.setCallbackParam("json_callback");
|
|
builder.requestObject(url, new AsyncCallback<JsArray<NominatimData>>() {
|
|
public void onFailure(Throwable caught) {
|
|
log.debug("request failed");
|
|
searchButton.setEnabled(true);
|
|
}
|
|
|
|
public void onSuccess(JsArray<NominatimData> data) {
|
|
List<PoiData> items = new ArrayList<PoiData>();
|
|
for (int i = 0, n = data.length(); i < n; i++) {
|
|
NominatimData d = data.get(i);
|
|
items.add(d);
|
|
}
|
|
|
|
cellList.setRowCount(items.size(), true);
|
|
cellList.setRowData(0, items);
|
|
scroller.setVisible(true);
|
|
searchButton.setEnabled(true);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Add a handler to send the name to the server
|
|
MyHandler handler = new MyHandler();
|
|
searchButton.addClickHandler(handler);
|
|
searchField.addKeyUpHandler(handler);
|
|
|
|
}
|
|
|
|
}
|