Ticket #9806: 9806.5.diff

File 9806.5.diff, 16.6 KB (added by Paul Winkler, 13 years ago)

patch that allows adding as well as editing geometries in admin UI for GeometryField

  • django/contrib/gis/admin/options.py

     
    3737    wms_url = 'http://labs.metacarta.com/wms/vmap0'
    3838    wms_layer = 'basic'
    3939    wms_name = 'OpenLayers WMS'
     40    wms_options = {'format': 'image/jpg'}
     41
    4042    debug = False
    4143    widget = OpenLayersWidget
    4244
     
    6769        in the `widget` attribute) using the settings from the attributes set
    6870        in this class.
    6971        """
    70         is_collection = db_field.geom_type in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION')
    71         if is_collection:
    72             if db_field.geom_type == 'GEOMETRYCOLLECTION': collection_type = 'Any'
    73             else: collection_type = OGRGeomType(db_field.geom_type.replace('MULTI', ''))
     72        is_unknown = db_field.geom_type in ('GEOMETRY',)
     73        if not is_unknown:
     74            #If it is not generic, get the parameters from the db_field
     75            is_collection = db_field.geom_type in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION')
     76            if is_collection:
     77                if db_field.geom_type == 'GEOMETRYCOLLECTION': collection_type = 'Any'
     78                else: collection_type = OGRGeomType(db_field.geom_type.upper().replace('MULTI', ''))
     79            else:
     80                collection_type = 'None'
     81            is_linestring = db_field.geom_type in ('LINESTRING', 'MULTILINESTRING')
     82            is_polygon = db_field.geom_type in ('POLYGON', 'MULTIPOLYGON')
     83            is_point = db_field.geom_type in ('POINT', 'MULTIPOINT')
     84            geom_type = OGRGeomType(db_field.geom_type)
    7485        else:
     86            #If it is generic, set sensible defaults
     87            is_collection = False
    7588            collection_type = 'None'
     89            is_linestring = False
     90            is_polygon = False
     91            is_point = False
     92            geom_type = OGRGeomType('Unknown')
    7693
    7794        class OLMap(self.widget):
    7895            template = self.map_template
    7996            geom_type = db_field.geom_type
     97            wms_options = ''
     98            if self.wms_options:
     99                wms_options = ["%s: '%s'" % pair for pair in self.wms_options.items()]
     100                wms_options = ', '.join(wms_options)
     101                wms_options = ', ' + wms_options
     102
    80103            params = {'default_lon' : self.default_lon,
     104                      'collection_type' : collection_type,
     105                      'debug' : self.debug,
    81106                      'default_lat' : self.default_lat,
    82107                      'default_zoom' : self.default_zoom,
     108                      'display_srid' : self.display_srid,
    83109                      'display_wkt' : self.debug or self.display_wkt,
    84                       'geom_type' : OGRGeomType(db_field.geom_type),
    85110                      'field_name' : db_field.name,
     111                      'geom_type' : geom_type,
    86112                      'is_collection' : is_collection,
    87                       'scrollable' : self.scrollable,
     113                      'is_linestring' : is_linestring,
     114                      'is_point' : is_point,
     115                      'is_polygon' : is_polygon,
     116                      'is_unknown': is_unknown,
    88117                      'layerswitcher' : self.layerswitcher,
    89                       'collection_type' : collection_type,
    90                       'is_linestring' : db_field.geom_type in ('LINESTRING', 'MULTILINESTRING'),
    91                       'is_polygon' : db_field.geom_type in ('POLYGON', 'MULTIPOLYGON'),
    92                       'is_point' : db_field.geom_type in ('POINT', 'MULTIPOINT'),
    93                       'num_zoom' : self.num_zoom,
     118                      'map_height' : self.map_height,
     119                      'map_width' : self.map_width,
     120                      'max_extent' : self.max_extent,
     121                      'max_resolution' : self.max_resolution,
    94122                      'max_zoom' : self.max_zoom,
    95123                      'min_zoom' : self.min_zoom,
    96                       'units' : self.units, #likely shoud get from object
    97                       'max_resolution' : self.max_resolution,
    98                       'max_extent' : self.max_extent,
    99124                      'modifiable' : self.modifiable,
    100125                      'mouse_position' : self.mouse_position,
     126                      'num_zoom' : self.num_zoom,
     127                      'openlayers_url': self.openlayers_url,
     128                      'openlayers_img_path': self.openlayers_img_path,
     129                      'point_zoom' : self.point_zoom,
    101130                      'scale_text' : self.scale_text,
    102                       'map_width' : self.map_width,
    103                       'map_height' : self.map_height,
    104                       'point_zoom' : self.point_zoom,
     131                      'scrollable' : self.scrollable,
    105132                      'srid' : self.map_srid,
    106                       'display_srid' : self.display_srid,
    107                       'wms_url' : self.wms_url,
     133                      'units' : self.units, #likely shoud get from object
    108134                      'wms_layer' : self.wms_layer,
    109135                      'wms_name' : self.wms_name,
    110                       'debug' : self.debug,
     136                      'wms_options': wms_options,
     137                      'wms_url' : self.wms_url,
    111138                      }
    112139        return OLMap
    113140
  • django/contrib/gis/admin/widgets.py

     
    11from django.conf import settings
    22from django.contrib.gis.gdal import OGRException
     3from django.contrib.gis.gdal import OGRGeomType
    34from django.contrib.gis.geos import GEOSGeometry, GEOSException
    45from django.forms.widgets import Textarea
    56from django.template import loader, Context
     
    1516    """
    1617    Renders an OpenLayers map using the WKT of the geometry.
    1718    """
     19
    1820    def render(self, name, value, attrs=None):
    1921        # Update the template parameters with any attributes passed in.
    20         if attrs: self.params.update(attrs)
     22        # If value is None, that means we haven't saved anything yet.
     23        if attrs:
     24            self.params.update(attrs)
    2125
    2226        # Defaulting the WKT value to a blank string -- this
    2327        # will be tested in the JavaScript and the appropriate
     
    3135                value = GEOSGeometry(value)
    3236            except (GEOSException, ValueError):
    3337                value = None
    34 
    35         if value and value.geom_type.upper() != self.geom_type:
     38        if value and value.geom_type.upper() != self.geom_type and self.geom_type != 'GEOMETRY':
    3639            value = None
    3740
    3841        # Constructing the dictionary of the map options.
     
    6568            # geometry.
    6669            self.params['wkt'] = wkt
    6770
     71            # Check if the field is generic so the proper values are overriden
     72            if self.params['is_unknown']:
     73                self.params['geom_type'] = OGRGeomType(value.geom_type)
     74                if value.geom_type.upper() in ('LINESTRING', 'MULTILINESTRING'):
     75                    self.params['is_linestring'] = True
     76                elif value.geom_type.upper() in ('POLYGON', 'MULTIPOLYGON'):
     77                    self.params['is_polygon'] = True
     78                elif value.geom_type.upper() in ('POINT', 'MULTIPOINT'):
     79                    self.params['is_point'] = True
     80                elif value.geom_type.upper() in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON'):
     81                    self.params['is_collection'] = True
     82                    self.params['collection_type'] = OGRGeomType(value.geom_type.upper().replace('MULTI', ''))
     83                elif value.geom_type.upper() == 'GEOMETRYCOLLECTION':
     84                    self.params['is_collection'] = True
     85                    self.params['collection_type'] = 'Any'
     86                    self.params['geom_type'] = 'Collection'
     87
     88
     89        else:
     90            if self.params['is_unknown']:
     91                # If the geometry is unknown and the value is not set,
     92                # make it as flexible as possible.
     93                self.params['geom_type'] = 'Collection'
     94                self.params['is_collection']=True
     95                self.params['collection_type'] = 'Any'
     96
     97        # If we don't already have a camelcase geom_type,
     98        # make one using str(OGRGeomType).
     99        # Works for most things but not 'GeometryCollection'.
     100        if str(self.params['geom_type']) == str(self.params['geom_type']).upper():
     101            self.params['geom_type'] = str(OGRGeomType(self.params['geom_type']))
    68102        return loader.render_to_string(self.template, self.params,
    69103                                       context_instance=geo_context)
    70104
  • django/contrib/gis/templates/gis/admin/openlayers.js

     
    11{# Author: Justin Bronn, Travis Pinney & Dane Springmeyer #}
    22{% block vars %}var {{ module }} = {};
     3{% if openlayers_img_path %}OpenLayers.ImgPath = '{{ openlayers_img_path }}';{% endif %}
    34{{ module }}.map = null; {{ module }}.controls = null; {{ module }}.panel = null; {{ module }}.re = new RegExp("^SRID=\d+;(.+)", "i"); {{ module }}.layers = {};
    45{{ module }}.modifiable = {{ modifiable|yesno:"true,false" }};
    56{{ module }}.wkt_f = new OpenLayers.Format.WKT();
     
    910{{ module }}.is_polygon = {{ is_polygon|yesno:"true,false" }};
    1011{{ module }}.is_point = {{ is_point|yesno:"true,false" }};
    1112{% endblock %}
    12 {{ module }}.get_ewkt = function(feat){return 'SRID={{ srid }};' + {{ module }}.wkt_f.write(feat);}
     13{{ module }}.get_ewkt = function(feat){
     14  return 'SRID={{ srid }};' + {{ module }}.wkt_f.write(feat);
     15};
    1316{{ module }}.read_wkt = function(wkt){
    1417  // OpenLayers cannot handle EWKT -- we make sure to strip it out.
    1518  // EWKT is only exposed to OL if there's a validation error in the admin.
    1619  var match = {{ module }}.re.exec(wkt);
    1720  if (match){wkt = match[1];}
    1821  return {{ module }}.wkt_f.read(wkt);
    19 }
     22};
    2023{{ module }}.write_wkt = function(feat){
    21   if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}
    22   else { {{ module }}.num_geom = 1;}
     24  if ({{ module }}.is_collection){
     25    {{ module }}.num_geom = feat.length;
     26  } else {
     27    {{ module }}.num_geom = 1;
     28  };
    2329  document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);
    24 }
     30};
    2531{{ module }}.add_wkt = function(event){
    2632  // This function will sync the contents of the `vector` layer with the
    2733  // WKT in the text field.
     
    4046    }
    4147    {{ module }}.write_wkt(event.feature);
    4248  }
    43 }
     49};
    4450{{ module }}.modify_wkt = function(event){
    4551  if ({{ module }}.is_collection){
    4652    if ({{ module }}.is_point){
     
    5864  } else {
    5965    {{ module }}.write_wkt(event.feature);
    6066  }
    61 }
     67};
    6268// Function to clear vector features and purge wkt from div
    6369{{ module }}.deleteFeatures = function(){
    6470  {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);
     
    6874  {{ module }}.deleteFeatures();
    6975  document.getElementById('{{ id }}').value = '';
    7076  {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
    71 }
     77};
    7278// Add Select control
    7379{{ module }}.addSelectControl = function(){
    7480  var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});
    7581  {{ module }}.map.addControl(select);
    7682  select.activate();
    77 }
    78 {{ module }}.enableDrawing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();}
    79 {{ module }}.enableEditing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();}
     83};
     84{{ module }}.enableDrawing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();};
     85{{ module }}.enableEditing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();};
    8086// Create an array of controls based on geometry type
    8187{{ module }}.getControls = function(lyr){
    8288  {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});
    83   var nav = new OpenLayers.Control.Navigation();
     89  var nav = new OpenLayers.Control.Navigation({'title': 'Navigate'});
    8490  var draw_ctl;
    8591  if ({{ module }}.is_linestring){
    86     draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'});
     92    draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath', 'title': 'Draw Lines'});
    8793  } else if ({{ module }}.is_polygon){
    88     draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'});
     94    draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon', 'title': 'Draw Polygons'});
    8995  } else if ({{ module }}.is_point){
    90     draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'});
    91   }
     96    draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint', 'title': 'Draw Points'});
     97  };
     98  /* if is_collection==true and collection_type=='Any', we should
     99   * provide a widget that allows choosing the type of feature to
     100   * add... but that'd take a lot more work. Possible example to draw
     101   * on: http://openlayers.org/dev/examples/snapping.html
     102   * For now, just assume we want MultiPolygons.
     103   */
     104  if (draw_ctl == undefined) {
     105    draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon', 'title': 'Draw Polygons'});
     106  };
     107  if ({{module}}.is_collection )  {
     108      draw_ctl.multi = true;
     109  };
    92110  if ({{ module }}.modifiable){
    93     var mod = new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'});
     111    var mod = new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature', 'title': 'Modify'});
    94112    {{ module }}.controls = [nav, draw_ctl, mod];
    95113  } else {
    96114    if(!lyr.features.length){
     
    99117      {{ module }}.controls = [nav];
    100118    }
    101119  }
    102 }
     120};
    103121{{ module }}.init = function(){
    104122    {% block map_options %}// The options hash, w/ zoom, resolution, and projection settings.
    105123    var options = {
     
    108126    // The admin map for this geometry field.
    109127    {{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
    110128    // Base Layer
    111     {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS( "{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'} );{% endblock %}
     129    {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS( "{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}' {{ wms_options|safe }} } );{% endblock %}
    112130    {{ module }}.map.addLayer({{ module }}.layers.base);
    113131    {% block extra_layers %}{% endblock %}
    114132    {% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
     
    121139      // WKT <textarea> as EWKT (so that SRID is included).
    122140      var admin_geom = {{ module }}.read_wkt(wkt);
    123141      {{ module }}.write_wkt(admin_geom);
    124       if ({{ module }}.is_collection){
    125         // If geometry collection, add each component individually so they may be
    126         // edited individually.
    127         for (var i = 0; i < {{ module }}.num_geom; i++){
    128           {{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);
    129         }
     142      var bounds;
     143      if ({{ module }}.is_collection) {
     144        {{ module }}.layers.vector.addFeatures(admin_geom);
     145        bounds = admin_geom[0].geometry.getBounds();
     146        for (var i = 1; i < admin_geom.length; i++ ) {
     147          bounds.extend(admin_geom[i].geometry.getBounds());
     148        };
    130149      } else {
    131150        {{ module }}.layers.vector.addFeatures([admin_geom]);
    132       }
    133       // Zooming to the bounds.
    134       {{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());
     151        bounds = admin_geom.geometry.getBounds();
     152      };
     153      {{ module }}.map.zoomToExtent(bounds);
    135154      if ({{ module }}.is_point){
    136155          {{ module }}.map.zoomTo({{ point_zoom }});
    137       }
     156      };
    138157    } else {
    139158      {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
    140159    }
     
    164183    } else {
    165184      {{ module }}.enableDrawing();
    166185    }
    167 }
     186};
Back to Top