15 # |
15 # |
16 # You should have received a copy of the GNU Lesser General Public License along |
16 # You should have received a copy of the GNU Lesser General Public License along |
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
18 """Specific views for entities implementing IGeocodable""" |
18 """Specific views for entities implementing IGeocodable""" |
19 |
19 |
20 __docformat__ = "restructuredtext en" |
20 try: |
|
21 from cubes.geocoding.views import (IGeocodableAdapter, |
|
22 GeocodingJsonView, |
|
23 GoogleMapBubbleView, |
|
24 GoogleMapsView, |
|
25 GoogeMapsLegend) |
21 |
26 |
22 from cubicweb.interfaces import IGeocodable |
27 from logilab.common.deprecation import class_moved |
23 from cubicweb.view import EntityView, EntityAdapter, implements_adapter_compat |
|
24 from cubicweb.predicates import implements, adaptable |
|
25 from cubicweb.utils import json_dumps |
|
26 |
28 |
27 class IGeocodableAdapter(EntityAdapter): |
29 msg = '[3.17] cubicweb.web.views.igeocodable moved to cubes.geocoding.views' |
28 """interface required by geocoding views such as gmap-view""" |
30 IGeocodableAdapter = class_moved(IGeocodableAdapter, message=msg) |
29 __needs_bw_compat__ = True |
31 GeocodingJsonView = class_moved(GeocodingJsonView, message=msg) |
30 __regid__ = 'IGeocodable' |
32 GoogleMapBubbleView = class_moved(GoogleMapBubbleView, message=msg) |
31 __select__ = implements(IGeocodable, warn=False) # XXX for bw compat, should be abstract |
33 GoogleMapsView = class_moved(GoogleMapsView, message=msg) |
32 |
34 GoogeMapsLegend = class_moved(GoogeMapsLegend, message=msg) |
33 @property |
35 except ImportError: |
34 @implements_adapter_compat('IGeocodable') |
36 from cubicweb.web import LOGGER |
35 def latitude(self): |
37 LOGGER.warning('[3.17] igeocoding extracted to cube geocoding that was not found. try installing it.') |
36 """returns the latitude of the entity in degree (-90 < float < +90)""" |
|
37 raise NotImplementedError |
|
38 |
|
39 @property |
|
40 @implements_adapter_compat('IGeocodable') |
|
41 def longitude(self): |
|
42 """returns the longitude of the entity in degree (-180 < float < +180)""" |
|
43 raise NotImplementedError |
|
44 |
|
45 @implements_adapter_compat('IGeocodable') |
|
46 def marker_icon(self): |
|
47 """returns the icon that should be used as the marker. |
|
48 |
|
49 an icon is defined by a 4-uple: |
|
50 |
|
51 (icon._url, icon.size, icon.iconAnchor, icon.shadow) |
|
52 """ |
|
53 return (self._cw.uiprops['GMARKER_ICON'], (20, 34), (4, 34), None) |
|
54 |
|
55 |
|
56 class GeocodingJsonView(EntityView): |
|
57 __regid__ = 'geocoding-json' |
|
58 __select__ = adaptable('IGeocodable') |
|
59 |
|
60 binary = True |
|
61 templatable = False |
|
62 content_type = 'application/json' |
|
63 |
|
64 def call(self): |
|
65 zoomlevel = self._cw.form.pop('zoomlevel', None) |
|
66 extraparams = self._cw.form.copy() |
|
67 extraparams.pop('vid', None) |
|
68 extraparams.pop('rql', None) |
|
69 markers = [] |
|
70 for entity in self.cw_rset.entities(): |
|
71 igeocodable = entity.cw_adapt_to('IGeocodable') |
|
72 # remove entities that don't define latitude and longitude |
|
73 if not (igeocodable.latitude and igeocodable.longitude): |
|
74 continue |
|
75 markers.append(self.build_marker_data(entity, igeocodable, |
|
76 extraparams)) |
|
77 if not markers: |
|
78 return |
|
79 geodata = { |
|
80 'markers': markers, |
|
81 } |
|
82 if zoomlevel: |
|
83 geodata['zoomlevel'] = int(zoomlevel) |
|
84 self.w(json_dumps(geodata)) |
|
85 |
|
86 def build_marker_data(self, entity, igeocodable, extraparams): |
|
87 return {'latitude': igeocodable.latitude, |
|
88 'longitude': igeocodable.longitude, |
|
89 'icon': igeocodable.marker_icon(), |
|
90 'title': entity.dc_long_title(), |
|
91 'bubbleUrl': entity.absolute_url( |
|
92 vid='gmap-bubble', __notemplate=1, **extraparams), |
|
93 } |
|
94 |
|
95 |
|
96 class GoogleMapBubbleView(EntityView): |
|
97 __regid__ = 'gmap-bubble' |
|
98 __select__ = adaptable('IGeocodable') |
|
99 |
|
100 def cell_call(self, row, col): |
|
101 entity = self.cw_rset.get_entity(row, col) |
|
102 self.w(u'<div>%s</div>' % entity.view('oneline')) |
|
103 # FIXME: we should call something like address-view if available |
|
104 |
|
105 |
|
106 class GoogleMapsView(EntityView): |
|
107 __regid__ = 'gmap-view' |
|
108 __select__ = adaptable('IGeocodable') |
|
109 |
|
110 paginable = False |
|
111 |
|
112 def call(self, gmap_key, width=400, height=400, uselabel=True, urlparams=None): |
|
113 self._cw.demote_to_html() |
|
114 self._cw.add_js('http://maps.google.com/maps?sensor=false&file=api&v=2&key=%s' |
|
115 % gmap_key, localfile=False) |
|
116 self._cw.add_js( ('cubicweb.widgets.js', 'cubicweb.gmap.js', 'gmap.utility.labeledmarker.js') ) |
|
117 rql = self.cw_rset.printable_rql() |
|
118 if urlparams is None: |
|
119 loadurl = self._cw.build_url(rql=rql, vid='geocoding-json') |
|
120 else: |
|
121 loadurl = self._cw.build_url(rql=rql, vid='geocoding-json', **urlparams) |
|
122 self.w(u'<div style="width: %spx; height: %spx;" class="widget gmap" ' |
|
123 u'cubicweb:wdgtype="GMapWidget" cubicweb:loadtype="auto" ' |
|
124 u'cubicweb:loadurl="%s" cubicweb:uselabel="%s"> </div>' |
|
125 % (width, height, loadurl, uselabel)) |
|
126 |
|
127 |
|
128 class GoogeMapsLegend(EntityView): |
|
129 __regid__ = 'gmap-legend' |
|
130 |
|
131 def call(self): |
|
132 self.w(u'<ol>') |
|
133 for rowidx in xrange(len(self.cw_rset)): |
|
134 self.w(u'<li>') |
|
135 self.wview('listitem', self.cw_rset, row=rowidx, col=0) |
|
136 self.w(u'</li>') |
|
137 self.w(u'</ol>') |
|