[7196] | 1 | ## $Id: widget.py 7819 2012-03-08 22:28:46Z henrik $ |
---|
[5693] | 2 | ## |
---|
[7196] | 3 | ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann |
---|
[5693] | 4 | ## This program is free software; you can redistribute it and/or modify |
---|
| 5 | ## it under the terms of the GNU General Public License as published by |
---|
| 6 | ## the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | ## (at your option) any later version. |
---|
[7196] | 8 | ## |
---|
[5693] | 9 | ## This program is distributed in the hope that it will be useful, |
---|
| 10 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | ## GNU General Public License for more details. |
---|
[7196] | 13 | ## |
---|
[5693] | 14 | ## You should have received a copy of the GNU General Public License |
---|
| 15 | ## along with this program; if not, write to the Free Software |
---|
| 16 | ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 17 | ## |
---|
| 18 | """Image file widgets. |
---|
| 19 | """ |
---|
[6533] | 20 | import os |
---|
[7819] | 21 | from waeup.kofa.image import KofaImageFile |
---|
[5693] | 22 | from hurry.file.browser.widget import ( |
---|
[6533] | 23 | EncodingFileWidget, DownloadWidget, FakeFieldStorage) |
---|
| 24 | from hurry.file.interfaces import IFileRetrieval |
---|
[5693] | 25 | from zope.app.form.browser.textwidgets import escape |
---|
| 26 | from zope.app.form.browser.widget import renderElement |
---|
[6035] | 27 | from zope.app.form.interfaces import ConversionError |
---|
[6533] | 28 | from zope.component import queryUtility |
---|
| 29 | from zope.publisher.browser import FileUpload |
---|
[5693] | 30 | |
---|
[6035] | 31 | |
---|
[5693] | 32 | class EncodingImageFileWidget(EncodingFileWidget): |
---|
| 33 | """A hurry.file widget that stores images. |
---|
[6035] | 34 | |
---|
| 35 | This is an upload widget suitable for edit forms and the like. |
---|
[5693] | 36 | """ |
---|
| 37 | #: We can set a basename for the image to be rendered. |
---|
| 38 | #: This will result in <img> links like <img src='.../<basename>.jpg' /> |
---|
| 39 | image_basename = None |
---|
[6035] | 40 | |
---|
| 41 | def _toFieldValue(self, (input, file_id)): |
---|
[6533] | 42 | # we got no file upload input |
---|
[6035] | 43 | if not input: |
---|
| 44 | # if we got a file_id, then retrieve file and return it |
---|
| 45 | if file_id: |
---|
| 46 | return self._retrieveFile(file_id) |
---|
| 47 | # no file upload input nor file id, so return missing value |
---|
| 48 | return self.context.missing_value |
---|
| 49 | # read in file from input |
---|
| 50 | try: |
---|
| 51 | seek = input.seek |
---|
| 52 | read = input.read |
---|
| 53 | except AttributeError, e: |
---|
| 54 | raise ConversionError('Form input is not a file object', e) |
---|
| 55 | |
---|
| 56 | seek(0) |
---|
| 57 | data = read() |
---|
| 58 | |
---|
| 59 | if data: |
---|
[6533] | 60 | retrieval = queryUtility(IFileRetrieval) |
---|
| 61 | if retrieval is not None: |
---|
| 62 | seek(0) |
---|
| 63 | return retrieval.createFile(input.filename, input) |
---|
[7819] | 64 | return KofaImageFile(input.filename, data) |
---|
[6035] | 65 | else: |
---|
| 66 | return self.context.missing_value |
---|
| 67 | |
---|
[6533] | 68 | def _toFormValue(self, value): |
---|
| 69 | if value == self.context.missing_value: |
---|
| 70 | return self._missing |
---|
| 71 | data = value.file.read() |
---|
| 72 | return FileUpload(FakeFieldStorage( |
---|
| 73 | value.filename.encode('UTF-8'), data)) |
---|
| 74 | |
---|
[5693] | 75 | def __call__(self): |
---|
| 76 | value = self._getFormValue() |
---|
[6533] | 77 | if value: |
---|
| 78 | file_id = self._setFile(value) |
---|
| 79 | else: |
---|
| 80 | file_id = None |
---|
[5693] | 81 | result = u'' |
---|
[6533] | 82 | options = dict( |
---|
| 83 | type=self.type, |
---|
| 84 | name=self.name, |
---|
| 85 | id=self.name, |
---|
| 86 | cssClass=self.cssClass, |
---|
| 87 | size=self.displayWidth, |
---|
| 88 | extra=self.extra,) |
---|
| 89 | if self.displayMaxWidth: |
---|
| 90 | options.update(maxlength=self.displayMaxWidth) |
---|
[5693] | 91 | if value: |
---|
| 92 | filename = value.filename |
---|
| 93 | if self.image_basename is not None: |
---|
| 94 | filename = self.image_basename + os.path.splitext(filename)[-1] |
---|
| 95 | result = renderElement( |
---|
| 96 | 'img', |
---|
| 97 | src=filename, |
---|
| 98 | ) |
---|
| 99 | result += renderElement('br') |
---|
[6533] | 100 | result += renderElement(self.tag, **options) |
---|
| 101 | if file_id is not None: |
---|
| 102 | if value: |
---|
| 103 | result += ' (%s)' % value.filename |
---|
| 104 | result += renderElement( |
---|
| 105 | 'input', |
---|
| 106 | type='hidden', |
---|
| 107 | name=self.name + '.file_id', |
---|
| 108 | id=self.name + '.file_id', |
---|
| 109 | value=file_id, |
---|
| 110 | ) |
---|
[5693] | 111 | return result |
---|
| 112 | |
---|
[6533] | 113 | def _setFile(self, file): |
---|
| 114 | """Store away uploaded file (FileUpload object). |
---|
| 115 | |
---|
| 116 | Returns file_id identifying file. |
---|
| 117 | """ |
---|
| 118 | # if there was no file input and there was a file_id already in the |
---|
| 119 | # input, reuse this for next request |
---|
| 120 | if not self.request.get(self.name): |
---|
| 121 | file_id = self.request.get(self.name + '.file_id') |
---|
| 122 | if file_id is not None: |
---|
| 123 | return file_id |
---|
| 124 | # otherwise, stuff filedata away in session, making a new file_id |
---|
| 125 | if file == self.context.missing_value: |
---|
| 126 | return None |
---|
| 127 | return self._storeFile(file) |
---|
| 128 | |
---|
[5693] | 129 | def _storeFile(self, file_upload): |
---|
| 130 | # filenames are normally in unicode encoding, while the contents |
---|
| 131 | # are byte streams. We turn the filename into a bytestream. |
---|
[6533] | 132 | retrieval = queryUtility(IFileRetrieval) |
---|
| 133 | if retrieval is not None: |
---|
| 134 | file_upload.seek(0) |
---|
| 135 | file_obj = retrieval.createFile(file_upload.filename, file_upload) |
---|
| 136 | data = file_obj.data |
---|
| 137 | else: |
---|
| 138 | data = file_upload.read() |
---|
| 139 | data = '%s\n%s' % (str(file_upload.filename), data) |
---|
[5693] | 140 | return data.encode('base64')[:-1] |
---|
| 141 | |
---|
[6035] | 142 | def _retrieveFile(self, file_id): |
---|
| 143 | data = file_id.decode('base64') |
---|
| 144 | filename, filedata = data.split('\n', 1) |
---|
[7819] | 145 | return KofaImageFile(filename, filedata) |
---|
[6035] | 146 | |
---|
[5693] | 147 | class ThumbnailWidget(DownloadWidget): |
---|
| 148 | """An image file widget that displays the data as thumbnail. |
---|
[6035] | 149 | |
---|
| 150 | XXX: give some reason to name this a _thumbnail_ widget. |
---|
[5693] | 151 | """ |
---|
| 152 | |
---|
| 153 | def __call__(self): |
---|
| 154 | if self._renderedValueSet(): |
---|
| 155 | value = self._data |
---|
| 156 | else: |
---|
| 157 | value = self.context.default |
---|
| 158 | if value == self.context.missing_value: |
---|
| 159 | return renderElement( |
---|
| 160 | u'div', |
---|
| 161 | contents=u'Download not available') |
---|
| 162 | filename = escape(value.filename) |
---|
| 163 | return renderElement( |
---|
| 164 | u'img', |
---|
| 165 | src=filename, |
---|
| 166 | contents=None) |
---|