    =================
    Named File Widget
    =================

    This package contains two widgets: the NamedFileWidget will be used when
    rendering NamedFile objects from plone.namedfile. The NamedImageWidget is used
    for NamedImage objects. This includes their sub-classes NamedBlobFile and
    NamedBlobImage.

    Like any widget, the file widgets provide the ``IWidget`` interface:

      >>> from zope.interface.verify import verifyClass
      >>> from z3c.form import interfaces
      >>> from plone.formwidget.namedfile import NamedFileWidget, NamedImageWidget

      >>> verifyClass(interfaces.IWidget, NamedFileWidget)
      True
      >>> verifyClass(interfaces.IWidget, NamedImageWidget)
      True

    There are also more specific interfaces for each widget:

        >>> from plone.formwidget.namedfile.interfaces import INamedFileWidget
        >>> from plone.formwidget.namedfile.interfaces import INamedImageWidget

        >>> verifyClass(INamedFileWidget, NamedFileWidget)
        True
        >>> verifyClass(INamedImageWidget, NamedImageWidget)
        True

    The widgets can be instantiated only using the request:

      >>> from z3c.form.testing import TestRequest
      >>> request = TestRequest()

      >>> file_widget = NamedFileWidget(request)
      >>> image_widget = NamedImageWidget(request)

    Before rendering a widget, one has to set the name and id of the widget:

      >>> file_widget.id = 'widget.id.file'
      >>> file_widget.name = 'widget.name.file'

      >>> image_widget.id = 'widget.id.image'
      >>> image_widget.name = 'widget.name.image'

    We also need to register the templates for the widgets:

      >>> import zope.component
      >>> from zope.pagetemplate.interfaces import IPageTemplate
      >>> from z3c.form.widget import WidgetTemplateFactory

      >>> def getPath(filename):
      ...     import os.path
      ...     import plone.formwidget.namedfile
      ...     return os.path.join(os.path.dirname(plone.formwidget.namedfile.__file__), filename)

      >>> zope.component.provideAdapter(
      ...     WidgetTemplateFactory(getPath('file_input.pt'), 'text/html'),
      ...     (None, None, None, None, INamedFileWidget),
      ...     IPageTemplate, name=interfaces.INPUT_MODE)

      >>> zope.component.provideAdapter(
      ...     WidgetTemplateFactory(getPath('image_input.pt'), 'text/html'),
      ...     (None, None, None, None, INamedImageWidget),
      ...     IPageTemplate, name=interfaces.INPUT_MODE)

    If we render the widget as this we get an input element in a simple wrapper.
    Later, we will show more advanced functionality when using a field-widget.

      >>> file_widget.update()
      >>> print file_widget.render()
>>> image_widget.update() >>> print image_widget.render()
    We can extract simple file data from the widget like this:

      >>> import cStringIO
      >>> myfile = cStringIO.StringIO('My file contents.')

      >>> file_widget.request = TestRequest(form={'widget.name.file': myfile})
      >>> file_widget.update()
      >>> file_widget.extract()
      >>> image_widget.request = TestRequest(form={'widget.name.image': myfile})
      >>> image_widget.update()
      >>> image_widget.extract()
    If nothing is found in the request, the default is returned:

      >>> file_widget.request = TestRequest()
      >>> file_widget.update()
      >>> file_widget.extract()
      >>> image_widget.request = TestRequest()
      >>> image_widget.update()
      >>> image_widget.extract()
    We can also handle file-upload objects.

      >>> import cStringIO
      >>> from ZPublisher.HTTPRequest import FileUpload

    Let's define a FieldStorage stub:

      >>> class FieldStorageStub:
      ...     def __init__(self, file, headers={}, filename='foo.bar'):
      ...         self.file = file
      ...         self.headers = headers
      ...         self.filename = filename

    Now build a FileUpload:

      >>> myfile = cStringIO.StringIO('File upload contents.')
      >>> aFieldStorage = FieldStorageStub(myfile)
      >>> myUpload = FileUpload(aFieldStorage)

      >>> file_widget.request = TestRequest(form={'widget.name.file': myUpload})
      >>> file_widget.update()
      >>> file_widget.extract()
      >>> image_widget.request = TestRequest(form={'widget.name.image': myUpload})
      >>> image_widget.update()
      >>> image_widget.extract()
The rendering is unchanged. >>> print file_widget.render() >>> print image_widget.render()
    Rendering field widgets
    -----------------------

    If the widgets are used as field widgets for the fields in plone.namedfile,
    we get more interesting behaviour: the user may either select to provide a
    new file, or keep the existing one.

    For this to work, we need a context and a data manager.

      >>> from plone.namedfile import field
      >>> from zope.interface import implements, Interface
      >>> class IContent(Interface):
      ...     file_field = field.NamedFile(title=u"File")
      ...     image_field = field.NamedImage(title=u"Image")

      >>> class Content(object):
      ...     implements(IContent)
      ...     def __init__(self, file, image):
      ...         self.file_field = file
      ...         self.image_field = image
      ...
      ...     def absolute_url(self):
      ...         return 'http://example.com/content1'

      >>> content = Content(None, None)

      >>> from z3c.form.datamanager import AttributeField
      >>> from zope.component import provideAdapter
      >>> provideAdapter(AttributeField)

      >>> from plone.formwidget.namedfile import NamedFileFieldWidget
      >>> from plone.formwidget.namedfile import NamedImageFieldWidget

      >>> file_widget = NamedFileFieldWidget(IContent['file_field'], TestRequest())
      >>> image_widget = NamedImageFieldWidget(IContent['image_field'], TestRequest())

      >>> file_widget.context = content
      >>> image_widget.context = content

      >>> file_widget.id = 'widget.id.file'
      >>> file_widget.name = 'widget.name.file'

      >>> image_widget.id = 'widget.id.image'
      >>> image_widget.name = 'widget.name.image'

    At first, there is no value, so the behaviour is much like before:

      >>> file_widget.update()
      >>> print file_widget.render()
>>> image_widget.update() >>> print image_widget.render()
    However, if we now set a value, we will have the option of keeping it,
    or changing it.

      >>> from plone.namedfile import NamedFile, NamedImage
      >>> file_widget.value = NamedFile(data='My file data', filename='data.txt')
      >>> image_widget.value = NamedImage(data='My image data', filename='faux.png')

      >>> file_widget.update()
      >>> print file_widget.render()
data.txt — 0 KB
Keep existing file
Remove existing file
Replace with new file
>>> image_widget.update() >>> print image_widget.render()
faux.png — 0 KB
Keep existing image
Remove existing image
Replace with new image
    (the image height and width are taken from the NamedImage instance, and here
    default to -1 since we didn't upload a real image)

    Notice how there are radio buttons to decide whether to upload a new file or
    keep the existing one. If the '.nochange' field is not submitted or is
    empty, the behaviour is the same as before:

      >>> myfile = cStringIO.StringIO('File upload contents.')
      >>> aFieldStorage = FieldStorageStub(myfile, filename='test2.txt')
      >>> myUpload = FileUpload(aFieldStorage)

      >>> file_widget.request = TestRequest(form={'widget.name.file': myUpload})
      >>> file_widget.update()
      >>> file_widget.extract()
      >>> myfile = cStringIO.StringIO('Random image content.')
      >>> aFieldStorage = FieldStorageStub(myfile, filename='faux2.png')
      >>> myUpload = FileUpload(aFieldStorage)

      >>> image_widget.request = TestRequest(form={'widget.name.image': myUpload})
      >>> image_widget.update()
      >>> image_widget.extract()
If the widgets are rendered again, the newly uploaded files will be shown. >>> print file_widget.render() test2.txt — 0 KB
Keep existing file
Remove existing file
Replace with new file
>>> print image_widget.render()
faux2.png — 0 KB
Keep existing image
Remove existing image
Replace with new image
    However, if we provide the '.nochange' field, we get back the value currently
    stored in the field.

      >>> content.file_field = NamedFile(data='My file data', filename='data.txt')
      >>> content.image_field = NamedImage(data='My image data', filename='faux.png')

      >>> file_widget.value = content.file_field
      >>> image_widget.value = content.image_field

      >>> file_widget.request = TestRequest(form={'widget.name.file': '', 'widget.name.file.nochange': 'nochange'})
      >>> file_widget.update()
      >>> file_widget.extract() is content.file_field
      True

      >>> myfile = cStringIO.StringIO('Random image content.')
      >>> aFieldStorage = FieldStorageStub(myfile, filename='faux2.png')
      >>> myUpload = FileUpload(aFieldStorage)

      >>> image_widget.request = TestRequest(form={'widget.name.image': '', 'widget.name.image.nochange': 'nochange'})
      >>> image_widget.update()
      >>> image_widget.extract() is content.image_field
      True

    The converter
    -------------

    This package comes with a data converter that can convert a file upload
    instance to a named file. It is registered to work on all named file/image
    instances and the two named file/image widgets.

      >>> from plone.formwidget.namedfile.converter import NamedDataConverter
      >>> provideAdapter(NamedDataConverter)

      >>> from zope.component import getMultiAdapter
      >>> from z3c.form.interfaces import IDataConverter

      >>> file_converter = getMultiAdapter((IContent['file_field'], file_widget), IDataConverter)
      >>> image_converter = getMultiAdapter((IContent['image_field'], image_widget), IDataConverter)

    A value of None or '' results in the field's missing_value being returned.

      >>> file_converter.toFieldValue(u'') is IContent['file_field'].missing_value
      True
      >>> file_converter.toFieldValue(None) is IContent['file_field'].missing_value
      True

      >>> image_converter.toFieldValue(u'') is IContent['image_field'].missing_value
      True
      >>> image_converter.toFieldValue(None) is IContent['image_field'].missing_value
      True

    A named file/image instance is returned as-is:

      >>> file_converter.toFieldValue(content.file_field) is content.file_field
      True
      >>> image_converter.toFieldValue(content.image_field) is content.image_field
      True

    A data string is converted to the appropriate type:

      >>> file_converter.toFieldValue('some file content')
>>> image_converter.toFieldValue('random data')
    A FileUpload object is converted to the appropriate type, preserving filename
    and content type.

      >>> myfile = cStringIO.StringIO('File upload contents.')
      >>> aFieldStorage = FieldStorageStub(myfile, filename='random.txt', headers={'Content-Type': 'text/x-dummy'})
      >>> file_obj = file_converter.toFieldValue(FileUpload(aFieldStorage))
      >>> file_obj.data
      'File upload contents.'
      >>> file_obj.filename
      u'random.txt'
      >>> file_obj.contentType
      'text/x-dummy'

      >>> myfile = cStringIO.StringIO('Random image content.')
      >>> aFieldStorage = FieldStorageStub(myfile, filename='random.png', headers={'Content-Type': 'image/x-dummy'})
      >>> image_obj = image_converter.toFieldValue(FileUpload(aFieldStorage))
      >>> image_obj.data
      'Random image content.'
      >>> image_obj.filename
      u'random.png'
      >>> image_obj.contentType
      'image/x-dummy'