# RemovedInDjango50Warning.
import logging
import warnings
from django.contrib.gis.gdal import GDALException
from django.contrib.gis.geos import GEOSException, GEOSGeometry
from django.forms.widgets import Textarea
from django.utils import translation
from django.utils.deprecation import RemovedInDjango50Warning
# Creating a template context that contains Django settings
# values needed by admin map templates.
geo_context = {"LANGUAGE_BIDI": translation.get_language_bidi()}
logger = logging.getLogger("django.contrib.gis")
class OpenLayersWidget(Textarea):
"""
Render an OpenLayers map using the WKT of the geometry.
"""
def __init__(self, *args, **kwargs):
warnings.warn(
"django.contrib.gis.admin.OpenLayersWidget is deprecated.",
RemovedInDjango50Warning,
stacklevel=2,
)
super().__init__(*args, **kwargs)
def get_context(self, name, value, attrs):
# Update the template parameters with any attributes passed in.
if attrs:
self.params.update(attrs)
self.params["editable"] = self.params["modifiable"]
else:
self.params["editable"] = True
# Defaulting the WKT value to a blank string -- this
# will be tested in the JavaScript and the appropriate
# interface will be constructed.
self.params["wkt"] = ""
# If a string reaches here (via a validation error on another
# field) then just reconstruct the Geometry.
if value and isinstance(value, str):
try:
value = GEOSGeometry(value)
except (GEOSException, ValueError) as err:
logger.error("Error creating geometry from value '%s' (%s)", value, err)
value = None
if (
value
and value.geom_type.upper() != self.geom_type
and self.geom_type != "GEOMETRY"
):
value = None
# Constructing the dictionary of the map options.
self.params["map_options"] = self.map_options()
# Constructing the JavaScript module name using the name of
# the GeometryField (passed in via the `attrs` keyword).
# Use the 'name' attr for the field name (rather than 'field')
self.params["name"] = name
# note: we must switch out dashes for underscores since js
# functions are created using the module variable
js_safe_name = self.params["name"].replace("-", "_")
self.params["module"] = "geodjango_%s" % js_safe_name
if value:
# Transforming the geometry to the projection used on the
# OpenLayers map.
srid = self.params["srid"]
if value.srid != srid:
try:
ogr = value.ogr
ogr.transform(srid)
wkt = ogr.wkt
except GDALException as err:
logger.error(
"Error transforming geometry from srid '%s' to srid '%s' (%s)",
value.srid,
srid,
err,
)
wkt = ""
else:
wkt = value.wkt
# Setting the parameter WKT with that of the transformed
# geometry.
self.params["wkt"] = wkt
self.params.update(geo_context)
return self.params
def map_options(self):
"""Build the map options hash for the OpenLayers template."""
# JavaScript construction utilities for the Bounds and Projection.
def ol_bounds(extent):
return "new OpenLayers.Bounds(%s)" % extent
def ol_projection(srid):
return 'new OpenLayers.Projection("EPSG:%s")' % srid
# An array of the parameter name, the name of their OpenLayers
# counterpart, and the type of variable they are.
map_types = [
("srid", "projection", "srid"),
("display_srid", "displayProjection", "srid"),
("units", "units", str),
("max_resolution", "maxResolution", float),
("max_extent", "maxExtent", "bounds"),
("num_zoom", "numZoomLevels", int),
("max_zoom", "maxZoomLevels", int),
("min_zoom", "minZoomLevel", int),
]
# Building the map options hash.
map_options = {}
for param_name, js_name, option_type in map_types:
if self.params.get(param_name, False):
if option_type == "srid":
value = ol_projection(self.params[param_name])
elif option_type == "bounds":
value = ol_bounds(self.params[param_name])
elif option_type in (float, int):
value = self.params[param_name]
elif option_type in (str,):
value = '"%s"' % self.params[param_name]
else:
raise TypeError
map_options[js_name] = value
return map_options