appy.gen: ugly Zope acquisition-related bugfix; bugfix while rendering file widgets.

This commit is contained in:
Gaetan Delannay 2011-10-11 17:32:23 +02:00
parent 17f6d15185
commit f1136eb786
3 changed files with 47 additions and 42 deletions

View file

@ -723,7 +723,7 @@ class Type:
def getValue(self, obj): def getValue(self, obj):
'''Gets, on_obj, the value conforming to self's type definition.''' '''Gets, on_obj, the value conforming to self's type definition.'''
value = getattr(obj, self.name, None) value = getattr(obj.aq_base, self.name, None)
if (value == None): if (value == None):
# If there is no value, get the default value if any # If there is no value, get the default value if any
if not self.editDefault: if not self.editDefault:
@ -1586,7 +1586,7 @@ class File(Type):
if isinstance(value, ZFileUpload): if isinstance(value, ZFileUpload):
# The file content comes from a HTTP POST. # The file content comes from a HTTP POST.
# Retrieve the existing value, or create one if None # Retrieve the existing value, or create one if None
existingValue = getattr(obj, self.name, None) existingValue = getattr(obj.aq_base, self.name, None)
if not existingValue: if not existingValue:
existingValue = OFSImageFile(self.name, '', '') existingValue = OFSImageFile(self.name, '', '')
# Set mimetype # Set mimetype
@ -1722,7 +1722,7 @@ class Ref(Type):
if (layoutType == 'edit') and self.add: return False if (layoutType == 'edit') and self.add: return False
if self.isBack: if self.isBack:
if layoutType == 'edit': return False if layoutType == 'edit': return False
else: return getattr(obj, self.name, None) else: return getattr(obj.aq_base, self.name, None)
return res return res
def getValue(self, obj, type='objects', noListIfSingleObj=False, def getValue(self, obj, type='objects', noListIfSingleObj=False,
@ -1741,7 +1741,7 @@ class Ref(Type):
If p_someObjects is True, it returns an instance of SomeObjects If p_someObjects is True, it returns an instance of SomeObjects
instead of returning a list of references.''' instead of returning a list of references.'''
uids = getattr(obj, self.name, []) uids = getattr(obj.aq_base, self.name, [])
if not uids: if not uids:
# Maybe is there a default value? # Maybe is there a default value?
defValue = Type.getValue(self, obj) defValue = Type.getValue(self, obj)
@ -1818,7 +1818,7 @@ class Ref(Type):
return return
# Gets the list of referred objects (=list of uids), or create it. # Gets the list of referred objects (=list of uids), or create it.
obj = obj.o obj = obj.o
refs = getattr(obj, self.name, None) refs = getattr(obj.aq_base, self.name, None)
if refs == None: if refs == None:
refs = obj.getProductConfig().PersistentList() refs = obj.getProductConfig().PersistentList()
setattr(obj, self.name, refs) setattr(obj, self.name, refs)
@ -1837,7 +1837,7 @@ class Ref(Type):
for v in value: self.unlinkObject(obj, v, back=back) for v in value: self.unlinkObject(obj, v, back=back)
return return
obj = obj.o obj = obj.o
refs = getattr(obj, self.name, None) refs = getattr(obj.aq_base, self.name, None)
if not refs: return if not refs: return
# Unlink p_value # Unlink p_value
uid = value.o.UID() uid = value.o.UID()
@ -1869,7 +1869,7 @@ class Ref(Type):
objects[i] = objects[i].o objects[i] = objects[i].o
uids = [o.UID() for o in objects] uids = [o.UID() for o in objects]
# Unlink objects that are not referred anymore # Unlink objects that are not referred anymore
refs = getattr(obj, self.name, None) refs = getattr(obj.aq_base, self.name, None)
if refs: if refs:
i = len(refs)-1 i = len(refs)-1
while i >= 0: while i >= 0:
@ -2085,7 +2085,7 @@ class Pod(Type):
def isFrozen(self, obj): def isFrozen(self, obj):
'''Is there a frozen document for p_self on p_obj?''' '''Is there a frozen document for p_self on p_obj?'''
value = getattr(obj.o, self.name, None) value = getattr(obj.o.aq_base, self.name, None)
return isinstance(value, obj.o.getProductConfig().File) return isinstance(value, obj.o.getProductConfig().File)
def getToolInfo(self, obj): def getToolInfo(self, obj):
@ -2098,7 +2098,7 @@ class Pod(Type):
# Get the output format(s) # Get the output format(s)
if self.isFrozen(obj): if self.isFrozen(obj):
# The only available format is the one from the frozen document # The only available format is the one from the frozen document
fileName = getattr(obj.o, self.name).filename fileName = getattr(obj.o.aq_base, self.name).filename
formats = (os.path.splitext(fileName)[1][1:],) formats = (os.path.splitext(fileName)[1][1:],)
else: else:
# Available formats are those which are selected in the tool. # Available formats are those which are selected in the tool.
@ -2115,7 +2115,7 @@ class Pod(Type):
field has been frozen. Else, it means that the value must be field has been frozen. Else, it means that the value must be
retrieved by calling pod to compute the result.''' retrieved by calling pod to compute the result.'''
rq = getattr(obj, 'REQUEST', None) rq = getattr(obj, 'REQUEST', None)
res = getattr(obj, self.name, None) res = getattr(obj.aq_base, self.name, None)
if res and res.size: return FileWrapper(res) # Return the frozen file. if res and res.size: return FileWrapper(res) # Return the frozen file.
# If we are here, it means that we must call pod to compute the file. # If we are here, it means that we must call pod to compute the file.
# A Pod field differs from other field types because there can be # A Pod field differs from other field types because there can be

View file

@ -26,7 +26,8 @@ class BaseMixin:
return self return self
o = property(get_o) o = property(get_o)
def createOrUpdate(self, created, values): def createOrUpdate(self, created, values,
initiator=None, initiatorField=None):
'''This method creates (if p_created is True) or updates an object. '''This method creates (if p_created is True) or updates an object.
p_values are manipulated versions of those from the HTTP request. p_values are manipulated versions of those from the HTTP request.
In the case of an object creation (p_created is True), p_self is a In the case of an object creation (p_created is True), p_self is a
@ -56,13 +57,7 @@ class BaseMixin:
self.historizeData(previousData) self.historizeData(previousData)
# Manage potential link with an initiator object # Manage potential link with an initiator object
if created and rq.get('nav', None): if created and initiator: initiator.appy().link(initiatorField, obj)
# Get the initiator
splitted = rq['nav'].split('.')
if splitted[0] == 'search': return # Not an initiator but a search.
initiator = self.getTool().getObject(splitted[1])
fieldName = splitted[2].split(':')[0]
initiator.appy().link(fieldName, obj)
# Manage "add" permissions and reindex the object # Manage "add" permissions and reindex the object
obj._appy_managePermissions() obj._appy_managePermissions()
@ -182,10 +177,11 @@ class BaseMixin:
# If this object is created from an initiator, get info about him. # If this object is created from an initiator, get info about him.
initiator = None initiator = None
initiatorPage = None initiatorPage = None
initiatorField = None
if rq.get('nav', '').startswith('ref.'): if rq.get('nav', '').startswith('ref.'):
splitted = rq['nav'].split('.') splitted = rq['nav'].split('.')
initiator = tool.getObject(splitted[1]) initiator = tool.getObject(splitted[1])
initiatorPage = splitted[2].split(':')[1] initiatorField, initiatorPage = splitted[2].split(':')
# If the user clicked on 'Cancel', go back to the previous page. # If the user clicked on 'Cancel', go back to the previous page.
if rq.get('buttonCancel.x', None): if rq.get('buttonCancel.x', None):
if initiator: if initiator:
@ -230,14 +226,14 @@ class BaseMixin:
return self.gotoEdit() return self.gotoEdit()
# Create or update the object in the database # Create or update the object in the database
obj, msg = self.createOrUpdate(isNew, values) obj, msg = self.createOrUpdate(isNew, values, initiator, initiatorField)
# Redirect the user to the appropriate page # Redirect the user to the appropriate page
if not msg: msg = obj.translate('Changes saved.', domain='plone') if not msg: msg = obj.translate('Changes saved.', domain='plone')
# If the object has already been deleted (ie, it is a kind of transient # If the object has already been deleted (ie, it is a kind of transient
# object like a one-shot form and has already been deleted in method # object like a one-shot form and has already been deleted in method
# onEdit), redirect to the main site page. # onEdit), redirect to the main site page.
if not getattr(obj.getParentNode(), obj.id, None): if not getattr(obj.getParentNode().aq_base, obj.id, None):
obj.unindexObject() obj.unindexObject()
return self.goto(tool.getSiteUrl(), msg) return self.goto(tool.getSiteUrl(), msg)
# If the user can't access the object anymore, redirect him to the # If the user can't access the object anymore, redirect him to the
@ -426,6 +422,8 @@ class BaseMixin:
def getMethod(self, methodName): def getMethod(self, methodName):
'''Returns the method named p_methodName.''' '''Returns the method named p_methodName.'''
# If I write "self.aq_base" instead of self, acquisition will be
# broken on returned object.
return getattr(self, methodName, None) return getattr(self, methodName, None)
def getFieldValue(self, name, onlyIfSync=False, layoutType=None): def getFieldValue(self, name, onlyIfSync=False, layoutType=None):
@ -441,6 +439,11 @@ class BaseMixin:
field named p_name.''' field named p_name.'''
return self.getAppyType(name).getFormattedValue(self, value) return self.getAppyType(name).getFormattedValue(self, value)
def getFileInfo(self, fileObject):
'''Returns filename and size of p_fileObject.'''
if not fileObject: return {'filename': '', 'size': 0}
return {'filename': fileObject.filename, 'size': fileObject.size}
def getAppyRefs(self, name, startNumber=None): def getAppyRefs(self, name, startNumber=None):
'''Gets the objects linked to me through Ref field named p_name. '''Gets the objects linked to me through Ref field named p_name.
If p_startNumber is None, this method returns all referred objects. If p_startNumber is None, this method returns all referred objects.
@ -498,7 +501,7 @@ class BaseMixin:
def getAppyRefIndex(self, fieldName, obj): def getAppyRefIndex(self, fieldName, obj):
'''Gets the position of p_obj within Ref field named p_fieldName.''' '''Gets the position of p_obj within Ref field named p_fieldName.'''
refs = getattr(self, fieldName, None) refs = getattr(self.aq_base, fieldName, None)
if not refs: raise IndexError() if not refs: raise IndexError()
return refs.index(obj.UID()) return refs.index(obj.UID())
@ -782,7 +785,7 @@ class BaseMixin:
'''This method changes the position of object with uid p_objectUid in '''This method changes the position of object with uid p_objectUid in
reference field p_fieldName to p_newIndex i p_isDelta is False, or reference field p_fieldName to p_newIndex i p_isDelta is False, or
to actualIndex+p_newIndex if p_isDelta is True.''' to actualIndex+p_newIndex if p_isDelta is True.'''
refs = getattr(self, fieldName, None) refs = getattr(self.aq_base, fieldName, None)
oldIndex = refs.index(objectUid) oldIndex = refs.index(objectUid)
refs.remove(objectUid) refs.remove(objectUid)
if isDelta: if isDelta:
@ -1269,7 +1272,7 @@ class BaseMixin:
appyType = self.getAppyType(name) appyType = self.getAppyType(name)
if (not appyType.type =='File') or not appyType.isShowable(self,'view'): if (not appyType.type =='File') or not appyType.isShowable(self,'view'):
return return
theFile = getattr(self, name, None) theFile = getattr(self.aq_base, name, None)
if theFile: if theFile:
response = self.REQUEST.RESPONSE response = self.REQUEST.RESPONSE
response.setHeader('Content-Disposition', 'inline;filename="%s"' % \ response.setHeader('Content-Disposition', 'inline;filename="%s"' % \

View file

@ -1,14 +1,13 @@
<tal:comment replace="nothing">View macro for a File.</tal:comment> <tal:comment replace="nothing">View macro for a File.</tal:comment>
<metal:view define-macro="view" <metal:view define-macro="view"
tal:define="empty python: not value or not value.size; tal:define="info python: contextObj.getFileInfo(value);
empty not: info/size;
imageSrc string:${contextObj/absolute_url}/download?name=$name"> imageSrc string:${contextObj/absolute_url}/download?name=$name">
<tal:file condition="python: not empty and not widget['isImage']"> <tal:file condition="python: not empty and not widget['isImage']">
<img tal:define="icon value/getBestIcon"
tal:condition="icon" tal:attributes="src string: $appUrl/$icon"/>
<a tal:attributes="href imageSrc" <a tal:attributes="href imageSrc"
tal:content="value/filename"> tal:content="info/filename">
</a>&nbsp;&nbsp;- </a>&nbsp;&nbsp;-
<i class="discreet" tal:content="python:'%sKb' % (value.size / 1024)"></i> <i class="discreet" tal:content="python:'%sKb' % (info['size'] / 1024)"></i>
</tal:file> </tal:file>
<tal:image condition="python: not empty and widget['isImage']"> <tal:image condition="python: not empty and widget['isImage']">
<img tal:attributes="src python: imageSrc" /> <img tal:attributes="src python: imageSrc" />
@ -17,14 +16,17 @@
</metal:view> </metal:view>
<tal:comment replace="nothing">Edit macro for an File.</tal:comment> <tal:comment replace="nothing">Edit macro for an File.</tal:comment>
<metal:edit define-macro="edit"> <metal:edit define-macro="edit"
<tal:showFile condition="python: value and value.size"> tal:define="info python: contextObj.getFileInfo(value);
empty not: info/size;">
<tal:showFile condition="not: empty">
<metal:call use-macro="app/skyn/widgets/file/macros/view"/><br/> <metal:call use-macro="app/skyn/widgets/file/macros/view"/><br/>
</tal:showFile> </tal:showFile>
<tal:editButtons condition="python: value and value.size"> <tal:editButtons condition="not: empty">
<tal:comment replace="nothing">Keep the file untouched.</tal:comment> <tal:comment replace="nothing">Keep the file untouched.</tal:comment>
<input type="radio" value="nochange" <input type="radio" value="nochange"
tal:attributes="checked python:test(value.size!=0, 'checked', None); tal:attributes="checked python:test(info['size']!=0, 'checked', None);
name string:${name}_delete; name string:${name}_delete;
id string:${name}_nochange; id string:${name}_nochange;
onclick string:document.getElementById('${name}_file').disabled=true;"/> onclick string:document.getElementById('${name}_file').disabled=true;"/>
@ -43,23 +45,23 @@
</tal:delete> </tal:delete>
<tal:comment replace="nothing">Replace with a new file.</tal:comment> <tal:comment replace="nothing">Replace with a new file.</tal:comment>
<input type="radio" value="" <input type="radio" value=""
tal:attributes="checked python:test(value.size==0, 'checked', None); tal:attributes="checked python:test(info['size']==0, 'checked', None);
name string:${name}_delete; name string:${name}_delete;
id string:${name}_upload; id string:${name}_upload;
onclick string:document.getElementById('${name}_file').disabled=false"/> onclick string:document.getElementById('${name}_file').disabled=false"/>
<label tal:attributes="for string:${name}_upload;" <label tal:attributes="for string:${name}_upload;"
i18n:translate="upload_file" i18n:domain="plone">Replace it with a new file</label> i18n:translate="upload_file" i18n:domain="plone">Replace it with a new file</label>
<br/> <br/>
</tal:editButtons> </tal:editButtons>
<tal:comment replace="nothing">The upload field.</tal:comment> <tal:comment replace="nothing">The upload field.</tal:comment>
<input type="file" <input type="file"
tal:attributes="name string:${name}_file; tal:attributes="name string:${name}_file;
id string:${name}_file; id string:${name}_file;
size widget/width"/> size widget/width"/>
<script type="text/javascript" <script type="text/javascript"
tal:define="isDisabled python:test(value and value.size, 'true', 'false')" tal:define="isDisabled python:test(empty, 'false', 'true')"
tal:content="string: document.getElementById('${name}_file').disabled=$isDisabled;"> tal:content="string: document.getElementById('${name}_file').disabled=$isDisabled;">
</script> </script>
</metal:edit> </metal:edit>
<tal:comment replace="nothing">Cell macro for an File.</tal:comment> <tal:comment replace="nothing">Cell macro for an File.</tal:comment>