[Checkins] SVN: Products.CMFDefault/trunk/Products/CMFDefault/ - added FileUpload field and widget

Yvo Schubbe y.2008 at wcm-solutions.de
Fri May 2 06:44:07 EDT 2008


Log message for revision 86084:
  - added FileUpload field and widget
  - refactored add form code

Changed:
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/widgets.py

-=-
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py	2008-05-02 10:44:06 UTC (rev 86084)
@@ -16,18 +16,16 @@
 """
 
 from zope.component import adapts
-from zope.component import getUtility
-from zope.component.interfaces import IFactory
 from zope.formlib import form
 from zope.interface import implements
 from zope.interface import Interface
 from zope.schema import ASCIILine
-from zope.schema import Bytes
 from zope.schema import Text
 from zope.schema import TextLine
 
 from Products.CMFDefault.formlib.form import ContentAddFormBase
 from Products.CMFDefault.formlib.form import ContentEditFormBase
+from Products.CMFDefault.formlib.schema import FileUpload
 from Products.CMFDefault.formlib.schema import ProxyFieldProperty
 from Products.CMFDefault.formlib.schema import SchemaAdapterBase
 from Products.CMFDefault.interfaces import IMutableFile
@@ -59,7 +57,7 @@
         title=_(u'Content type'),
         readonly=True)
 
-    upload = Bytes(
+    file = FileUpload(
         title=_(u'Upload'),
         required=False)
 
@@ -72,9 +70,10 @@
     adapts(IMutableFile)
     implements(IFileSchema)
 
-    _upload = ProxyFieldProperty(IFileSchema['upload'], 'data')
+    def _getFile(self):
+        return ''
 
-    def _setUpload(self, value):
+    def _setFile(self, value):
         self.context.manage_upload(value)
 
     title = ProxyFieldProperty(IFileSchema['title'], 'Title', 'setTitle')
@@ -83,7 +82,7 @@
     description = ProxyFieldProperty(IFileSchema['description'],
                                      'Description', 'setDescription')
     format = ProxyFieldProperty(IFileSchema['format'], 'Format')
-    upload = property(_upload.__get__, _setUpload)
+    file = property(_getFile, _setFile)
 
 
 class FileAddView(ContentAddFormBase):
@@ -93,7 +92,7 @@
 
     form_fields = (
         form.FormFields(IFileSchema).select('title', 'description') +
-        form.FormFields(Bytes(__name__='upload', title=_(u'Upload')),
+        form.FormFields(FileUpload(__name__='file', title=_(u'Upload')),
                         TextLine(__name__='portal_type', default=u'File'))
         )
 
@@ -102,22 +101,17 @@
               self).setUpWidgets(ignore_request=ignore_request)
         self.widgets['description'].height = 3
         self.widgets['portal_type'].hide = True
-        self.widgets['upload'].displayWidth = 60
+        self.widgets['file'].displayWidth = 60
 
     def create(self, data):
-        ttool = self._getTool('portal_types')
-        fti = ttool.getTypeInfo(data['portal_type'])
-        factory = getUtility(IFactory, fti.factory)
-        obj = factory('temp_id')
-        obj._setPortalTypeName(data['portal_type'])
-
+        obj = super(FileAddView,
+                    self).create(dict(id=data['file'].filename,
+                                      portal_type=data['portal_type']))
         adapted = FileSchemaAdapter(obj)
+        adapted.title = data['title']
         adapted.language = u''
-        adapted.upload = self.request.form['%s.upload' % self.prefix]
-        if data['title']:
-            adapted.title = data['title']
-        if data['description']:
-            adapted.description = data['description']
+        adapted.description = data['description']
+        adapted.file = data['file']
         return obj
 
 
@@ -132,11 +126,4 @@
         super(FileEditView,
               self).setUpWidgets(ignore_request=ignore_request)
         self.widgets['description'].height = 3
-        self.widgets['upload'].displayWidth = 60
-
-    def _handle_success(self, action, data):
-        if data.get('upload'):
-            data['upload'] = self.request.form['%s.upload' % self.prefix]
-        else:
-            del data['upload']
-        return super(FileEditView, self)._handle_success(action, data)
+        self.widgets['file'].displayWidth = 60

Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt	2008-05-02 10:44:06 UTC (rev 86084)
@@ -32,7 +32,7 @@
     True
     >>> browser.getControl(name='form.title').value = 'FILE TITLE'
     >>> browser.getControl(name='form.description').value = 'FILE DESCRIPTION.'
-    >>> ctrl = browser.getControl(name='form.upload')
+    >>> ctrl = browser.getControl(name='form.file')
     >>> ctrl.add_file(StringIO('FILE DATA'), 'text/plain', 'myFile')
     >>> browser.getControl('[[zope][Add]]').click()
     >>> '[[cmf_default][[[cmf_default][File]] added.]]' in browser.contents
@@ -52,8 +52,8 @@
     >>> browser.open('http://localhost/site/myFile/@@edit.html')
     >>> '[[cmf_default][Edit [[cmf_default][File]]]]' in browser.contents
     True
-    >>> ctrl = browser.getControl(name='form.upload')
-    >>> ctrl.add_file(StringIO('FILE DATA'), 'text/plain', 'test.txt')
+    >>> ctrl = browser.getControl(name='form.file')
+    >>> ctrl.add_file(StringIO('FILE DATA 2'), 'text/plain', 'test.txt')
     >>> browser.getControl('[[cmf_default][Change]]').click()
     >>> '[[cmf_default][[[cmf_default][File]] changed.]]' in browser.contents
     True

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/configure.zcml	2008-05-02 10:44:06 UTC (rev 86084)
@@ -6,4 +6,9 @@
       permission="zope.Public"
       />
 
+  <adapter
+      factory=".widgets.FileUploadWidget"
+      permission="zope.Public"
+      />
+
 </configure>

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2008-05-02 10:44:06 UTC (rev 86084)
@@ -23,6 +23,8 @@
 from Products.Five.formlib.formbase import PageDisplayForm
 from Products.Five.formlib.formbase import PageForm
 from zope.app.container.interfaces import INameChooser
+from zope.component import getUtility
+from zope.component.interfaces import IFactory
 from zope.datetime import parseDatetimetz
 from zope.formlib import form
 from zope.i18n.interfaces import IUserPreferredLanguages
@@ -152,15 +154,18 @@
         return self._setRedirect('portal_types',
                                  ('object/folderContents', 'object/view'))
 
+    def create(self, data):
+        id =  data.pop('id', '')
+        portal_type = data.pop('portal_type')
+        ttool = self._getTool('portal_types')
+        fti = ttool.getTypeInfo(portal_type)
+        factory = getUtility(IFactory, fti.factory)
+        obj = factory(id=id, **data)
+        obj._setPortalTypeName(portal_type)
+        return obj
+
     def add(self, obj):
         container = self.context
-        upload = self.request.form.get('%s.upload' % self.prefix)
-        if upload:
-            filename = upload.filename.split('\\')[-1] # for IE
-            filename = filename.strip().replace(' ','_')
-        else:
-            filename = u''
-        name = INameChooser(container).chooseName(filename, obj)
 
         #check container constraints
         ttool = self._getTool('portal_types')
@@ -171,6 +176,7 @@
             self.status = u'Disallowed subobject type: %s' % portal_type
             return None
 
+        name = INameChooser(container).chooseName(obj.getId(), obj)
         obj.id = name
         container._setObject(name, obj)
 

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py	2008-05-02 10:44:06 UTC (rev 86084)
@@ -28,7 +28,9 @@
 from zope.datetime import parseDatetimetz
 from zope.interface import implements
 from zope.schema import BytesLine
+from zope.schema import Field
 from zope.schema.interfaces import IBytesLine
+from zope.schema.interfaces import IField
 
 from Products.CMFCore.interfaces import IPropertiesTool
 from Products.CMFDefault.utils import checkEmailAddress
@@ -74,7 +76,7 @@
         elif callable(attribute):
             attribute = attribute()
 
-        if self._field._type == str:
+        if self._field._type in (str, None):
             return attribute
         if isinstance(attribute, str) and inst.encoding:
             return attribute.decode(inst.encoding)
@@ -139,3 +141,17 @@
         super(EmailLine, self)._validate(value)
         checkEmailAddress(value)
         return True
+
+
+class IFileUpload(IField):
+
+    """A field for file uploads.
+    """
+
+
+class FileUpload(Field):
+
+    """File upload form field.
+    """
+
+    implements(IFileUpload)

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/widgets.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/widgets.py	2008-05-02 10:43:28 UTC (rev 86083)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/widgets.py	2008-05-02 10:44:06 UTC (rev 86084)
@@ -17,6 +17,7 @@
 
 from zope.app.form import InputWidget
 from zope.app.form.browser import BrowserWidget
+from zope.app.form.browser import FileWidget
 from zope.app.form.browser import MultiSelectSetWidget
 from zope.app.form.browser import RadioWidget
 from zope.app.form.browser import TextWidget
@@ -26,6 +27,7 @@
 from zope.app.form.interfaces import WidgetInputError
 from zope.component import adapts
 from zope.component import getUtility
+from zope.i18nmessageid import MessageFactory
 from zope.interface import implementsOnly
 from zope.publisher.interfaces.browser import IBrowserRequest
 from zope.schema import Set
@@ -38,9 +40,12 @@
 from Products.CMFDefault.utils import scrubHTML
 from Products.CMFDefault.utils import Message as _
 from schema import IEmailLine
+from schema import IFileUpload
 from vocabulary import SimpleVocabulary
 
+zope_ = MessageFactory("zope")
 
+
 # generic widgets
 
 def ChoiceRadioWidget(field, request):
@@ -105,6 +110,26 @@
     return TupleTextAreaWidget(field, field.value_type, request)
 
 
+class FileUploadWidget(FileWidget):
+
+    implementsOnly(IInputWidget)
+    adapts(IFileUpload, IBrowserRequest)
+
+    def _toFieldValue(self, input):
+        if not input:
+            return self.context.missing_value
+        try:
+            filename = input.filename.split('\\')[-1] # for IE
+            input.filename = filename.strip().replace(' ','_')
+        except AttributeError, e:
+            raise ConversionError(zope_('Form input is not a file object'), e)
+        return input
+
+    def hasInput(self):
+        return ((self.required and self.name+".used" in self.request.form) or
+                self.request.form.get(self.name))
+
+
 # special widgets
 
 class SubjectInputWidget(InputWidget, BrowserWidget):



More information about the Checkins mailing list