/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2010-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.features.poller.remote.gwt.client;
import java.util.HashMap;
import java.util.Map;
import org.gwtopenmaps.openlayers.client.Bounds;
import org.gwtopenmaps.openlayers.client.Icon;
import org.gwtopenmaps.openlayers.client.LonLat;
import org.gwtopenmaps.openlayers.client.MapOptions;
import org.gwtopenmaps.openlayers.client.MapWidget;
import org.gwtopenmaps.openlayers.client.Marker;
import org.gwtopenmaps.openlayers.client.Pixel;
import org.gwtopenmaps.openlayers.client.Projection;
import org.gwtopenmaps.openlayers.client.Size;
import org.gwtopenmaps.openlayers.client.control.MousePosition;
import org.gwtopenmaps.openlayers.client.control.PanZoomBar;
import org.gwtopenmaps.openlayers.client.event.MapMoveListener;
import org.gwtopenmaps.openlayers.client.event.MapZoomListener;
import org.gwtopenmaps.openlayers.client.event.MarkerBrowserEventListener;
import org.gwtopenmaps.openlayers.client.layer.Markers;
import org.gwtopenmaps.openlayers.client.layer.XYZ;
import org.gwtopenmaps.openlayers.client.layer.XYZOptions;
import org.gwtopenmaps.openlayers.client.popup.Popup;
import org.opennms.features.poller.remote.gwt.client.events.GWTMarkerClickedEvent;
import org.opennms.features.poller.remote.gwt.client.events.MapPanelBoundsChangedEvent;
import org.opennms.features.poller.remote.gwt.client.utils.BoundsBuilder;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* <p>OpenLayersMapPanel class.</p>
*
* @author ranger
* @version $Id: $
* @since 1.8.1
*/
public class OpenLayersMapPanel extends Composite implements MapPanel {
private class DefaultMarkerClickHandler implements MarkerBrowserEventListener {
private GWTMarkerState m_markerState;
public DefaultMarkerClickHandler(GWTMarkerState markerState) {
setMarkerState(markerState);
}
public void setMarkerState(GWTMarkerState markerState) {
m_markerState = markerState;
}
public GWTMarkerState getMarkerState() {
return m_markerState;
}
public void onBrowserEvent(final MarkerBrowserEvent markerBrowserEvent) {
m_eventBus.fireEvent(new GWTMarkerClickedEvent(getMarkerState()));
}
}
interface OpenLayersMapPanelUiBinder extends UiBinder<Widget, OpenLayersMapPanel> {}
private static OpenLayersMapPanelUiBinder uiBinder = GWT.create(OpenLayersMapPanelUiBinder.class);
@UiField
SimplePanel m_mapHolder;
private MapWidget m_mapWidget;
private org.gwtopenmaps.openlayers.client.Map m_map;
private Markers m_markersLayer;
private Map<String, Marker> m_markers = new HashMap<String, Marker>();
private HandlerManager m_eventBus;
private static final Projection PROJECTION_SPHERICAL_MERCATOR = new Projection("EPSG:900913");
private static final Projection PROJECTION_LAT_LON = new Projection("EPSG:4326");
/**
* <p>Constructor for OpenLayersMapPanel.</p>
*
* @param eventBus a {@link com.google.gwt.event.shared.HandlerManager} object.
*/
public OpenLayersMapPanel(final HandlerManager eventBus) {
m_eventBus = eventBus;
initWidget(uiBinder.createAndBindUi(this));
initializeMap();
m_map.addMapMoveListener(new MapMoveListener() {
public void onMapMove(final MapMoveEvent eventObject) {
m_eventBus.fireEvent(new MapPanelBoundsChangedEvent(getBounds()));
}
});
m_map.addMapZoomListener(new MapZoomListener() {
public void onMapZoom(final MapZoomEvent eventObject) {
m_eventBus.fireEvent(new MapPanelBoundsChangedEvent(getBounds()));
}
});
}
/** {@inheritDoc} */
@Override
protected void onLoad() {
super.onLoad();
syncMapSizeWithParent();
}
/**
* <p>initializeMap</p>
*/
private void initializeMap() {
final MapOptions mo = new MapOptions();
mo.setProjection(PROJECTION_SPHERICAL_MERCATOR.getProjectionCode());
mo.setDisplayProjection(PROJECTION_LAT_LON);
mo.setMaxExtent(new Bounds(-180, -90, 180, 90).transform(PROJECTION_LAT_LON,PROJECTION_SPHERICAL_MERCATOR));
m_mapWidget = new MapWidget("100%", "100%", mo);
m_mapHolder.add(m_mapWidget);
m_map = m_mapWidget.getMap();
m_map.addControl(new PanZoomBar());
m_map.addControl(new MousePosition());
m_map.zoomTo(2);
initializeImageError();
XYZOptions xyzOptions = new XYZOptions();
xyzOptions.setSphericalMercator(true);
xyzOptions.setAttribution("Default tiles courtesy of <a href=\"http://open.mapquest.co.uk/\">MapQuest</a>");
XYZ x = new XYZ("OpenStreetMap", getLayerUrl(), xyzOptions);
x.setIsBaseLayer(true);
x.setIsVisible(true);
m_map.addLayer(x);
m_markersLayer = new Markers("Remote Pollers");
m_markersLayer.setIsVisible(true);
m_markersLayer.setIsBaseLayer(false);
m_map.addLayer(m_markersLayer);
/*
final LayerSwitcher switcher = new LayerSwitcher();
m_map.addControl(switcher);
*/
m_map.zoomToMaxExtent();
Window.addResizeHandler(new ResizeHandler() {
public void onResize(ResizeEvent event) {
syncMapSizeWithParent();
}
});
}
private static native void initializeImageError() /*-{
$wnd.OpenLayers.Util.onImageLoadError = function() {
this.style.display = "";
this.src = "images/nodata.png";
};
}-*/;
/** {@inheritDoc} */
public void showLocationDetails(String name, String htmlTitle, String htmlContent) {
final Marker marker = getMarker(name);
m_map.setCenter(marker.getLonLat());
if (marker != null) {
final VerticalPanel panel = new VerticalPanel();
panel.add(new Label(htmlTitle));
panel.add(new HTML(htmlContent));
Popup p = new Popup(name, marker.getLonLat(), new Size(300, 300), panel.toString(), true);
// p.setAutoSize(true);
p.getJSObject().setProperty("autoSize", true);
m_map.addPopupExclusive(p);
}
}
private Marker createMarker(final GWTMarkerState marker) {
final LonLat lonLat = toLonLat(marker.getLatLng());
final Icon icon = createIcon(marker);
final Marker m = new Marker(lonLat, icon);
m.addBrowserEventListener("click", new DefaultMarkerClickHandler(marker));
return m;
}
private Icon createIcon(final GWTMarkerState marker) {
return new Icon(marker.getImageURL(), new Size(32, 32), new Pixel(-16, -32));
}
/**
* <p>getBounds</p>
*
* @return a {@link org.opennms.features.poller.remote.gwt.client.GWTBounds} object.
*/
public GWTBounds getBounds() {
try {
return toGWTBounds(m_map.getExtent());
} catch (final Exception e) {
return new GWTBounds(-180, -90, 180, 90);
}
}
/** {@inheritDoc} */
public void setBounds(final GWTBounds b) {
m_map.zoomToExtent(toBounds(b));
}
private static LonLat toLonLat(final GWTLatLng latLng) {
final LonLat ll = new LonLat(latLng.getLongitude(), latLng.getLatitude());
ll.transform(PROJECTION_LAT_LON.getProjectionCode(), PROJECTION_SPHERICAL_MERCATOR.getProjectionCode());
return ll;
}
private static GWTBounds toGWTBounds(final Bounds fromBounds) {
if (fromBounds == null) {
return new GWTBounds(-180, -90, 180, 90);
}
final Bounds bounds = fromBounds.transform(PROJECTION_SPHERICAL_MERCATOR, PROJECTION_LAT_LON);
BoundsBuilder bldr = new BoundsBuilder();
bldr.extend(Math.max(-90, bounds.getLowerLeftY()), Math.max(-180, bounds.getLowerLeftX()));
bldr.extend(Math.min(90, bounds.getUpperRightY()), Math.min(180, bounds.getUpperRightX()));
return bldr.getBounds();
}
private static Bounds toBounds(final GWTBounds bounds) {
Bounds b = null;
if (bounds == null) {
b = new Bounds(-180, -90, 180, 90);
}
final GWTLatLng nec = bounds.getNorthEastCorner();
final GWTLatLng swc = bounds.getSouthWestCorner();
b = new Bounds(swc.getLongitude(), swc.getLatitude(), nec.getLongitude(), nec.getLatitude());
return b.transform(PROJECTION_LAT_LON, PROJECTION_SPHERICAL_MERCATOR);
}
private void syncMapSizeWithParent() {
m_map.updateSize();
}
/** {@inheritDoc} */
public void placeMarker(final GWTMarkerState marker) {
Marker m = getMarker(marker.getName());
if(m == null) {
m = createMarker(marker);
m_markers.put(marker.getName(), m);
}
updateMarker(m, marker);
}
private void updateMarker(final Marker m, final GWTMarkerState marker) {
if (marker.isVisible()) {
m.setImageUrl(marker.getImageURL());
m_markersLayer.addMarker(m);
} else {
m_markersLayer.removeMarker(m);
}
}
private Marker getMarker(final String name) {
return m_markers.get(name);
}
private native String getLayerUrl() /*-{
return $wnd.openlayersUrl;
}-*/;
/**
* <p>getWidget</p>
*
* @return a {@link com.google.gwt.user.client.ui.Widget} object.
*/
public Widget getWidget() {
return this;
}
/** {@inheritDoc} */
public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
return addDomHandler(handler, DoubleClickEvent.getType());
}
/** {@inheritDoc} */
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
}