#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2008-2011 É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 = [settings.MEDIA_URL+"OpenLayers.js", "http://www.openstreetmap.org/openlayers/OpenStreetMap.js"] def getMapJS(area_name=''): '''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"var restricted_extent;\n" if area_name: js += u"var area_name='%s';\n" % area_name if settings.RESTRICTED_EXTENT: restricted_extent_str = [str(coord) \ for coord in settings.RESTRICTED_EXTENT] js += u"restricted_extent = new OpenLayers.Bounds(%s);\n" %\ ", ".join(restricted_extent_str) 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, area_name=''): ''' 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(area_name) 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, instance=None): 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, area_name='', routefile_id=None): ''' Render a map and latitude, longitude information field ''' tpl = getMapJS(area_name) help_create = '' if not value: help_create = """

%s

%s

%s

%s

%s

%s

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

%s

%s

%s

%s

""" % (_(u"Modification mode"), _(u"To move a point click on it and drag it to the desired position."), _(u"To delete a point move the mouse cursor over it and press the \"d\" or \ \"Del\" key."), _(u"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: # upload a file tpl += u""" """ % _(u"Give a name and set category before uploading a file.") tpl += u'' % ( _(u"Upload a route file (GPX or KML)")) 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, routefile_id) 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_lon', 'upper_left_lat',), ('lower_right_lon', 'lower_right_lat')): 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 class MultiSelectWidget(forms.SelectMultiple): class Media: css = {'all': ( settings.MEDIA_URL + 'jquery/bsmSelect/css/jquery.bsmselect.css', settings.MEDIA_URL + 'jquery/css/jquery.bsmselect.custom.css', ) } js = ( settings.MEDIA_URL + 'jquery/jquery-1.4.4.min.js', settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.js', settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.compatibility.js', ) def render(self, name, value, attrs=None): rendered = super(MultiSelectWidget, self).render(name, value, attrs) return mark_safe(rendered + u'''
''' % {'name':name, 'title':_("Select...")}) class SelectMultipleField(models.ManyToManyField): ''' Set the widget for the category field ''' def formfield(self, **keys): self.help_text = "" defaults = {'widget': MultiSelectWidget} keys.update(defaults) return super(SelectMultipleField, self).formfield(**keys)