136 lines
5.0 KiB
Python
136 lines
5.0 KiB
Python
# 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
|