org.opencms.gwt.client.ui.input.location.CmsLocationController.java Source code

Java tutorial

Introduction

Here is the source code for org.opencms.gwt.client.ui.input.location.CmsLocationController.java

Source

/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.gwt.client.ui.input.location;

import org.opencms.gwt.client.Messages;
import org.opencms.gwt.client.rpc.CmsLog;
import org.opencms.gwt.client.ui.CmsAlertDialog;
import org.opencms.gwt.client.ui.CmsErrorDialog;
import org.opencms.gwt.client.ui.CmsPopup;
import org.opencms.gwt.client.util.CmsClientStringUtil;
import org.opencms.gwt.client.util.CmsDebugLog;
import org.opencms.gwt.client.util.CmsDomUtil;
import org.opencms.util.CmsStringUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.SuggestOracle;

/**
 * The location picker controller.<p>
 */
public class CmsLocationController {

    /** Flag indicating the API is currently being loaded. */
    private static boolean loadingApi;

    /** Flag indicating the dynamic error style has been inserted. */
    private static boolean m_hasInsertedDynamicStyle;

    /** The main API param. */
    private static final String MAPS_MAIN_PARAM = "v=3.exp&sensor=false";

    /** The places library param. */
    private static final String MAPS_PLACES_PARAM = "libraries=places";

    /** The URI of google maps API. */
    private static final String MAPS_URI = "https://maps.googleapis.com/maps/api/js";

    /** The callback to be executed once the API is loaded. */
    private static List<Command> onApiReady = new ArrayList<Command>();

    /** The parsed configuration JSON object. */
    private JavaScriptObject m_config;

    /** The previous value. */
    private CmsLocationValue m_currentValue;

    /** The current location value. */
    private CmsLocationValue m_editValue;

    /** The goe coder instance. */
    private JavaScriptObject m_geocoder;

    /** The map. */
    private JavaScriptObject m_map;

    /** The map marker. */
    private JavaScriptObject m_marker;

    /** The picker widget. */
    private CmsLocationPicker m_picker;

    /** The popup displaying the map. */
    private CmsPopup m_popup;

    /** The popup content widget. */
    private CmsLocationPopupContent m_popupContent;

    /** The preview map. */
    private JavaScriptObject m_previewMap;

    /** The preview map marker. */
    private JavaScriptObject m_previewMarker;

    /**
     * Constructor.<p>
     *
     * @param picker the picker widget
     * @param configuration the widget configuration
     */
    public CmsLocationController(CmsLocationPicker picker, String configuration) {
        parseConfig(configuration);
        initDynamicStyle();
        m_picker = picker;
        m_editValue = CmsLocationValue.parse(
                "{\"address\": \"London\", \"lat\": 51.5001524, \"lng\": -0.1262362, \"height\": 300, \"width\": 400, \"mode\": \"\", \"type\":\"roadmap\", \"zoom\": 8}");
        m_currentValue = m_editValue.cloneValue();
    }

    /**
     * Called once the API is loaded.<p>
     */
    private static void apiReady() {

        loadingApi = false;
        for (Command callback : onApiReady) {
            callback.execute();
        }
        onApiReady.clear();
    }

    /**
     * Returns the available map modes.<p>
     *
     * @return the available map modes
     */
    private static Map<String, String> getModeItems() {

        Map<String, String> modes = new LinkedHashMap<String, String>();
        modes.put("dynamic", Messages.get().key(Messages.GUI_LOCATION_DYNAMIC_0));
        modes.put("static", Messages.get().key(Messages.GUI_LOCATION_STATIC_0));
        return modes;
    }

    /**
     * Returns the available map types.<p>
     *
     * @return the available map types
     */
    private static Map<String, String> getTypeItems() {

        Map<String, String> types = new LinkedHashMap<String, String>();
        types.put("roadmap", Messages.get().key(Messages.GUI_LOCATION_ROADMAP_0));
        types.put("hybrid", Messages.get().key(Messages.GUI_LOCATION_HYBRID_0));
        types.put("satellite", Messages.get().key(Messages.GUI_LOCATION_SATELLITE_0));
        types.put("terrain", Messages.get().key(Messages.GUI_LOCATION_TERRAIN_0));
        return types;
    }

    /**
     * Returns the available zoom levels.<p>
     *
     * @return the available zoom levels
     */
    private static Map<String, String> getZoomItems() {

        Map<String, String> zoomItems = new LinkedHashMap<String, String>();
        for (int i = 0; i < 21; i++) {
            String value = String.valueOf(i);
            zoomItems.put(value, value);
        }
        return zoomItems;
    }

    /**
     * Returns if the google maps API is already loaded to the window context.<p>
     *
     * @return <code>true</code>  if the google maps API is already loaded to the window context
     */
    private static boolean isApiLoaded() {

        return isMainApiLoaded() && isPlacesApiLoaded();
    }

    /**
     * Returns if the google maps API is already loaded to the window context.<p>
     *
     * @return <code>true</code>  if the google maps API is already loaded to the window context
     */
    private static native boolean isMainApiLoaded()/*-{
                                                   var result = $wnd.google !== undefined
                                                   && $wnd.google.maps !== undefined
                                                   && $wnd.google.maps.Map !== undefined;
                                                   return result;
                                                   }-*/;

    /**
     * Returns if the google maps API is already loaded to the window context.<p>
     *
     * @return <code>true</code>  if the google maps API is already loaded to the window context
     */
    private static native boolean isPlacesApiLoaded()/*-{
                                                     var result = $wnd.google !== undefined
                                                     && $wnd.google.maps !== undefined
                                                     && $wnd.google.maps.places !== undefined;
                                                     return result;
                                                     }-*/;

    /**
     * Returns the current location value.<p>
     *
     * @return the location value
     */
    public CmsLocationValue getLocationValue() {

        return m_editValue;
    }

    /**
     * Returns the JSON string representation of the current value.<p>
     *
     * @return the JSON string representation
     */
    public String getStringValue() {

        return m_currentValue == null ? "" : m_currentValue.toJSONString();
    }

    /** Sets the location value as string.
     *
     * @param value the string representation of the location value (JSON)
     **/
    public void setStringValue(String value) {

        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value)) {
            try {
                m_editValue = CmsLocationValue.parse(value);
                m_currentValue = m_editValue.cloneValue();
                displayValue();
                if ((m_popup != null) && m_popup.isVisible()) {
                    m_popupContent.displayValues(m_editValue);
                    updateMarkerPosition();
                }
            } catch (Exception e) {
                CmsLog.log(e.getLocalizedMessage() + "\n" + CmsClientStringUtil.getStackTrace(e, "\n"));
            }
        } else {
            m_currentValue = null;
            displayValue();
        }
    }

    /**
     * Return a maps API position object according the the current location value.<p>
     *
     * @return the position object
     */
    protected native JavaScriptObject getCurrentPosition()/*-{
                                                          var val = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue;
                                                          return new $wnd.google.maps.LatLng(val.lat, val.lng);
                                                              
                                                          }-*/;

    /**
     * Called on address value change.<p>
     *
     * @param address the new address
     */
    protected native void onAddressChange(String address) /*-{
                                                          var self = this;
                                                          this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = address;
                                                          this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder
                                                          .geocode(
                                                          {
                                                          'address' : address
                                                          },
                                                          function(results, status) {
                                                          // check to see if we have at least one valid address
                                                          if (!results
                                                          || (status != $wnd.google.maps.GeocoderStatus.OK)
                                                          || !results[0].formatted_address) {
                                                          alert("Address not found");
                                                          return;
                                                          }
                                                          var lat = results[0].geometry.location.lat();
                                                          var lng = results[0].geometry.location.lng();
                                                          self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,true,false);
                                                          });
                                                          }-*/;

    /**
     * Called on address suggestion selection.<p>
     *
     * @param suggestion the selected suggestion
     */
    protected void onAddressChange(SuggestOracle.Suggestion suggestion) {

        try {
            onAddressChange(suggestion.getDisplayString());
        } catch (Throwable t) {
            CmsErrorDialog.handleException(t);
        }
    }

    /**
     * Cancels the location selection.<p>
     */
    protected void onCancel() {

        m_popup.hide();
        if (m_currentValue != null) {
            m_editValue = m_currentValue;
        }
        displayValue();
    }

    /**
     * Called on height value change.<p>
     *
     * @param height the height
     */
    protected void onHeightChange(String height) {

        m_editValue.setHeight(height);
    }

    /**
     * Called on latitude value change.<p>
     *
     * @param latitude the latitude
     */
    protected void onLatitudeChange(String latitude) {

        try {
            m_editValue.setLatitude(latitude);
            updateMarkerPosition();
            updateAddress();
        } catch (Throwable t) {
            CmsErrorDialog.handleException(t);
        }
    }

    /**
     * Called on longitude value change.<p>
     *
     * @param longitude the longitude
     */
    protected void onLongitudeChange(String longitude) {

        try {
            m_editValue.setLongitude(longitude);
            updateMarkerPosition();
            updateAddress();
        } catch (Throwable t) {
            CmsErrorDialog.handleException(t);
        }
    }

    /**
     * Called on mode value change.<p>
     *
     * @param mode the mode
     */
    protected void onModeChange(String mode) {

        m_editValue.setMode(mode);
    }

    /**
     * Sets the selected location value.<p>
     */
    protected void onOk() {

        ensureFormattedAddress();
    }

    /**
     * Ensures the preview map has the right size and is centered.<p>
     */
    protected native void onPreviewResize()/*-{
                                           var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMap;
                                           if (map != null) {
                                           $wnd.google.maps.event.trigger(map, 'resize');
                                           var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()();
                                           map.setCenter(pos);
                                           }
                                           }-*/;

    /**
     * Called on map type change.<p>
     *
     * @param type the map type
     */
    protected native void onTypeChange(String type)/*-{
                                                   this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.type = type;
                                                   this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map
                                                   .setMapTypeId(type);
                                                   }-*/;

    /**
     * Called on width value change.<p>
     *
     * @param width the width
     */
    protected void onWidthChange(String width) {

        m_editValue.setWidth(width);
    }

    /**
     * Called on zoom value change.<p>
     *
     * @param zoom the zoom
     */
    protected native void onZoomChange(String zoom) /*-{
                                                    var z = parseInt(zoom);
                                                    if (!isNaN(z)) {
                                                    this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.zoom = z;
                                                    var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map;
                                                    map.setZoom(z);
                                                    var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()();
                                                    map.panTo(pos);
                                                    map.setCenter(pos);
                                                    }
                                                    }-*/;

    /**
    * Fires the value change event for the location picker.<p>
    *
    * @param force <code>true</code> to always fire the event
    */
    void fireChangeEventOnPicker(boolean force) {

        String val = m_editValue.toJSONString();
        if (force || (m_currentValue == null) || !val.equals(m_currentValue.toJSONString())) {
            m_currentValue = m_editValue.cloneValue();
            displayValue();
            ValueChangeEvent.fire(m_picker, val);
        }
    }

    /**
     * Displays the map for the current location.<p>
     */
    native void initMap() /*-{
                          try {
                          if (this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map == null) {
                          var value = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue;
                          var type = (value.type == null || value.type == "") ? "roadmap"
                          : value.type;
                          var zoom = parseInt(value.zoom);
                          if (isNaN(zoom)) {
                          zoom = 8;
                          }
                              
                          var mapOptions = {
                          zoom : zoom,
                          mapTypeId : type,
                          center : new $wnd.google.maps.LatLng(-34.397, 150.644),
                          streetViewControl : false
                          };
                          var popupContent = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_popupContent;
                          var canvas = popupContent.@org.opencms.gwt.client.ui.input.location.CmsLocationPopupContent::getMapCanvas()();
                          this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map = new $wnd.google.maps.Map(
                          canvas, mapOptions);
                          this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder = new $wnd.google.maps.Geocoder();
                          }
                          } catch (e) {
                          $wnd.console.log(e.message);
                          }
                          this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::updateMarkerPosition()();
                          }-*/;

    /**
     * Opens the location picker popup.<p>
     */
    void openPopup() {

        if (hasError()) {
            CmsAlertDialog alert = new CmsAlertDialog(Messages.get().key(Messages.ERR_TITLE_ERROR_0),
                    Messages.get().key(Messages.ERR_LOCATION_MISSING_API_KEY_1, "<br />"));
            alert.center();
            return;
        }
        try {
            if (m_popup == null) {
                m_popup = new CmsPopup(Messages.get().key(Messages.GUI_LOCATION_DIALOG_TITLE_0),
                        hasMap() ? 1020 : 420);
                m_popupContent = new CmsLocationPopupContent(this, new CmsLocationSuggestOracle(this),
                        getModeItems(), getTypeItems(), getZoomItems());
                setFieldVisibility();
                m_popup.setMainContent(m_popupContent);
                m_popup.addDialogClose(null);
            }
            m_popup.center();
            m_popup.show();
            initialize();
            updateForm();
        } catch (Throwable t) {
            CmsErrorDialog.handleException(t);
        }
    }

    /**
     * Shows the map preview.<p>
     */
    native void showMapPreview() /*-{
                                 var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMap;
                                 var value = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue;
                                 var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()();
                                 var type = (value.type == null || value.type == "") ? "roadmap"
                                 : value.type;
                                 var zoom = parseInt(value.zoom);
                                 if (isNaN(zoom)) {
                                 zoom = 8;
                                 }
                                 if (map == null) {
                                 var picker = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_picker;
                                 var canvas = picker.@org.opencms.gwt.client.ui.input.location.CmsLocationPicker::getMapPreview()();
                                 var mapOptions = {
                                 zoom : zoom,
                                 mapTypeId : type,
                                 center : pos,
                                 draggable : false,
                                 disableDefaultUi : true,
                                 disableDoubleClickZoom : true,
                                 mapTypeControl : false,
                                 zoomControl : false,
                                 streetViewControl : false,
                                 scrollwheel : false,
                                 keyboardShortcuts : false
                                 };
                                 map = new $wnd.google.maps.Map(canvas, mapOptions);
                                 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMap = map;
                                 } else {
                                 map.setZoom(zoom);
                                 map.setMapTypeId(type);
                                     
                                 }
                                 var marker = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMarker;
                                 if (marker == null) {
                                 var marker = new $wnd.google.maps.Marker({
                                 position : pos,
                                 map : map,
                                 draggable : false
                                 });
                                 this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_previewMarker = marker;
                                 } else {
                                 marker.setPosition(pos);
                                 }
                                 $wnd.google.maps.event.trigger(map, 'resize');
                                 map.setCenter(pos);
                                 }-*/;

    /**
     * Displays the values within the picker widget.<p>
     */
    private void displayValue() {

        if (m_currentValue == null) {
            m_picker.displayValue("");
            m_picker.setPreviewVisible(false);
            m_picker.setLocationInfo(Collections.<String, String>emptyMap());
        } else {
            m_picker.displayValue(m_editValue.getAddress());
            Map<String, String> infos = new LinkedHashMap<String, String>();
            if (hasLatLng()) {
                infos.put(Messages.get().key(Messages.GUI_LOCATION_LATITUDE_0), m_editValue.getLatitudeString());
                infos.put(Messages.get().key(Messages.GUI_LOCATION_LONGITUDE_0), m_editValue.getLongitudeString());
            }
            if (hasSize()) {
                infos.put(Messages.get().key(Messages.GUI_LOCATION_SIZE_0),
                        m_editValue.getWidth() + " x " + m_editValue.getHeight());
            }
            if (hasType()) {
                infos.put(Messages.get().key(Messages.GUI_LOCATION_TYPE_0), m_editValue.getType());
            }
            if (hasMode()) {
                infos.put(Messages.get().key(Messages.GUI_LOCATION_MODE_0), m_editValue.getMode());
            }
            m_picker.setLocationInfo(infos);
            m_picker.setPreviewVisible(true);
            if (isApiLoaded()) {
                showMapPreview();
            } else {
                onApiReady(new Command() {

                    public void execute() {

                        showMapPreview();
                    }
                });
            }
        }
    }

    /**
     * Checks the current address with the google geocoder to ensure a well formatted address.<p>
     * Will close the picker popup afterwards.<p>
     */
    private native void ensureFormattedAddress()/*-{
                                                var self = this;
                                                var address = self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address;
                                                if (address != null && address.trim().length > 0) {
                                                self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder
                                                .geocode(
                                                {
                                                'address' : address
                                                },
                                                function(results, status) {
                                                // check to see if we have at least one valid address
                                                if (results
                                                && (status == $wnd.google.maps.GeocoderStatus.OK)
                                                && results[0].formatted_address) {
                                                self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = results[0].formatted_address;
                                                var lat = results[0].geometry.location
                                                .lat();
                                                var lng = results[0].geometry.location
                                                .lng();
                                                self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,true,false);
                                                }
                                                self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()();
                                                });
                                                }
                                                self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::fireChangeAndClose()();
                                                }-*/;

    /**
     * Fires the value change event and closes the picker popup.<p>
     */
    private void fireChangeAndClose() {

        fireChangeEventOnPicker(false);
        m_popup.hide();
    }

    /**
     * Returns the Google API key.<p>
     *
     * @return the Google API key
     */
    private native String getAPIKey()/*-{
                                     return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey;
                                     }-*/;

    /**
     * Returns the value display string.<p>
     *
     * @return the value
     */
    private String getDisplayString() {

        return Messages.get().key(Messages.GUI_LOCATION_DISPLAY_3, m_editValue.getAddress(),
                m_editValue.getLatitudeString(), m_editValue.getLongitudeString());
    }

    /**
     * Evaluates if the address field is configured.<p>
     *
     * @return <code>true</code> if the address field is configured
     */
    private native boolean hasAddress()/*-{
                                       return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                       .indexOf('address') != -1;
                                       }-*/;

    /**
     * Evaluates if the Google API key is configured.<p>
     *
     * @return <code>true</code> if the Google API key is configured
     */
    private native boolean hasAPIKey()/*-{
                                      return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config != null
                                      && this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.apiKey != null;
                                      }-*/;

    /**
     * Checks whether the error element is present in the preview DIV or the preview DIV is empty.<p>
     *
     * @return <code>true</code> in case of an error state
     */
    private boolean hasError() {

        return (CmsDomUtil.querySelector(".gm-err-content", m_picker.getMapPreview()) != null)
                || (((m_picker.getMapPreview().getFirstChildElement() == null) || CmsStringUtil
                        .isEmptyOrWhitespaceOnly(m_picker.getMapPreview().getFirstChildElement().getInnerHTML())));
    }

    /**
     * Evaluates if the lat. lng. fields are configured.<p>
     *
     * @return <code>true</code> if the lat. lng. fields are configured
     */
    private native boolean hasLatLng()/*-{
                                      return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                      .indexOf('coords') != -1;
                                      }-*/;

    /**
     * Evaluates if the map field is configured.<p>
     *
     * @return <code>true</code> if the map field is configured
     */
    private native boolean hasMap()/*-{
                                   return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                   .indexOf('map') != -1;
                                   }-*/;

    /**
     * Evaluates if the mode field is configured.<p>
     *
     * @return <code>true</code> if the mode field is configured
     */
    private native boolean hasMode()/*-{
                                    return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                    .indexOf('mode') != -1;
                                    }-*/;

    /**
     * Evaluates if the size fields are configured.<p>
     *
     * @return <code>true</code> if the size fields are configured
     */
    private native boolean hasSize()/*-{
                                    return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                    .indexOf('size') != -1;
                                    }-*/;

    /**
     * Evaluates if the type field is configured.<p>
     *
     * @return <code>true</code> if the type field is configured
     */
    private native boolean hasType()/*-{
                                    return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                    .indexOf('type') != -1;
                                    }-*/;

    /**
     * Evaluates if the zoom field is configured.<p>
     *
     * @return <code>true</code> if the zoom field is configured
     */
    private native boolean hasZoom()/*-{
                                    return this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config.edit
                                    .indexOf('zoom') != -1;
                                    }-*/;

    /**
     * Adds a CSS style rule to display the localized error message on missing API key.<p>
     */
    private void initDynamicStyle() {

        if (!m_hasInsertedDynamicStyle) {
            String message = Messages.get().key(Messages.ERR_LOCATION_MISSING_API_KEY_1, "\\a");
            message.replace("<br />", "\\\\a");
            CmsDebugLog.consoleLog("Setting missing key message: " + message);
            CmsDomUtil.addDynamicStyleRule(
                    "div.gm-err-content:after, div.mapPreview > div > div:empty:after{ content:'" + message
                            + "' !important; }");
            m_hasInsertedDynamicStyle = true;
        }
    }

    /**
     * Initializes the location picker.<p>
     */
    private void initialize() {

        if (isApiLoaded()) {
            initMap();
        } else {
            onApiReady(new Command() {

                public void execute() {

                    initMap();
                }
            });
        }
    }

    /**
     * Loads the google maps API and initializes the map afterwards.<p>
     */
    private native void loadApi()/*-{
                                 $wnd.cmsLocationPickerApiReady = function() {
                                 @org.opencms.gwt.client.ui.input.location.CmsLocationController::apiReady()();
                                 }
                                 var uri = @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_URI;
                                 uri += '?'
                                 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_MAIN_PARAM
                                 + '&'
                                 + @org.opencms.gwt.client.ui.input.location.CmsLocationController::MAPS_PLACES_PARAM;
                                 if (this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::hasAPIKey()()) {
                                 uri += '&key='
                                 + this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getAPIKey()();
                                 }
                                 uri += '&callback=cmsLocationPickerApiReady';
                                     
                                 var script = $wnd.document.createElement('script');
                                 script.type = 'text/javascript';
                                 script.src = uri;
                                 $wnd.document.body.appendChild(script);
                                 }-*/;

    /**
     * Adds a callback to be executed once the API is ready. Will be executed right away if the API is already loaded.<p>
     *
     * @param callback the callback
     */
    private void onApiReady(Command callback) {

        if (isApiLoaded()) {
            callback.execute();
        } else {
            onApiReady.add(callback);
            if (!loadingApi) {
                loadingApi = true;
                loadApi();
            }
        }
    }

    /**
     * Parses the configuration string.<p>
     *
     * @param configuration the configuration
     */
    private native void parseConfig(String configuration)/*-{
                                                         this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_config = JSON
                                                         .parse(configuration);
                                                         }-*/;

    /**
     * Sets all editable fields visible.<p>
     */
    private void setFieldVisibility() {

        m_popupContent.setMapVisible(hasMap());
        m_popupContent.setAddressVisible(hasAddress());
        m_popupContent.setLatLngVisible(hasLatLng());
        m_popupContent.setSizeVisible(hasSize());
        m_popupContent.setTypeVisible(hasType());
        m_popupContent.setModeVisible(hasMode());
        m_popupContent.setZoomVisible(hasZoom());
    }

    /**
     * Sets the position values and updates the map view.<p>
     *
     * @param latitude the latitude
     * @param longitude the longitude
     * @param updateMap <code>true</code> to update the map
     * @param updateAddress <code>true</code> to update the address from the new position data
     */
    private void setPosition(float latitude, float longitude, boolean updateMap, boolean updateAddress) {

        m_editValue.setLatitude(latitude);
        m_editValue.setLongitude(longitude);
        m_popupContent.displayValues(m_editValue);
        if (updateMap) {
            updateMarkerPosition();
        }
        if (updateAddress) {
            updateAddress();
        }
    }

    /**
     * Updates the address according to the current position data.<p>
     */
    private native void updateAddress()/*-{
                                       var self = this;
                                       var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()();
                                       // try to evaluate the address from the current position
                                       this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_geocoder
                                       .geocode(
                                       {
                                       'latLng' : pos
                                       },
                                       function(results, status) {
                                       var address = "";
                                       // check that everything is ok
                                       if (status == $wnd.google.maps.GeocoderStatus.OK
                                       && results[0]
                                       && results[0].formatted_address) {
                                       // set the new address
                                       address = results[0].formatted_address;
                                       }
                                       if (address != self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address) {
                                       self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_editValue.address = address;
                                       self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::updateForm()();
                                       }
                                       });
                                       }-*/;

    /**
     * Displays the current location value within the popup form.<p>
     */
    private void updateForm() {

        m_popupContent.displayValues(m_editValue);
    }

    /**
     * Updates the marker position according to the current location value.<p>
     */
    private native void updateMarkerPosition()/*-{
                                              var map = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_map;
                                              var pos = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::getCurrentPosition()();
                                              var marker = this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker;
                                              if (marker == null) {
                                              try {
                                              var marker = new $wnd.google.maps.Marker({
                                              position : pos,
                                              map : map,
                                              draggable : true
                                              });
                                              this.@org.opencms.gwt.client.ui.input.location.CmsLocationController::m_marker = marker;
                                              var self = this;
                                              // handle marker dnd
                                              $wnd.google.maps.event
                                              .addListener(
                                              marker,
                                              "dragend",
                                              function() {
                                              var lat = marker.getPosition().lat();
                                              var lng = marker.getPosition().lng();
                                              self.@org.opencms.gwt.client.ui.input.location.CmsLocationController::setPosition(FFZZ)(lat,lng,false,true);
                                              });
                                              } catch (e) {
                                              $wnd.alert(e.message);
                                              }
                                              } else {
                                              marker.setPosition(pos);
                                              }
                                              map.panTo(pos);
                                              map.setCenter(pos);
                                              }-*/;

}