#!/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 conf from django import forms from django.conf import settings from django.contrib.gis.db import models from django.contrib.gis.geos import fromstr from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ 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')"\ u";\n" % settings.CHIMERE_EPSG_DISPLAY_PROJECTION js += u"OpenLayers.ImgPath = '%schimere/img/';\n" % settings.STATIC_URL js += u"var epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \ settings.CHIMERE_EPSG_PROJECTION js += u"var centerLonLat = new OpenLayers.LonLat(%f,"\ u"%f).transform(epsg_display_projection, epsg_projection);\n" % \ settings.CHIMERE_DEFAULT_CENTER js += u"var media_path = '%s';\n" % settings.STATIC_URL js += u"var map_layer = %s;\n" % settings.CHIMERE_MAP_LAYER js += u"var restricted_extent;\n" if area_name: js += u"var area_name='%s';\n" % area_name if settings.CHIMERE_RESTRICTED_EXTENT: restricted_extent_str = [str(coord) \ for coord in settings.CHIMERE_RESTRICTED_EXTENT] js += u"restricted_extent = new OpenLayers.Bounds(%s);\n" %\ ", ".join(restricted_extent_str) js = u"\n" % js return js class TextareaWidget(forms.Textarea): """ Manage the edition of a text using TinyMCE """ class Media: js = ["%stiny_mce.js" % settings.TINYMCE_URL, "%schimere/js/textareas.js" % settings.STATIC_URL,] class DatePickerWidget(forms.TextInput): """ Manage the edition of dates. JQuery and Jquery-UI are already loaded by default so don't include them in Media files. """ def render(self, *args, **kwargs): rendered = super(DatePickerWidget, self).render(*args, **kwargs) rendered += u"\n\n" % kwargs['attrs']['id'] return mark_safe(rendered) class PointChooserWidget(forms.TextInput): """ Manage the edition of point on a map """ class Media: css = { "all": settings.OSM_CSS_URLS + \ ["%schimere/css/forms.css" % settings.STATIC_URL,] } js = settings.OSM_JS_URLS + \ ["%schimere/js/edit_map.js" % settings.STATIC_URL, "%schimere/js/base.js" % settings.STATIC_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.STATIC_URL tpl += u"
"\ u"
"\ u"

"\ u"

"\ u"

"\ u"
"\ u"" % ( _("Latitude"), value_y, _("Longitude"), value_x, name, name, val) tpl += "\n"\ u"
\n" 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": settings.OSM_CSS_URLS + \ ["%schimere/css/forms.css" % settings.STATIC_URL,] } js = settings.OSM_JS_URLS + \ ["%schimere/js/edit_route_map.js" % settings.STATIC_URL, "%schimere/js/base.js" % settings.STATIC_URL,] 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 = u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n" % (_(u"Creation mode"), _(u"To start drawing the route click on the toggle button: "\ u"\"Draw\"."), _(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 "\ u"finished you can edit it."), _(u"While creating to undo a drawing click again on the toggle "\ u"button \"Stop drawing\".")) help_modify = u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n"\ u"

%s

\n" % (_(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 "\ u"\"d\" or \"Del\" key."), _(u"To add a point click in the middle of a segment and drag the new "\ u"point to the desired position")) tpl += u'\n' % \ settings.STATIC_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"\n

%s

\n" % _(u"or") tpl += u"
\n"\ u"%s
"\ u"
\n"\ u"
" % (_(u"Start \"hand\" drawing")) if value: tpl += u"\n
" else: tpl += u"\n
\n"\ u"
\n"\ u" %s"\ u"\n"\ u""\ u"%s
\n"\ u"
" % (_(u"Move on the map"), _(u"Draw")) tpl += "\n
%s
"\ % help_create style = '' if value: style = " style='display:block'" tpl += u"\n
%s
"\ u"\n
\n"\ u"\n"\ u"\n" % ( style, help_modify, name, name, value, routefile_id) tpl += u"\n" 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": settings.OSM_CSS_URLS + ["%schimere/css/forms.css" % settings.STATIC_URL,] } js = settings.OSM_JS_URLS + ["%schimere/js/edit_area.js" % settings.STATIC_URL, "%schimere/js/base.js" % settings.STATIC_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"
\n"\ u"\n"\ u"\n"\ u"\n"\ u"\n" % ( upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon) tpl += u"\n
\n" 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': list(settings.JQUERY_CSS_URLS) + [ settings.STATIC_URL + 'chimere/js/jquery/bsmSelect/css/jquery.bsmselect.css', settings.STATIC_URL + 'chimere/js/jquery/bsmSelect/css/jquery.bsmselect.custom.css', ] } js = list(settings.JQUERY_JS_URLS) + [ settings.STATIC_URL + 'chimere/js/jquery/bsmSelect/js/jquery.bsmselect.js', settings.STATIC_URL + 'chimere/js/jquery/bsmSelect/js/jquery.bsmselect.compatibility.js', ] def render(self, name, value, attrs=None): rendered = super(MultiSelectWidget, self).render(name, value, attrs) rendered += u"
\n" % {'name':name, 'title':_("Select...")} return mark_safe(rendered) 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) from south.modelsinspector import add_introspection_rules add_introspection_rules([], ["^chimere\.widgets\.PointField"]) add_introspection_rules([], ["^chimere\.widgets\.SelectMultipleField"]) add_introspection_rules([], ["^chimere\.widgets\.RouteField"])