web/views/igeocodable.py
changeset 5556 9ab2b4c74baf
parent 5467 57372dbfd114
child 5877 0c7b7b76a84f
--- a/web/views/igeocodable.py	Thu May 20 20:47:13 2010 +0200
+++ b/web/views/igeocodable.py	Thu May 20 20:47:55 2010 +0200
@@ -21,27 +21,59 @@
 __docformat__ = "restructuredtext en"
 
 from cubicweb.interfaces import IGeocodable
-from cubicweb.view import EntityView
-from cubicweb.selectors import implements
+from cubicweb.view import EntityView, EntityAdapter, implements_adapter_compat
+from cubicweb.selectors import implements, adaptable
 from cubicweb.web import json
 
+class IGeocodableAdapter(EntityAdapter):
+    """interface required by geocoding views such as gmap-view"""
+    __regid__ = 'IGeocodable'
+    __select__ = implements(IGeocodable) # XXX for bw compat, should be abstract
+
+    @property
+    @implements_adapter_compat('IGeocodable')
+    def latitude(self):
+        """returns the latitude of the entity"""
+        raise NotImplementedError
+
+    @property
+    @implements_adapter_compat('IGeocodable')
+    def longitude(self):
+        """returns the longitude of the entity"""
+        raise NotImplementedError
+
+    @implements_adapter_compat('IGeocodable')
+    def marker_icon(self):
+        """returns the icon that should be used as the marker.
+
+        an icon is defined by a 4-uple:
+
+          (icon._url, icon.size,  icon.iconAnchor, icon.shadow)
+        """
+        return (self._cw.uiprops['GMARKER_ICON'], (20, 34), (4, 34), None)
+
+
 class GeocodingJsonView(EntityView):
     __regid__ = 'geocoding-json'
-    __select__ = implements(IGeocodable)
+    __select__ = adaptable('IGeocodable')
 
     binary = True
     templatable = False
     content_type = 'application/json'
 
     def call(self):
-        # remove entities that don't define latitude and longitude
-        self.cw_rset = self.cw_rset.filtered_rset(lambda e: e.latitude and e.longitude)
         zoomlevel = self._cw.form.pop('zoomlevel', 8)
         extraparams = self._cw.form.copy()
         extraparams.pop('vid', None)
         extraparams.pop('rql', None)
-        markers = [self.build_marker_data(rowidx, extraparams)
-                   for rowidx in xrange(len(self.cw_rset))]
+        markers = []
+        for entity in self.cw_rset.entities():
+            igeocodable = entity.cw_adapt_to('IGeocodable')
+            # remove entities that don't define latitude and longitude
+            if not (igeocodable.latitude and igeocodable.longitude):
+                continue
+            markers.append(self.build_marker_data(entity, igeocodable,
+                                                  extraparams))
         center = {
             'latitude': sum(marker['latitude'] for marker in markers) / len(markers),
             'longitude': sum(marker['longitude'] for marker in markers) / len(markers),
@@ -53,24 +85,19 @@
             }
         self.w(json.dumps(geodata))
 
-    def build_marker_data(self, row, extraparams):
-        entity = self.cw_rset.get_entity(row, 0)
-        icon = None
-        if hasattr(entity, 'marker_icon'):
-            icon = entity.marker_icon()
-        else:
-            icon = (self._cw.uiprops['GMARKER_ICON'], (20, 34), (4, 34), None)
-        return {'latitude': entity.latitude, 'longitude': entity.longitude,
+    def build_marker_data(self, entity, igeocodable, extraparams):
+        return {'latitude': igeocodable.latitude,
+                'longitude': igeocodable.longitude,
+                'icon': igeocodable.marker_icon(),
                 'title': entity.dc_long_title(),
-                #icon defines : (icon._url, icon.size,  icon.iconAncho', icon.shadow)
-                'icon': icon,
-                'bubbleUrl': entity.absolute_url(vid='gmap-bubble', __notemplate=1, **extraparams),
+                'bubbleUrl': entity.absolute_url(
+                    vid='gmap-bubble', __notemplate=1, **extraparams),
                 }
 
 
 class GoogleMapBubbleView(EntityView):
     __regid__ = 'gmap-bubble'
-    __select__ = implements(IGeocodable)
+    __select__ = adaptable('IGeocodable')
 
     def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
@@ -80,16 +107,14 @@
 
 class GoogleMapsView(EntityView):
     __regid__ = 'gmap-view'
-    __select__ = implements(IGeocodable)
+    __select__ = adaptable('IGeocodable')
 
     paginable = False
 
     def call(self, gmap_key, width=400, height=400, uselabel=True, urlparams=None):
         self._cw.demote_to_html()
-        # remove entities that don't define latitude and longitude
-        self.cw_rset = self.cw_rset.filtered_rset(lambda e: e.latitude and e.longitude)
-        self._cw.add_js('http://maps.google.com/maps?sensor=false&file=api&v=2&key=%s' % gmap_key,
-                        localfile=False)
+        self._cw.add_js('http://maps.google.com/maps?sensor=false&file=api&v=2&key=%s'
+                        % gmap_key, localfile=False)
         self._cw.add_js( ('cubicweb.widgets.js', 'cubicweb.gmap.js', 'gmap.utility.labeledmarker.js') )
         rql = self.cw_rset.printable_rql()
         if urlparams is None:
@@ -98,7 +123,8 @@
             loadurl = self._cw.build_url(rql=rql, vid='geocoding-json', **urlparams)
         self.w(u'<div style="width: %spx; height: %spx;" class="widget gmap" '
                u'cubicweb:wdgtype="GMapWidget" cubicweb:loadtype="auto" '
-               u'cubicweb:loadurl="%s" cubicweb:uselabel="%s"> </div>' % (width, height, loadurl, uselabel))
+               u'cubicweb:loadurl="%s" cubicweb:uselabel="%s"> </div>'
+               % (width, height, loadurl, uselabel))
 
 
 class GoogeMapsLegend(EntityView):