diff options
author | etienne <etienne@9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864> | 2009-01-11 13:16:21 +0000 |
---|---|---|
committer | etienne <etienne@9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864> | 2009-01-11 13:16:21 +0000 |
commit | 03c7e15227fb84b94d9f870aac69d7d54b61889a (patch) | |
tree | c7d4c5e276fd3092449c195b8c354f7ebe645979 | |
parent | 4182d638dcbe194b65b38d1ae92068dadbefc84d (diff) | |
download | Chimère-03c7e15227fb84b94d9f870aac69d7d54b61889a.tar.bz2 Chimère-03c7e15227fb84b94d9f870aac69d7d54b61889a.zip |
Modification of created routes
git-svn-id: http://www.peacefrogs.net/svn/chimere/trunk@9 9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864
-rw-r--r-- | main/actions.py | 3 | ||||
-rw-r--r-- | main/admin.py | 15 | ||||
-rw-r--r-- | main/forms.py | 70 | ||||
-rw-r--r-- | main/models.py | 74 | ||||
-rw-r--r-- | main/views.py | 41 | ||||
-rw-r--r-- | main/widgets.py | 81 | ||||
-rw-r--r-- | static/forms.css | 40 | ||||
-rw-r--r-- | static/styles.css | 5 | ||||
-rw-r--r-- | urls.py | 1 |
9 files changed, 319 insertions, 11 deletions
diff --git a/main/actions.py b/main/actions.py index d47a323..a4bf06d 100644 --- a/main/actions.py +++ b/main/actions.py @@ -29,4 +29,5 @@ class Action: def __init__(self, id, path, label): self.id, self.path, self.label = id, main_path + path, label -actions = [Action('view', '', _('View')), Action('edit', 'edit', _('Add'))] +actions = [Action('view', '', _('View')), Action('edit', 'edit', _('Add')), + Action('edit-route', 'edit-route', _('Add route'))] diff --git a/main/admin.py b/main/admin.py index 7e19e4b..21ba3cb 100644 --- a/main/admin.py +++ b/main/admin.py @@ -22,8 +22,8 @@ Settings for administration pages """ from chimere.main.models import Category, Icon, SubCategory, Marker, \ - PropertyModel, Property, News -from chimere.main.forms import MarkerAdminForm + PropertyModel, Property, News, Route +from chimere.main.forms import MarkerAdminForm, RouteAdminForm from django.contrib import admin class MarkerAdmin(admin.ModelAdmin): @@ -35,6 +35,16 @@ class MarkerAdmin(admin.ModelAdmin): list_filter = ('status', 'subcategory') form = MarkerAdminForm + +class RouteAdmin(admin.ModelAdmin): + """ + Specialized the Route field. + """ + search_fields = ("name",) + list_display = ('name', 'subcategory', 'status') + list_filter = ('status', 'subcategory') + form = RouteAdminForm + class SubCategoryAdmin(admin.ModelAdmin): """ Specialized the subcategory admin @@ -48,5 +58,6 @@ admin.site.register(Icon) admin.site.register(Category) admin.site.register(SubCategory, SubCategoryAdmin) admin.site.register(Marker, MarkerAdmin) +admin.site.register(Route, RouteAdmin) admin.site.register(PropertyModel) admin.site.register(Property) diff --git a/main/forms.py b/main/forms.py index cb45edc..2343869 100644 --- a/main/forms.py +++ b/main/forms.py @@ -23,7 +23,7 @@ Forms from django import forms from django.contrib.gis.db import models -from chimere.main.models import Marker, PropertyModel, Property +from chimere.main.models import Marker, Route, PropertyModel, Property class MarkerAdminForm(forms.ModelForm): """ @@ -92,3 +92,71 @@ class MarkerForm(MarkerAdminForm): class Meta: model = Marker exclude = ('status',) + +class RouteAdminForm(forms.ModelForm): + """ + Main form for route + """ + # declare properties + for property in PropertyModel.objects.filter(available=True): + exec('property_%d_%d = forms.CharField(label="%s", widget=forms.%s, \ +required=False)' % (property.order, property.id, property.name, + PropertyModel.TYPE_WIDGET[property.type])) + class Meta: + model = Route + + def __init__(self, *args, **keys): + """ + Custom initialization method in order to manage properties + """ + if 'instance' in keys and keys['instance']: + instance = keys['instance'] + property_dct = {} + for pm in PropertyModel.objects.filter(available=True): + property = instance.getProperty(pm) + if property: + property_dct[pm.getNamedId()] = property.value + if 'initial' in keys: + keys['initial'].update(property_dct) + else: + keys['initial'] = property_dct + super(RouteAdminForm, self).__init__(*args, **keys) + + def save(self, *args, **keys): + """ + Custom save method in order to manage associeted properties + """ + new_marker = super(RouteAdminForm, self).save(*args, **keys) + if 'status' not in self.cleaned_data: + new_marker.status = 'S' + new_marker.save() + # save each property + for propertymodel in PropertyModel.objects.filter(available=True): + properties = Property.objects.filter(marker=new_marker, + propertymodel=propertymodel) + # new property + if not properties: + new_property = Property.objects.create(marker=new_marker, + propertymodel=propertymodel, + value=self.cleaned_data['property_%d_%d' % ( + propertymodel.order, propertymodel.id)]) + new_property.save() + else: + # in case of multiple edition as the same time delete arbitrary + # the others + if len(properties) > 1: + for property in properties[1:]: + property.delete() + property = properties[0] + property.value = self.cleaned_data['property_%d_%d' % ( + propertymodel.order, propertymodel.id)] + property.save() + return new_marker + +class RouteForm(RouteAdminForm): + """ + Form for the edit page + """ + class Meta: + model = Route + exclude = ('status',) diff --git a/main/models.py b/main/models.py index f449d09..ead8a85 100644 --- a/main/models.py +++ b/main/models.py @@ -26,7 +26,7 @@ from django.contrib.gis.db import models from django.contrib import admin from chimere import settings -from chimere.main.widgets import PointField +from chimere.main.widgets import PointField, RouteField class News(models.Model): @@ -163,6 +163,78 @@ class Marker(models.Model): 'icon_width':self.subcategory.icon.image.width, 'icon_height':self.subcategory.icon.image.height,} +class Route(models.Model): + '''Route on the map + ''' + name = models.CharField(_("Name"), max_length=150) + subcategory = models.ForeignKey(SubCategory, verbose_name=_("Subcategory")) + route = RouteField(_("Route")) + picture = models.ImageField(_("Image"), upload_to='upload', blank=True, + height_field='height', width_field='width') + STATUS = (('S', _('Submited')), + ('A', _('Available')), + ('D', _('Disabled')),) + STATUS_DCT = {} + for key, label in STATUS: + STATUS_DCT[key] = label + status = models.CharField(_("Status"), max_length=1, choices=STATUS) + objects = models.GeoManager() + + def __unicode__(self): + return self.name + + class Meta: + ordering = ('subcategory__category', 'subcategory', 'status', 'name') + verbose_name = _("Route") + + def getLatitude(self): + '''Return the latitude + ''' + return self.point.y + + def getLongitude(self): + '''Return the longitude + ''' + return self.point.x + + def getProperty(self, propertymodel, safe=None): + """Get the property of an associated property model. + If safe set to True, verify if the property is available + """ + if safe and not propertymodel.available: + return + try: + property = Property.objects.get(propertymodel=propertymodel, + marker=self) + except Property.DoesNotExist: + return + return property + + def getProperties(self): + """Get all the property availables + """ + properties = [] + for pm in PropertyModel.objects.filter(available=True): + property = self.getProperty(pm) + if property: + properties.append(property) + return properties + + def getGeoJSON(self): + '''Return a GeoJSON string + ''' + return """{"type":"Feature", "geometry":{"type":"Point", \ +"crs": "EPSG:%(epsg)d", "coordinates":[%(longitude)s, %(latitude)s]}, \ +"properties":{"pk": %(id)d, "name": "%(name)s", \ +"icon_path":"%(icon_path)s", "icon_width":%(icon_width)d, \ +"icon_height":%(icon_height)d}}""" % {'id':self.id, 'name':self.name, +'icon_path':self.subcategory.icon.image, 'latitude':self.getLatitude(), +'longitude':self.getLongitude(), 'epsg':settings.EPSG_PROJECTION, +'icon_width':self.subcategory.icon.image.width, +'icon_height':self.subcategory.icon.image.height,} + + + class PropertyModel(models.Model): '''Model for a property ''' diff --git a/main/views.py b/main/views.py index d655aad..f0cc604 100644 --- a/main/views.py +++ b/main/views.py @@ -30,9 +30,10 @@ from django.core import serializers from chimere import settings from chimere.main.actions import actions -from chimere.main.models import SubCategory, PropertyModel, Marker, News -from chimere.main.widgets import getMapJS, PointChooserWidget, URL_OSM_JS -from chimere.main.forms import MarkerForm +from chimere.main.models import SubCategory, PropertyModel, Marker, Route, News +from chimere.main.widgets import getMapJS, PointChooserWidget, \ + RouteChooserWidget, URL_OSM_JS +from chimere.main.forms import MarkerForm, RouteForm def index(request): """ @@ -96,6 +97,40 @@ def edit(request): response_dct['current_category'] = int(form.data['subcategory']) return render_to_response('edit.html', response_dct) +def editRoute(request): + """ + Route edition page + """ + # If the form has been submited + if request.method == 'POST': + form = RouteForm(request.POST, request.FILES) + print request.POST + # All validation rules pass + if form.is_valid(): + route = form.save() + # set the submited status + route.status = 'S' + route.save() + return HttpResponseRedirect('/chimere/submited') + else: + # An unbound form + form = RouteForm() + # get the « manualy » declared_fields. Ie: properties + declared_fields = form.declared_fields.keys() + response_dct = {'actions':actions, 'action_selected':'edit-route', + 'error_message':'', + 'media_path':settings.MEDIA_URL, + 'form':form, + 'extra_head':form.media, + 'sub_categories':SubCategory.getAvailable(), + 'route_widget':RouteChooserWidget().render('route', None), + 'properties':declared_fields + } + # manualy populate the custom widget + if 'subcategory' in form.data and form.data['subcategory']: + response_dct['current_category'] = int(form.data['subcategory']) + return render_to_response('edit_route.html', response_dct) + def welcome(request, display=None): """ Welcome string diff --git a/main/widgets.py b/main/widgets.py index bd0a72b..1e12c19 100644 --- a/main/widgets.py +++ b/main/widgets.py @@ -23,7 +23,7 @@ Extra widgets and fields from django import forms from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from chimere import settings from django.contrib.gis.db import models @@ -112,3 +112,82 @@ class PointField(models.PointField): defaults = {'widget': PointChooserWidget} keys.update(defaults) return super(PointField, self).formfield(**keys) + +class RouteChooserWidget(forms.TextInput): + """ + Manage the edition of route on a map + """ + class Media: + css = { + "all": ("%sforms.css" % settings.MEDIA_URL,) + } + js = ["%sedit_route_map.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 = """<h3>%s</h3> +<p>%s</p> +<p>%s</p> +<p>%s</p> +<p>%s</p> +<p>%s</p>""" % (_("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 = """<h3>%s</h3> +<p>%s</p> +<p>%s</p> +<p>%s</p>""" % (_("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'<script src="%sedit_route_map.js"></script>\n' % \ + settings.MEDIA_URL + if not value: + tpl += u"""<div id='draw-toggle-off' class='toggle-button' \ +onclick='toggleDrawOn();'>%s</div> +<div id='draw-toggle-on' class='toggle-button' \ +onclick='toggleDrawOff();'>%s</div> +<hr class='spacer'/>""" % (_("Start drawing"), _("Stop drawing")) + tpl += """ +<div id='map_edit'></div>""" + if not value: + tpl += ''' +<div class='help-route' id='help-route-create'>%s</div>''' % help_create + style = '' + if value: + style = " style='display:block'" + tpl += """ +<div class='help-route' id='help-route-modify'%s>%s</div> +<hr class='spacer'/> +<input type='hidden' name='%s' id='id_%s' value="%s"/> +""" % (style, help_modify, name, name, value) + tpl += """<script type='text/javascript'><!-- +init();""" + if value: + tpl += """ +var geometry='%s'; +initFeature(geometry);""" % value.json + tpl += """ +// --></script> +""" + 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) diff --git a/static/forms.css b/static/forms.css index e536e96..c8e4939 100644 --- a/static/forms.css +++ b/static/forms.css @@ -8,4 +8,42 @@ float:left; #live_lonlat{ margin:1em; float:left; -}
\ No newline at end of file +} + +.toggle-button{ +float:left; +padding:4px; +-moz-border-radius: 4px; +-webkit-border-radius: 4px; +border-radius: 4px; +border:1px solid grey; +} + +#draw-toggle-off{ +color:black; +} + +#draw-toggle-on{ +background-color:lightgrey; +display:None; +} + +.help-route{ +width:700px; +background-color:#EEF;; +margin: 10px 0px; +float:left; +padding:0 4px; +-moz-border-radius: 4px; +-webkit-border-radius: 4px; +border-radius: 4px; +border:1px solid grey; +} + +#help-route-create{ +} + +#help-route-modify{ +display:None +} + diff --git a/static/styles.css b/static/styles.css index 28af34c..fda1fa9 100644 --- a/static/styles.css +++ b/static/styles.css @@ -41,6 +41,7 @@ color:purple; hr.spacer{ clear:both; border:None; +visibility: hidden; } .edit label{ @@ -120,7 +121,7 @@ z-index:5; top:50px; bottom:58px; left:80px; -right:360px; +margin-right:360px; background-color:#FFF; opacity:0.9; -moz-border-radius:10px; @@ -170,6 +171,8 @@ border: 1px solid black; margin:0px; padding:0px; height:92%; +margin:0; +padding:0; top:40px; bottom:8px; left:8px; @@ -13,6 +13,7 @@ urlpatterns = patterns('', (r'^chimere/admin/(.*)', admin.site.root), (r'^chimere/$', 'chimere.main.views.index'), (r'^chimere/edit/$', 'chimere.main.views.edit'), + (r'^chimere/edit-route/$', 'chimere.main.views.editRoute'), (r'^chimere/submited/$', 'chimere.main.views.submited'), (r'^chimere/getDetail/(?P<marker_id>\d+)/$', 'chimere.main.views.getDetail'), |