diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt
index 9bd93ee4..3fb925b7 100644
--- a/docs/HISTORY.txt
+++ b/docs/HISTORY.txt
@@ -7,6 +7,10 @@ Changelog
* Declare dependency on plone.rfc822 >= 1.0b2 (for IPrimaryField).
[davisagli]
+* Add a @@display-file view which doesn't set Content-Disposition, so we don't
+ force download of images, for example.
+ [lentinj]
+
1.0b7 - 2011-03-22
------------------
diff --git a/plone/namedfile/browser.py b/plone/namedfile/browser.py
index f10e1246..9c3e40bb 100644
--- a/plone/namedfile/browser.py
+++ b/plone/namedfile/browser.py
@@ -40,6 +40,14 @@ def publishTraverse(self, request, name):
return self
def __call__(self):
+ file = self._getFile()
+
+ if not self.filename:
+ self.filename = getattr(file, 'filename', self.fieldname)
+ set_headers(file, self.request.response, filename=self.filename)
+ return stream_data(file)
+
+ def _getFile(self):
if not self.fieldname:
info = IPrimaryFieldInfo(self.context, None)
if info is None:
@@ -53,9 +61,15 @@ def __call__(self):
if file is None:
raise NotFound(self, self.fieldname, self.request)
- if not self.filename:
- self.filename = getattr(file, 'filename', self.fieldname)
-
- set_headers(file, self.request.response, filename=self.filename)
+ return file
+class DisplayFile(Download):
+ """Display a file, via ../context/@@display-file/fieldname/filename
+
+ Same as Download, however in this case we don't set the filename so the
+ browser can decide to display the file instead.
+ """
+ def __call__(self):
+ file = self._getFile()
+ set_headers(file, self.request.response)
return stream_data(file)
diff --git a/plone/namedfile/configure.zcml b/plone/namedfile/configure.zcml
index fd299d31..4798e387 100644
--- a/plone/namedfile/configure.zcml
+++ b/plone/namedfile/configure.zcml
@@ -11,6 +11,13 @@
permission="zope2.View"
/>
+
+
diff --git a/plone/namedfile/usage.txt b/plone/namedfile/usage.txt
index 8ebf39dc..22d50b51 100644
--- a/plone/namedfile/usage.txt
+++ b/plone/namedfile/usage.txt
@@ -191,10 +191,11 @@ Note that is possible for force the mimetype:
Download view
-------------
-This package also comes with a view that can be used to download files. To
-use it, link to ../context-object/@@download/fieldname, where `fieldname` is
-the name of the attribute on the context-object where the named file is
-stored.
+This package also comes with a view that can be used to download files. This
+will set Content-Disposition to ensure the browser downloads the file rather
+than displaying it. To use it, link to ../context-object/@@download/fieldname,
+where `fieldname` is the name of the attribute on the context-object where the
+named file is stored.
We will test this with a dummy request, faking traversal.
@@ -266,6 +267,82 @@ We will test this with a dummy request, faking traversal.
'image/foo'
'attachment; filename="zpt.gif"'
+Display-file view
+-------------
+
+This package also comes with a view that can be used to display files in the
+browser. To use it, link to ../context-object/@@display-file/fieldname, where
+`fieldname` is the name of the attribute on the context-object where the named
+file is stored.
+
+We will test this with a dummy request, faking traversal.
+
+ >>> from plone.namedfile.browser import DisplayFile
+ >>> from zope.publisher.browser import TestRequest
+
+ >>> request = TestRequest()
+ >>> display_file = DisplayFile(container, request).publishTraverse(request, 'simple')
+ >>> display_file()
+ 'dummy test data'
+ >>> request.response.getHeader('Content-Length')
+ '15'
+ >>> request.response.getHeader('Content-Type')
+ 'text/plain'
+ >>> request.response.getHeader('Content-Disposition')
+
+ >>> if HAVE_BLOBS:
+ ... request = TestRequest()
+ ... display_file = DisplayFile(container, request).publishTraverse(request, 'blob')
+ ... data = display_file()
+ ... print repr(isinstance(data, file))
+ ... print repr(data.read())
+ ... print repr(request.response.getHeader('Content-Length'))
+ ... print repr(request.response.getHeader('Content-Type'))
+ ... print repr(request.response.getHeader('Content-Disposition'))
+ ... else:
+ ... print repr(True)
+ ... print repr('dummy test data')
+ ... print repr('15')
+ ... print repr('text/plain')
+ ... print repr(None)
+ True
+ 'dummy test data'
+ '15'
+ 'text/plain'
+ None
+
+ >>> request = TestRequest()
+ >>> display_file = DisplayFile(container, request).publishTraverse(request, 'image')
+ >>> display_file() == zptlogo
+ True
+
+ >>> request.response.getHeader('Content-Length')
+ '341'
+ >>> request.response.getHeader('Content-Type')
+ 'image/foo'
+ >>> request.response.getHeader('Content-Disposition')
+
+ >>> request = TestRequest()
+ >>> if HAVE_BLOBS:
+ ... display_file = DisplayFile(container, request).publishTraverse(request, 'blobimage')
+ ... data = display_file()
+ ... print repr(isinstance(data, file))
+ ... print repr(data.read() == zptlogo)
+ ... print repr(request.response.getHeader('Content-Length'))
+ ... print repr(request.response.getHeader('Content-Type'))
+ ... print repr(request.response.getHeader('Content-Disposition'))
+ ... else:
+ ... print repr(True)
+ ... print repr(True)
+ ... print repr('341')
+ ... print repr('image/foo')
+ ... print repr(None)
+ True
+ True
+ '341'
+ 'image/foo'
+ None
+
Specifying the primary field
----------------------------