com.ecom.web.components.gmap.GMap2.java Source code

Java tutorial

Introduction

Here is the source code for com.ecom.web.components.gmap.GMap2.java

Source

/*
 *
 * ==============================================================================
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.ecom.web.components.gmap;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.cycle.RequestCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecom.web.components.gmap.api.GControl;
import com.ecom.web.components.gmap.api.GEvent;
import com.ecom.web.components.gmap.api.GInfoWindow;
import com.ecom.web.components.gmap.api.GLatLng;
import com.ecom.web.components.gmap.api.GLatLngBounds;
import com.ecom.web.components.gmap.api.GMapType;
import com.ecom.web.components.gmap.api.GMarker;
import com.ecom.web.components.gmap.api.GOverlay;

/**
 * Wicket component to embed <a href="http://maps.google.com">Google Maps</a> into your pages.
 * <p>
 * The Google Maps API requires an API key to use it. You will need to generate one for each
 * deployment context you have. See the <a href="http://www.google.com/apis/maps/signup.html">Google
 * Maps API sign up page</a> for more information.
 */
public class GMap2 extends Panel implements GOverlayContainer {
    /** log. */
    private static final Logger log = LoggerFactory.getLogger(GMap2.class);

    private static final long serialVersionUID = 1L;

    private GLatLng center = new GLatLng(37.4419, -122.1419);

    private boolean googleBarEnabled = false;

    private boolean draggingEnabled = true;

    private boolean doubleClickZoomEnabled = false;

    private boolean scrollWheelZoomEnabled = false;

    private GMapType mapType = GMapType.G_NORMAL_MAP;

    private int zoom = 13;

    private final Set<GControl> controls = new HashSet<GControl>();

    private final List<GOverlay> overlays = new ArrayList<GOverlay>();

    private final WebMarkupContainer map;

    private final GInfoWindow infoWindow;

    private GLatLngBounds bounds;

    //private final OverlayListener overlayListener;

    /**
     * Construct.
     * 
     * @param id
     * @param headerContrib
     */
    public GMap2(final String id, final GMapHeaderContributor headerContrib) {
        super(id);

        add(headerContrib);

        infoWindow = new GInfoWindow();
        add(infoWindow);

        map = new WebMarkupContainer("map");
        map.setOutputMarkupId(true);
        add(map);
        //      overlayListener = new OverlayListener();
        //      add(overlayListener);
    }

    public GMap2(final String id) {
        super(id);

        infoWindow = new GInfoWindow();
        add(infoWindow);

        map = new WebMarkupContainer("map");
        map.setOutputMarkupId(true);
        add(map);

    }

    /**
     * @see org.apache.wicket.Component#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
     */
    @Override
    public void renderHead(IHeaderResponse response) {
        response.renderOnDomReadyJavaScript(getJSinit());
    }

    /**
     * @see org.apache.wicket.Component#onBeforeRender()
     */
    @Override
    protected void onBeforeRender() {

        RuntimeConfigurationType configurationType = Application.get().getConfigurationType();
        if (configurationType.equals(RuntimeConfigurationType.DEVELOPMENT)
                && !Application.get().getMarkupSettings().getStripWicketTags()) {
            log.warn("Application is in DEVELOPMENT mode && Wicket tags are not stripped,"
                    + " Firefox 3.0 will not render the GMap."
                    + " Change to DEPLOYMENT mode  || turn on Wicket tags stripping." + " See:"
                    + " http://www.nabble.com/Gmap2-problem-with-Firefox-3.0-to18137475.html.");
        }
        super.onBeforeRender();
    }

    /**
     * Add a control.
     * 
     * @param control
     *            control to add
     * @return This
     */
    public GMap2 addControl(GControl control) {
        controls.add(control);

        if (AjaxRequestTarget.get() != null && findPage() != null) {
            AjaxRequestTarget.get().appendJavaScript(control.getJSadd(GMap2.this));
        }

        return this;
    }

    /**
     * Remove a control.
     * 
     * @param control
     *            control to remove
     * @return This
     */
    public GMap2 removeControl(GControl control) {
        controls.remove(control);

        if (AjaxRequestTarget.get() != null && findPage() != null) {
            AjaxRequestTarget.get().appendJavaScript(control.getJSremove(GMap2.this));
        }

        return this;
    }

    /**
     * Add an overlay.
     * 
     * @param overlay
     *            overlay to add
     * @return This
     */
    public GMap2 addOverlay(GOverlay overlay) {
        overlays.add(overlay);
        overlay.setParent(this);

        if (AjaxRequestTarget.get() != null && findPage() != null) {
            AjaxRequestTarget.get().appendJavaScript(overlay.getJSadd());
        }

        return this;
    }

    /**
     * Remove an overlay.
     * 
     * @param overlay
     *            overlay to remove
     * @return This
     */
    public GMap2 removeOverlay(GOverlay overlay) {
        while (overlays.contains(overlay)) {
            overlays.remove(overlay);
        }

        if (AjaxRequestTarget.get() != null && findPage() != null) {
            AjaxRequestTarget.get().appendJavaScript(overlay.getJSremove());
        }

        overlay.setParent(null);

        return this;
    }

    /**
     * Clear all overlays.
     * 
     * @return This
     */
    public GMap2 removeAllOverlays() {
        for (GOverlay overlay : overlays) {
            overlay.setParent(null);
        }
        overlays.clear();
        if (AjaxRequestTarget.get() != null && findPage() != null) {
            AjaxRequestTarget.get().appendJavaScript(getJSinvoke("clearOverlays()"));
        }
        return this;
    }

    public List<GOverlay> getOverlays() {
        return Collections.unmodifiableList(overlays);
    }

    public Set<GControl> getControls() {
        return Collections.unmodifiableSet(controls);
    }

    public GLatLng getCenter() {
        return center;
    }

    public GLatLngBounds getBounds() {
        return bounds;
    }

    public void enableGoogleBar(boolean enabled) {
        if (googleBarEnabled != enabled) {
            googleBarEnabled = enabled;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetGoogleBarEnabled(enabled));
            }
        }
    }

    public void setDraggingEnabled(boolean enabled) {
        if (draggingEnabled != enabled) {
            draggingEnabled = enabled;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetDraggingEnabled(enabled));
            }
        }
    }

    public boolean isDraggingEnabled() {
        return draggingEnabled;
    }

    public void setDoubleClickZoomEnabled(boolean enabled) {
        if (doubleClickZoomEnabled != enabled) {
            doubleClickZoomEnabled = enabled;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetDoubleClickZoomEnabled(enabled));
            }
        }
    }

    public boolean isDoubleClickZoomEnabled() {
        return doubleClickZoomEnabled;
    }

    public void setScrollWheelZoomEnabled(boolean enabled) {
        if (scrollWheelZoomEnabled != enabled) {
            scrollWheelZoomEnabled = enabled;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetScrollWheelZoomEnabled(enabled));
            }
        }
    }

    public boolean isScrollWheelZoomEnabled() {
        return scrollWheelZoomEnabled;
    }

    public GMapType getMapType() {
        return mapType;
    }

    public void setMapType(GMapType mapType) {
        if (this.mapType != mapType) {
            this.mapType = mapType;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(mapType.getJSsetMapType(GMap2.this));
            }
        }
    }

    public int getZoom() {
        return zoom;
    }

    public void setZoom(int level) {
        if (zoom != level) {
            zoom = level;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetZoom(zoom));
            }
        }
    }

    /**
     * Set the center.
     * 
     * @param center
     *            center to set
     */
    public void setCenter(GLatLng center) {
        if (!this.center.equals(center)) {
            this.center = center;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSsetCenter(center));
            }
        }
    }

    /**
     * Changes the center point of the map to the given point. If the point is already visible in
     * the current map view, change the center in a smooth animation.
     * 
     * @param center
     *            the new center of the map
     */
    public void panTo(GLatLng center) {
        if (!this.center.equals(center)) {
            this.center = center;

            if (AjaxRequestTarget.get() != null && findPage() != null) {
                AjaxRequestTarget.get().appendJavaScript(getJSpanTo(center));
            }
        }
    }

    public GInfoWindow getInfoWindow() {
        return infoWindow;
    }

    /**
     * Generates the JavaScript used to instantiate this GMap2 as an JavaScript class on the client
     * side.
     * 
     * @return The generated JavaScript
     */
    private String getJSinit() {
        StringBuffer js = new StringBuffer("new WicketMap2('" + map.getMarkupId() + "');\n");

        //js.append(overlayListener.getJSinit());
        js.append(getJSsetCenter(getCenter()));
        js.append(getJSsetZoom(getZoom()));
        js.append(getJSsetDraggingEnabled(draggingEnabled));
        js.append(getJSsetDoubleClickZoomEnabled(doubleClickZoomEnabled));
        js.append(getJSsetScrollWheelZoomEnabled(scrollWheelZoomEnabled));
        js.append(getJSsetGoogleBarEnabled(googleBarEnabled));

        js.append(mapType.getJSsetMapType(this));

        // Add the controls.
        for (GControl control : controls) {
            js.append(control.getJSadd(this));
        }

        // Add the overlays.
        for (GOverlay overlay : overlays) {
            js.append(overlay.getJSadd());
        }

        js.append(infoWindow.getJSinit());

        //      for (Object behavior : getBehaviors(GEventListenerBehavior.class))
        //      {
        //         js.append(((GEventListenerBehavior)behavior).getJSaddListener());
        //      }

        return js.toString();
    }

    @Override
    protected boolean getStatelessHint() {
        return true;
    }

    /**
     * Convenience method for generating a JavaScript call on this GMap2 with the given invocation.
     * 
     * @param invocation
     *            The JavaScript call to invoke on this GMap2.
     * @return The generated JavaScript.
     */
    // TODO Could this become default or protected?
    public String getJSinvoke(String invocation) {
        return "Wicket.maps['" + map.getMarkupId() + "']." + invocation + ";\n";
    }

    /**
     * @see #fitMarkers(List, boolean, double)
     */
    public void fitMarkers(final List<GLatLng> markersToShow) {
        fitMarkers(markersToShow, false, 0.0);
    }

    /**
     * @see #fitMarkers(List, boolean, double)
     */
    public void fitMarkers(final List<GLatLng> markersToShow, boolean showMarkersForPoints) {
        fitMarkers(markersToShow, showMarkersForPoints, 0.0);
    }

    /**
     * <p>
     * Makes the map zoom out and centre around all the GLatLng points in markersToShow.
     * <p>
     * Big ups to Doug Leeper for the code.
     * 
     * @see <a href= "http://www.nabble.com/Re%3A-initial-GMap2-bounds-question-p19886673.html"
     *      >Doug's Nabble post</a>
     * @param markersToShow
     *            the points to centre around.
     * @param showMarkersForPoints
     *            if true, will also add basic markers to the map for each point focused on. Just a
     *            simple convenience method - you will probably want to turn this off so that you
     *            can show more information with each marker when clicked etc.
     */
    public void fitMarkers(final List<GLatLng> markersToShow, boolean showMarkersForPoints,
            final double zoomAdjustment) {
        if (markersToShow.isEmpty()) {
            log.warn("Empty list provided to GMap2.fitMarkers method.");
            return;
        }

        this.add(new Behavior() {
            private static final long serialVersionUID = 1L;

            @Override
            public void renderHead(Component component, IHeaderResponse response) {
                StringBuffer buf = new StringBuffer();
                buf.append("var bounds = new GLatLngBounds();\n");
                buf.append("var map = " + GMap2.this.getJSinvoke("map"));

                // Ask google maps to keep extending the bounds to include each
                // point
                for (GLatLng point : markersToShow) {
                    buf.append("bounds.extend( " + point.getJSconstructor() + " );\n");
                }

                // set the zoom level that shows the bounds
                buf.append("map.setZoom( map.getBoundsZoomLevel(bounds) + " + zoomAdjustment + ");\n");

                // center in the middle of the bounds
                buf.append("map.setCenter( bounds.getCenter() );\n");

                response.renderOnDomReadyJavaScript(buf.toString());
            }
        });

        // show the markers
        if (showMarkersForPoints) {
            for (GLatLng location : markersToShow) {
                addOverlay(new GMarker(location));
            }
        }
    }

    private String getJSsetGoogleBarEnabled(boolean enabled) {
        return getJSinvoke("setGoogleBarEnabled(" + enabled + ")");
    }

    private String getJSsetDraggingEnabled(boolean enabled) {
        return getJSinvoke("setDraggingEnabled(" + enabled + ")");
    }

    private String getJSsetDoubleClickZoomEnabled(boolean enabled) {
        return getJSinvoke("setDoubleClickZoomEnabled(" + enabled + ")");
    }

    private String getJSsetScrollWheelZoomEnabled(boolean enabled) {
        return getJSinvoke("setScrollWheelZoomEnabled(" + enabled + ")");
    }

    private String getJSsetZoom(int zoom) {
        return getJSinvoke("setZoom(" + zoom + ")");
    }

    private String getJSsetCenter(GLatLng center) {
        if (center != null)
            return getJSinvoke("setCenter(" + center.getJSconstructor() + ")");
        else
            return "";
    }

    private String getJSpanDirection(int dx, int dy) {
        return getJSinvoke("panDirection(" + dx + "," + dy + ")");
    }

    private String getJSpanTo(GLatLng center) {
        return getJSinvoke("panTo(" + center.getJSconstructor() + ")");
    }

    private String getJSzoomOut() {
        return getJSinvoke("zoomOut()");
    }

    private String getJSzoomIn() {
        return getJSinvoke("zoomIn()");
    }

    /**
     * Update state from a request to an AJAX target.
     */
    public void update(AjaxRequestTarget target) {
        Request request = RequestCycle.get().getRequest();

        // Attention: don't use setters as this will result in an endless
        // AJAX request loop
        bounds = GLatLngBounds.parse(request.getRequestParameters().getParameterValue("bounds").toString());
        center = GLatLng.parse(request.getRequestParameters().getParameterValue("center").toString());
        zoom = request.getRequestParameters().getParameterValue("zoom").toInt();
        mapType = GMapType.valueOf(request.getRequestParameters().getParameterValue("currentMapType").toString());

        infoWindow.update(target);
    }

    public void setOverlays(List<GOverlay> overlays) {
        removeAllOverlays();
        for (GOverlay overlay : overlays) {
            addOverlay(overlay);
        }
    }

    private abstract class JSMethodBehavior extends Behavior {

        private static final long serialVersionUID = 1L;

        private final String attribute;

        public JSMethodBehavior(final String attribute) {
            this.attribute = attribute;
        }

        /**
         * @see Behavior#onComponentTag(org.apache.wicket.Component,
         *      org.apache.wicket.markup.ComponentTag)
         */
        @Override
        public void onComponentTag(Component component, ComponentTag tag) {
            String invoke = getJSinvoke();

            if (attribute.equalsIgnoreCase("href")) {
                invoke = "javascript:" + invoke;
            }

            tag.put(attribute, invoke);
        }

        protected abstract String getJSinvoke();
    }

    public class ZoomOutBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        public ZoomOutBehavior(String event) {
            super(event);
        }

        @Override
        protected String getJSinvoke() {
            return getJSzoomOut();
        }
    }

    public class ZoomInBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        public ZoomInBehavior(String event) {
            super(event);
        }

        @Override
        protected String getJSinvoke() {
            return getJSzoomIn();
        }
    }

    public class PanDirectionBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        private final int dx;

        private final int dy;

        public PanDirectionBehavior(String event, final int dx, final int dy) {
            super(event);
            this.dx = dx;
            this.dy = dy;
        }

        @Override
        protected String getJSinvoke() {
            return getJSpanDirection(dx, dy);
        }
    }

    public class SetZoomBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        private final int zoom;

        public SetZoomBehavior(final String event, final int zoom) {
            super(event);
            this.zoom = zoom;
        }

        @Override
        protected String getJSinvoke() {
            return getJSsetZoom(zoom);
        }
    }

    public class SetCenterBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        private final GLatLng gLatLng;

        public SetCenterBehavior(String event, GLatLng gLatLng) {
            super(event);
            this.gLatLng = gLatLng;
        }

        @Override
        protected String getJSinvoke() {
            return getJSsetCenter(gLatLng);
        }
    }

    public class SetMapTypeBehavior extends JSMethodBehavior {
        private static final long serialVersionUID = 1L;

        private final GMapType mapType;

        public SetMapTypeBehavior(String event, GMapType mapType) {
            super(event);
            this.mapType = mapType;
        }

        @Override
        protected String getJSinvoke() {
            return mapType.getJSsetMapType(GMap2.this);
        }
    }

    public class OverlayListener extends AbstractDefaultAjaxBehavior {
        private static final long serialVersionUID = 1L;

        @Override
        protected void respond(AjaxRequestTarget target) {
            Request request = RequestCycle.get().getRequest();

            String overlayId = request.getRequestParameters().getParameterValue("overlay.overlayId").toString();
            String event = request.getRequestParameters().getParameterValue("overlay.event").toString();
            // TODO this is ugly
            // the id's of the Overlays are unique within the ArrayList
            // maybe we should change that collection
            for (GOverlay overlay : overlays) {
                if (overlay.getId().equals(overlayId)) {
                    overlay.onEvent(target, GEvent.valueOf(event));
                    break;
                }
            }
        }

        public Object getJSinit() {
            return getJSinvoke("overlayListenerCallbackUrl = '" + getCallbackUrl() + "'");
        }
    }
}