#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2008 Étienne Loks # This program 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. # This program 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 this program. If not, see . # See the file COPYING for details. """ Extra widgets and fields """ from django import forms from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from django.contrib.gis.geos import fromstr from chimere import settings from django.contrib.gis.db import models URL_OSM_CSS = ["http://www.openlayers.org/api/theme/default/style.css"] URL_OSM_JS = ["http://www.openlayers.org/api/OpenLayers.js", "http://www.openstreetmap.org/openlayers/OpenStreetMap.js"] def getMapJS(): '''Variable initialization for drawing the map ''' # projection, center and bounds definitions js = u"var epsg_display_projection = new OpenLayers.Projection('EPSG:%d')\ ;\n" % settings.EPSG_DISPLAY_PROJECTION js += u"var epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \ settings.EPSG_PROJECTION js += u"var centerLonLat = new OpenLayers.LonLat(%f,\ %f).transform(epsg_display_projection, epsg_projection);\n" % \ settings.DEFAULT_CENTER js += u"var media_path = '%s';\n" % settings.MEDIA_URL js += u"var map_layer = %s;\n" % settings.MAP_LAYER js = u""" """ % js return js class TextareaWidget(forms.Textarea): """ Manage the edition of a text using TinyMCE """ class Media: js = ["%stiny_mce.js" % settings.TINYMCE_URL, "%stextareas.js" % settings.MEDIA_URL,] class PointChooserWidget(forms.TextInput): """ Manage the edition of point on a map """ class Media: css = { "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,] } js = URL_OSM_JS + ["%sedit_map.js" % settings.MEDIA_URL, "%sbase.js" % settings.MEDIA_URL,] def render(self, name, value, attrs=None): ''' Render a map and latitude, longitude information field ''' val = '0' value_x, value_y = 0, 0 if value: val = str(value) if hasattr(value, 'x') and hasattr(value, 'y'): value_x, value_y = value.x, value.y elif isinstance(value, unicode) and value.startswith('POINT('): try: value_x, value_y = value.split('(')[1][:-1].split(' ') value_x, value_y = float(value_x), float(value_y) except: value = None else: value = None tpl = getMapJS() tpl += u'\n' % settings.MEDIA_URL tpl += u"""

\

""" % (_("Latitude"), value_y, _("Longitude"), value_x, name, name, val) tpl += """
""" return mark_safe(tpl) class PointField(models.PointField): ''' Set the widget for the form field ''' def formfield(self, **keys): defaults = {'widget': PointChooserWidget} keys.update(defaults) return super(PointField, self).formfield(**keys) def clean(self, value): if len(value) != 2 and self.required: raise ValidationError(_("Invalid point")) return value class RouteChooserWidget(forms.TextInput): """ Manage the edition of route on a map """ class Media: css = { "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,] } js = ["%sedit_route_map.js" % settings.MEDIA_URL, "%sbase.js" % settings.MEDIA_URL,] + URL_OSM_JS def render(self, name, value, attrs=None): ''' Render a map and latitude, longitude information field ''' tpl = getMapJS() help_create = '' if not value: help_create = """

%s

%s

%s

%s

%s

%s

""" % (_("Creation mode"), _("To start drawing the route click on the toggle button : \"Start drawing\"."), _("Then click on the map to begin the drawing."), _("You can add points by clicking again."), _("To finish the drawing double click. When the drawing is finished you can \ edit it."), _("While creating to undo a drawing click again on the toggle button \"Stop \ drawing\".")) help_modify = """

%s

%s

%s

%s

""" % (_("Modification mode"), _("To move a point click on it and drag it to the desired position."), _("To delete a point move the mouse cursor over it and press the \"d\" key."), _("To add a point click in the middle of a segment and drag the new point to \ the desired position")) tpl += u'\n' % \ settings.MEDIA_URL if not value: tpl += u"""
%s
%s

""" % (_("Start drawing"), _("Stop drawing")) tpl += """
""" if not value: tpl += '''
%s
''' % help_create style = '' if value: style = " style='display:block'" tpl += """
%s

""" % (style, help_modify, name, name, value) tpl += """ """ return mark_safe(tpl) class RouteField(models.LineStringField): ''' Set the widget for the form field ''' def formfield(self, **keys): defaults = {'widget': RouteChooserWidget} keys.update(defaults) return super(RouteField, self).formfield(**keys) class AreaWidget(forms.TextInput): """ Manage the edition of an area on the map """ class Media: css = { "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,] } js = URL_OSM_JS + ["%sedit_area.js" % settings.MEDIA_URL, "%sbase.js" % settings.MEDIA_URL,] def render(self, name, value, attrs=None): """ Render a map """ upper_left_lat, upper_left_lon = 0, 0 lower_right_lat, lower_right_lon = 0, 0 if value: if len(value) == 2: upper_left = value[0] lower_right = value[1] if hasattr(upper_left, 'x') and hasattr(upper_left, 'y'): upper_left_lon, upper_left_lat = upper_left.x, upper_left.y if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'): lower_right_lon, lower_right_lat = lower_right.x, \ lower_right.y tpl = getMapJS() tpl += u"""
""" % (upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon) tpl += """
""" return mark_safe(tpl) def value_from_datadict(self, data, files, name): """ Return the appropriate values """ values = [] for keys in (('upper_left_lat', 'upper_left_lon',), ('lower_right_lat', 'lower_right_lon')): value = [] for key in keys: val = data.get(key, None) if not val: return [] value.append(val) values.append(value) return values class AreaField(forms.MultiValueField): ''' Set the widget for the form field ''' widget = AreaWidget def compress(self, data_list): if not data_list: return None return data_list