Index: main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/image.txt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/image.txt	(revision 6534)
+++ main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/image.txt	(revision 6537)
@@ -9,9 +9,10 @@
 
 In order to do this, we have a special way to store file data along with
-its filename::
+its filename:
 
   >>> import os
   >>> from waeup.sirp.image import WAeUPImageFile
   >>> testimage = os.path.join(os.path.dirname(__file__), 'sample.jpg')
+  >>> testimage2 = os.path.join(os.path.dirname(__file__), 'sample2.jpg')
   >>> some_file = WAeUPImageFile('foo.jpg', open(testimage, 'rb').read())
   >>> some_file.filename
@@ -21,5 +22,5 @@
 
 We can provide a download widget. In this case, there's nothing
-to download::
+to download:
 
   >>> from hurry.file.browser import DownloadWidget
@@ -34,5 +35,5 @@
   u'<div>Download not available</div>'
 
-Even if there were data in the request, there'd be nothing to download::
+Even if there were data in the request, there'd be nothing to download:
 
   >>> from zope.publisher.browser import FileUpload
@@ -42,5 +43,5 @@
   u'<div>Download not available</div>'
 
-Now set a value::
+Now set a value:
 
   >>> widget.setRenderedValue(some_file)
@@ -58,7 +59,6 @@
 
 Now on to an edit widget. First the case in an add form with no
-data already available, and no data in request::
-
-  >>> #from hurry.file.browser import EncodingFileWidget
+data already available, and no data in request:
+
   >>> from waeup.sirp.image.browser import EncodingImageFileWidget
   >>> field = ImageFile(__name__='foo', title=u'Foo', required=False)
@@ -80,5 +80,5 @@
 
 Now let's try a situation where data is available in the request, but
-it's an empty string for the file::
+it's an empty string for the file:
 
   >>> request = TestRequest(form={'field.foo': u''})
@@ -98,5 +98,5 @@
 
 Now let's render again when there's already available data. What should show
-up is an extra, hidden field which contains the file_id::
+up is an extra, hidden field which contains the file_id:
 
   >>> widget.setRenderedValue(some_file)
@@ -119,5 +119,5 @@
 
 Now let's render again, this time with file data available in the request
-instead. The same should happen::
+instead. The same should happen:
 
   >>> request = TestRequest(form={'field.foo': FileUpload(some_file)})
@@ -141,5 +141,5 @@
 
 Now let's render again, this time not with file data available in the
-request, but an id. Again, we should see the same::
+request, but an id. Again, we should see the same:
 
   >>> request = TestRequest(form={'field.foo.file_id':
@@ -164,5 +164,5 @@
 
 If there is both file data and an id, something else happens. First, let's
-prepare some new file::
+prepare some new file:
 
   >>> another_file = WAeUPImageFile('bar.txt', 'bar contents')
@@ -171,5 +171,5 @@
 EncodingImageFileWidget, that the file_id is going to be
 "Zm9vLnR4dAp0aGUgY29udGVudHM=". Let's make a request with the original
-id, but a new file upload::
+id, but a new file upload:
 
   >>> request = TestRequest(form={'field.foo': FileUpload(another_file),
@@ -177,5 +177,5 @@
   ...                             'Zm9vLnR4dAp0aGUgY29udGVudHM='})
 
-We expect the new file to be the one that's uploaded::
+We expect the new file to be the one that's uploaded:
 
   >>> widget = EncodingImageFileWidget(field, request)
@@ -197,2 +197,225 @@
     />
 
+Support for File Retrievals
+---------------------------
+
+As :class:`waeup.sirp.image.WAeUPImageFile` objects support storing
+image data by using external 'storages', also our widgets should do
+so.
+
+We create a simple IFileRetrieval utility and enable it:
+
+  >>> import hashlib
+  >>> from zope.component import provideUtility
+  >>> from hurry.file.interfaces import IFileRetrieval
+  >>> from StringIO import StringIO
+  >>> class MyFileRetrieval(object):
+  ...     storage = dict()
+  ...     def getFile(self, data):
+  ...         entry = self.storage.get(data, None)
+  ...         if entry is None:
+  ...             return None
+  ...         return StringIO(entry)
+  ...     def createFile(self, filename, f):
+  ...         contents = f.read()
+  ...         id_string = hashlib.md5(contents).hexdigest()
+  ...         result = WAeUPImageFile(filename, id_string)
+  ...         self.storage[id_string] = contents
+  ...         return result
+
+  >>> retrieval = MyFileRetrieval()
+  >>> provideUtility(retrieval, IFileRetrieval)
+
+With this utility in place we can post requests. When no data was
+posted and the field also contains no data, we will get a simple
+input as appropriate for add forms:
+
+  >>> field = ImageFile(__name__='foo', title=u'Foo', required=False)
+  >>> field = field.bind(None)
+  >>> request = TestRequest()
+  >>> widget = EncodingImageFileWidget(field, request)
+  >>> print normalize(widget())
+  <input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+
+If the request contains empty data but it is only an empty string, the
+result will be the same:
+
+  >>> request = TestRequest(form={'field.foo': u''})
+  >>> widget = EncodingImageFileWidget(field, request)
+  >>> print normalize(widget())
+  <input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+
+We now want to simulate, that the field contains already data,
+identified by some `file_id`. To do so, we first store the data in our
+file retrieval and then create a WAeUPImageFile object with that
+file_id stored:
+
+  >>> from waeup.sirp.image import createWAeUPImageFile
+  >>> image = createWAeUPImageFile(
+  ...     'sample.jpg', open(testimage, 'rb'))
+  >>> file_id = image.data
+  >>> file_id    # MD5 sum of the file contents
+  '9feac4265077922000aa8b88748e25be'
+
+  >>> import hashlib
+  >>> hashlib.md5(open(testimage, 'rb').read()).hexdigest()
+  '9feac4265077922000aa8b88748e25be'
+
+The new file was stored by our utility, as createWAeUPImageFile looks
+up IFileRetrieval utilities and uses them:
+
+  >>> retrieval.storage.keys()
+  ['9feac4265077922000aa8b88748e25be']
+
+We set this image as value of the widget:
+
+  >>> widget.setRenderedValue(image)
+  >>> print normalize(widget())
+  <img
+    src="sample.jpg"
+    /><br
+    /><input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+    (sample.jpg)<input
+    class="hiddenType"
+    id="field.foo.file_id"
+    name="field.foo.file_id"
+    type="hidden"
+    value="c2FtcGxlLmpwZwo5ZmVhYzQyNjUwNzc5MjIwMDBhYThiODg3NDhlMjViZQ=="
+    />
+
+  >>> retrieval.storage.keys()
+  ['9feac4265077922000aa8b88748e25be']
+
+The stored hidden value contains the filename and our file_id:
+
+  >>> "c2FtcGxlLmpwZwo5ZmVhYzQyNjUwNzc5MjIwMDBhYThiODg3NDhlMjViZQ==".decode(
+  ...    'base64')
+  'sample.jpg\n9feac4265077922000aa8b88748e25be'
+
+Now, we want the the widget rendered again but this time with the data
+coming from the request. To do so, we have to create a FileUpload
+object that wraps the real file:
+
+  >>> class UploadedFile(object):
+  ...   headers = {}
+  ...   def __init__(self, filename, f):
+  ...     self.filename = filename
+  ...     self.file = f
+
+Now we can 'post' the request and will get the same result as above:
+
+  >>> upload = FileUpload(UploadedFile('sample.jpg', open(testimage, 'rb')))
+  >>> request = TestRequest(form={'field.foo': upload})
+  >>> widget = EncodingImageFileWidget(field, request)
+  >>> print normalize(widget())
+  <img... />...
+  ...<input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+    (sample.jpg)<input
+    class="hiddenType"
+    id="field.foo.file_id"
+    name="field.foo.file_id"
+    type="hidden"
+    value="c2FtcGxlLmpwZwo5ZmVhYzQyNjUwNzc5MjIwMDBhYThiODg3NDhlMjViZQ=="
+    />
+
+Now let's render again, this time not with file data available in the
+request, but an id. Again, we should see the same:
+
+  >>> request = TestRequest(form={
+  ...   'field.foo.file_id':
+  ...   'c2FtcGxlLmpwZwo5ZmVhYzQyNjUwNzc5MjIwMDBhYThiODg3NDhlMjViZQ=='})
+  >>> widget = EncodingImageFileWidget(field, request)
+  >>> print normalize(widget())
+  <img... />...
+  ...<input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+    (sample.jpg)<input
+    class="hiddenType"
+    id="field.foo.file_id"
+    name="field.foo.file_id"
+    type="hidden"
+    value="c2FtcGxlLmpwZwo5ZmVhYzQyNjUwNzc5MjIwMDBhYThiODg3NDhlMjViZQ=="
+    />
+
+If there is both file data and an id, something else happens. First, let's
+prepare some new file:
+
+  >>> upload = FileUpload(UploadedFile('sample2.jpg', open(testimage2, 'rb')))
+
+We happen to know, due to the implementation of
+EncodingImageFileWidget, that the file_id is going to be
+"Zm9vLnR4dAp0aGUgY29udGVudHM=". Let's make a request with the original
+id, but a new file upload:
+
+  >>> request = TestRequest(form={'field.foo': upload,
+  ...                             'field.foo.file_id':
+  ...                             'Z2FtcGxlLmpwZwr/2P/gAA=='})
+
+We expect the new file to be the one that's uploaded:
+
+  >>> field = ImageFile(__name__='foo', title=u'Foo', required=False)
+  >>> field = field.bind(None)
+  >>> widget = EncodingImageFileWidget(field, request)
+  >>> print normalize(widget())
+  <img... />...
+  ...<input
+    class="fileType"
+    id="field.foo"
+    name="field.foo"
+    size="20"
+    type="file"
+    />
+    (sample2.jpg)<input
+    class="hiddenType"
+    id="field.foo.file_id"
+    name="field.foo.file_id"
+    type="hidden"
+    value="c2FtcGxlMi5qcGcKZDk2MDkwZWRlMmRjODlkZDdkZWM5ZDU3MmFkNThjNzQ="
+    />
+
+The value displayed above again means the filename and md5 sum of the
+stored file:
+
+  >>> "c2FtcGxlMi5qcGcKZDk2MDkwZWRlMmRjODlkZDdkZWM5ZDU3MmFkNThjNzQ=".decode(
+  ...      'base64')
+  'sample2.jpg\nd96090ede2dc89dd7dec9d572ad58c74'
+
+where the md5 sum is in fact correct:
+
+  >>> import hashlib
+  >>> hashlib.md5(open(testimage2, 'rb').read()).hexdigest()
+  'd96090ede2dc89dd7dec9d572ad58c74'
+
+Our file retrieval utility now contains two files:
+
+  >>> retrieval.storage.keys()
+  ['9feac4265077922000aa8b88748e25be', 'd96090ede2dc89dd7dec9d572ad58c74']
Index: main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/test_image.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/test_image.py	(revision 6534)
+++ main/waeup.sirp/trunk/src/waeup/sirp/image/browser/tests/test_image.py	(revision 6537)
@@ -46,3 +46,2 @@
             )
         )
-
