13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
14 # details. |
14 # details. |
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 IDownloadable |
18 """Specific views for entities adapting to IDownloadable""" |
19 |
19 |
20 """ |
|
21 __docformat__ = "restructuredtext en" |
20 __docformat__ = "restructuredtext en" |
22 _ = unicode |
21 _ = unicode |
23 |
22 |
24 from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape |
23 from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape |
25 |
24 |
26 from cubicweb.view import EntityView |
25 from cubicweb.view import EntityView |
27 from cubicweb.selectors import (one_line_rset, score_entity, |
26 from cubicweb.selectors import (one_line_rset, implements, match_context_prop, |
28 implements, match_context_prop) |
27 adaptable, has_mimetype) |
29 from cubicweb.interfaces import IDownloadable |
|
30 from cubicweb.mttransforms import ENGINE |
28 from cubicweb.mttransforms import ENGINE |
31 from cubicweb.web.box import EntityBoxTemplate |
29 from cubicweb.web.box import EntityBoxTemplate |
32 from cubicweb.web.views import primary, baseviews |
30 from cubicweb.web.views import primary, baseviews |
33 |
31 |
34 |
|
35 def is_image(entity): |
|
36 mt = entity.download_content_type() |
|
37 if not (mt and mt.startswith('image/')): |
|
38 return 0 |
|
39 return 1 |
|
40 |
32 |
41 def download_box(w, entity, title=None, label=None, footer=u''): |
33 def download_box(w, entity, title=None, label=None, footer=u''): |
42 req = entity._cw |
34 req = entity._cw |
43 w(u'<div class="sideBox">') |
35 w(u'<div class="sideBox">') |
44 if title is None: |
36 if title is None: |
45 title = req._('download') |
37 title = req._('download') |
46 w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>' |
38 w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>' |
47 % xml_escape(title)) |
39 % xml_escape(title)) |
48 w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">') |
40 w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">') |
49 w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>' |
41 w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>' |
50 % (xml_escape(entity.download_url()), |
42 % (xml_escape(entity.cw_adapt_to('IDownloadable').download_url()), |
51 req.uiprops['DOWNLOAD_ICON'], |
43 req.uiprops['DOWNLOAD_ICON'], |
52 _('download icon'), xml_escape(label or entity.dc_title()))) |
44 _('download icon'), xml_escape(label or entity.dc_title()))) |
53 w(u'%s</div>' % footer) |
45 w(u'%s</div>' % footer) |
54 w(u'</div></div>\n') |
46 w(u'</div></div>\n') |
55 |
47 |
56 |
48 |
57 class DownloadBox(EntityBoxTemplate): |
49 class DownloadBox(EntityBoxTemplate): |
58 __regid__ = 'download_box' |
50 __regid__ = 'download_box' |
59 # no download box for images |
51 # no download box for images |
60 # XXX primary_view selector ? |
52 # XXX primary_view selector ? |
61 __select__ = (one_line_rset() & implements(IDownloadable) & |
53 __select__ = (one_line_rset() & match_context_prop() |
62 match_context_prop() & ~score_entity(is_image)) |
54 & adaptable('IDownloadable') & ~has_mimetype('image/')) |
63 order = 10 |
55 order = 10 |
64 |
56 |
65 def cell_call(self, row, col, title=None, label=None, **kwargs): |
57 def cell_call(self, row, col, title=None, label=None, **kwargs): |
66 entity = self.cw_rset.get_entity(row, col) |
58 entity = self.cw_rset.get_entity(row, col) |
67 download_box(self.w, entity, title, label) |
59 download_box(self.w, entity, title, label) |
70 class DownloadView(EntityView): |
62 class DownloadView(EntityView): |
71 """this view is replacing the deprecated 'download' controller and allow |
63 """this view is replacing the deprecated 'download' controller and allow |
72 downloading of entities providing the necessary interface |
64 downloading of entities providing the necessary interface |
73 """ |
65 """ |
74 __regid__ = 'download' |
66 __regid__ = 'download' |
75 __select__ = one_line_rset() & implements(IDownloadable) |
67 __select__ = one_line_rset() & adaptable('IDownloadable') |
76 |
68 |
77 templatable = False |
69 templatable = False |
78 content_type = 'application/octet-stream' |
70 content_type = 'application/octet-stream' |
79 binary = True |
71 binary = True |
80 add_to_breadcrumbs = False |
72 add_to_breadcrumbs = False |
81 |
73 |
82 def set_request_content_type(self): |
74 def set_request_content_type(self): |
83 """overriden to set the correct filetype and filename""" |
75 """overriden to set the correct filetype and filename""" |
84 entity = self.cw_rset.complete_entity(0, 0) |
76 entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) |
85 encoding = entity.download_encoding() |
77 adapter = entity.cw_adapt_to('IDownloadable') |
|
78 encoding = adapter.download_encoding() |
86 if encoding in BINARY_ENCODINGS: |
79 if encoding in BINARY_ENCODINGS: |
87 contenttype = 'application/%s' % encoding |
80 contenttype = 'application/%s' % encoding |
88 encoding = None |
81 encoding = None |
89 else: |
82 else: |
90 contenttype = entity.download_content_type() |
83 contenttype = adapter.download_content_type() |
91 self._cw.set_content_type(contenttype or self.content_type, |
84 self._cw.set_content_type(contenttype or self.content_type, |
92 filename=entity.download_file_name(), |
85 filename=adapter.download_file_name(), |
93 encoding=encoding) |
86 encoding=encoding) |
94 |
87 |
95 def call(self): |
88 def call(self): |
96 self.w(self.cw_rset.complete_entity(0, 0).download_data()) |
89 entity = self.cw_rset.complete_entity(self.cw_row or 0, self.cw_col or 0) |
|
90 adapter = entity.cw_adapt_to('IDownloadable') |
|
91 self.w(adapter.download_data()) |
97 |
92 |
98 |
93 |
99 class DownloadLinkView(EntityView): |
94 class DownloadLinkView(EntityView): |
100 """view displaying a link to download the file""" |
95 """view displaying a link to download the file""" |
101 __regid__ = 'downloadlink' |
96 __regid__ = 'downloadlink' |
102 __select__ = implements(IDownloadable) |
97 __select__ = adaptable('IDownloadable') |
103 title = None # should not be listed in possible views |
98 title = None # should not be listed in possible views |
104 |
99 |
105 |
100 |
106 def cell_call(self, row, col, title=None, **kwargs): |
101 def cell_call(self, row, col, title=None, **kwargs): |
107 entity = self.cw_rset.get_entity(row, col) |
102 entity = self.cw_rset.get_entity(row, col) |
108 url = xml_escape(entity.download_url()) |
103 url = xml_escape(entity.cw_adapt_to('IDownloadable').download_url()) |
109 self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title()))) |
104 self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title()))) |
110 |
105 |
111 |
106 |
112 class IDownloadablePrimaryView(primary.PrimaryView): |
107 class IDownloadablePrimaryView(primary.PrimaryView): |
113 __select__ = implements(IDownloadable) |
108 __select__ = adaptable('IDownloadable') |
114 |
109 |
115 def render_entity_attributes(self, entity): |
110 def render_entity_attributes(self, entity): |
116 super(IDownloadablePrimaryView, self).render_entity_attributes(entity) |
111 super(IDownloadablePrimaryView, self).render_entity_attributes(entity) |
117 self.w(u'<div class="content">') |
112 self.w(u'<div class="content">') |
118 contenttype = entity.download_content_type() |
113 adapter = entity.cw_adapt_to('IDownloadable') |
|
114 contenttype = adapter.download_content_type() |
119 if contenttype.startswith('image/'): |
115 if contenttype.startswith('image/'): |
120 self.wview('image', entity.cw_rset, row=entity.cw_row) |
116 self.wview('image', entity.cw_rset, row=entity.cw_row) |
121 else: |
117 else: |
122 self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row) |
118 self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row) |
123 try: |
119 try: |
124 if ENGINE.has_input(contenttype): |
120 if ENGINE.has_input(contenttype): |
|
121 # XXX expect File like schema (access to 'data' attribute) |
125 self.w(entity.printable_value('data')) |
122 self.w(entity.printable_value('data')) |
126 except TransformError: |
123 except TransformError: |
127 pass |
124 pass |
128 except Exception, ex: |
125 except Exception, ex: |
129 msg = self._cw._("can't display data, unexpected error: %s") \ |
126 msg = self._cw._("can't display data, unexpected error: %s") \ |
131 self.w('<div class="error">%s</div>' % msg) |
128 self.w('<div class="error">%s</div>' % msg) |
132 self.w(u'</div>') |
129 self.w(u'</div>') |
133 |
130 |
134 |
131 |
135 class IDownloadableLineView(baseviews.OneLineView): |
132 class IDownloadableLineView(baseviews.OneLineView): |
136 __select__ = implements(IDownloadable) |
133 __select__ = adaptable('IDownloadable') |
137 |
134 |
138 def cell_call(self, row, col, title=None, **kwargs): |
135 def cell_call(self, row, col, title=None, **kwargs): |
139 """the oneline view is a link to download the file""" |
136 """the oneline view is a link to download the file""" |
140 entity = self.cw_rset.get_entity(row, col) |
137 entity = self.cw_rset.get_entity(row, col) |
141 url = xml_escape(entity.absolute_url()) |
138 url = xml_escape(entity.absolute_url()) |
142 name = xml_escape(title or entity.download_file_name()) |
139 adapter = entity.cw_adapt_to('IDownloadable') |
143 durl = xml_escape(entity.download_url()) |
140 name = xml_escape(title or adapter.download_file_name()) |
|
141 durl = xml_escape(adapter.download_url()) |
144 self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' % |
142 self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' % |
145 (url, name, durl, self._cw._('download'))) |
143 (url, name, durl, self._cw._('download'))) |
146 |
144 |
147 |
145 |
148 class ImageView(EntityView): |
146 class ImageView(EntityView): |
149 __regid__ = 'image' |
147 __regid__ = 'image' |
150 __select__ = implements(IDownloadable) & score_entity(is_image) |
148 __select__ = has_mimetype('image/') |
151 |
149 |
152 title = _('image') |
150 title = _('image') |
153 |
151 |
154 def call(self): |
152 def call(self): |
155 rset = self.cw_rset |
153 rset = self.cw_rset |
158 self.wview(self.__regid__, rset, row=i, col=0) |
156 self.wview(self.__regid__, rset, row=i, col=0) |
159 self.w(u'</div>') |
157 self.w(u'</div>') |
160 |
158 |
161 def cell_call(self, row, col, width=None, height=None, link=False): |
159 def cell_call(self, row, col, width=None, height=None, link=False): |
162 entity = self.cw_rset.get_entity(row, col) |
160 entity = self.cw_rset.get_entity(row, col) |
|
161 adapter = entity.cw_adapt_to('IDownloadable') |
163 #if entity.data_format.startswith('image/'): |
162 #if entity.data_format.startswith('image/'): |
164 imgtag = u'<img src="%s" alt="%s" ' % ( |
163 imgtag = u'<img src="%s" alt="%s" ' % ( |
165 xml_escape(entity.download_url()), |
164 xml_escape(adapter.download_url()), |
166 (self._cw._('download %s') % xml_escape(entity.download_file_name()))) |
165 (self._cw._('download %s') % xml_escape(adapter.download_file_name()))) |
167 if width: |
166 if width: |
168 imgtag += u'width="%i" ' % width |
167 imgtag += u'width="%i" ' % width |
169 if height: |
168 if height: |
170 imgtag += u'height="%i" ' % height |
169 imgtag += u'height="%i" ' % height |
171 imgtag += u'/>' |
170 imgtag += u'/>' |