Several bugfixes for 0.6 series (bugfix while defining pod fields in a custom tool, bugfix in the creation flag, import of objects was broken...) and minor improvements in the layouting system (automatic generation of 'cell' layouts was optimized).

This commit is contained in:
Gaetan Delannay 2010-11-10 15:15:00 +01:00
parent 3d87036f85
commit 7dc55f23c2
11 changed files with 230 additions and 207 deletions

View file

@ -675,7 +675,7 @@ class Type:
'''p_value is a real p_obj(ect) value from a field from this type. This
method returns a pretty, string-formatted version, for displaying
purposes. Needs to be overridden by some child classes.'''
if value in nullValues: return ''
if self.isEmptyValue(value): return ''
return value
def getRequestValue(self, request):
@ -689,7 +689,7 @@ class Type:
representation of the field value coming from the request.
This method computes the real (potentially converted or manipulated
in some other way) value as can be stored in the database.'''
if value in nullValues: return None
if self.isEmptyValue(value): return None
return value
def getMasterData(self):
@ -698,6 +698,10 @@ class Type:
if self.master: return (self.master, self.masterValue)
if self.group: return self.group.getMasterData()
def isEmptyValue(self, value, obj=None):
'''Returns True if the p_value must be considered as an empty value.'''
return value in nullValues
def validateValue(self, obj, value):
'''This method may be overridden by child classes and will be called at
the right moment by m_validate defined below for triggering
@ -711,7 +715,7 @@ class Type:
definition. If it is the case, None is returned. Else, a translated
error message is returned.'''
# Check that a value is given if required.
if value in nullValues:
if self.isEmptyValue(value, obj):
if self.required and self.isClientVisible(obj):
# If the field is required, but not visible according to
# master/slave relationships, we consider it not to be required.
@ -759,6 +763,28 @@ class Type:
p_self type definition on p_obj.'''
setattr(obj, self.name, value)
def clone(self, forTool=True):
'''Returns a clone of myself. If p_forTool is True, the clone will be
adapted to its life into the tool.'''
res = copy.copy(self)
res.group = copy.copy(self.group)
res.page = copy.copy(self.page)
if not forTool: return res
# A field added to the tool can't have parameters that would lead to the
# creation of new fields in the tool.
res.editDefault = False
res.optional = False
res.show = True
# Set default layouts for all Tool fields
res.layouts = res.formatLayouts(None)
res.specificReadPermission = False
res.specificWritePermission = False
res.multiplicity = (0, self.multiplicity[1])
if type(res.validator) == types.FunctionType:
# We will not be able to call this function from the tool.
res.validator = None
return res
class Integer(Type):
def __init__(self, validator=None, multiplicity=(0,1), index=None,
default=None, optional=False, editDefault=False, show=True,
@ -781,7 +807,11 @@ class Integer(Type):
return obj.translate('bad_%s' % self.pythonType.__name__)
def getStorableValue(self, value):
if value not in nullValues: return self.pythonType(value)
if not self.isEmptyValue(value): return self.pythonType(value)
def getFormattedValue(self, obj, value):
if self.isEmptyValue(value): return ''
return str(value)
class Float(Type):
allowedDecimalSeps = (',', '.')
@ -814,7 +844,7 @@ class Float(Type):
self.pythonType = float
def getFormattedValue(self, obj, value):
if value in nullValues: return ''
if self.isEmptyValue(value): return ''
# Determine the field separator
sep = self.sep[0]
# Produce the rounded string representation
@ -847,7 +877,7 @@ class Float(Type):
return obj.translate('bad_%s' % self.pythonType.__name__)
def getStorableValue(self, value):
if value not in nullValues:
if not self.isEmptyValue(value):
for sep in self.sep: value = value.replace(sep, '.')
return self.pythonType(value)
@ -1021,7 +1051,7 @@ class String(Type):
return value
def getFormattedValue(self, obj, value):
if value in nullValues: return ''
if self.isEmptyValue(value): return ''
res = value
if self.isSelect:
if isinstance(self.validator, Selection):
@ -1148,7 +1178,7 @@ class Boolean(Type):
return res
def getStorableValue(self, value):
if value not in nullValues:
if not self.isEmptyValue(value):
exec 'res = %s' % value
return res
@ -1187,7 +1217,7 @@ class Date(Type):
'jscalendar/calendar-en.js')
def getFormattedValue(self, obj, value):
if value in nullValues: return ''
if self.isEmptyValue(value): return ''
res = value.strftime('%d/%m/') + str(value.year())
if self.format == Date.WITH_HOUR:
res += ' %s' % value.strftime('%H:%M')
@ -1212,7 +1242,7 @@ class Date(Type):
return value
def getStorableValue(self, value):
if value not in nullValues:
if not self.isEmptyValue(value):
import DateTime
return DateTime.DateTime(value)
@ -1246,13 +1276,21 @@ class File(Type):
def getDefaultLayouts(self): return {'view':'lf','edit':'lrv-f'}
def isEmptyValue(self, value, obj=None):
'''Must p_value be considered as empty?'''
if not obj: return Type.isEmptyValue(self, value)
if value is not None: return False
# If "nochange", the value must not be considered as empty
return obj.REQUEST.get('%s_delete' % self.name) != 'nochange'
imageExts = ('.jpg', '.jpeg', '.png', '.gif')
def validateValue(self, obj, value):
form = obj.REQUEST.form
action = '%s_delete' % self.name
if not value.filename and form.has_key(action) and not form[action]:
if (not value or not value.filename) and form.has_key(action) and \
not form[action]:
# If this key is present but empty, it means that the user selected
# "replace the file with a new one". So in this cas he must provide
# "replace the file with a new one". So in this case he must provide
# a new file to upload.
return obj.translate('file_required')
# Check that, if self.isImage, the uploaded file is really an image
@ -1345,7 +1383,7 @@ class Ref(Type):
historized, sync)
self.validable = self.link
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
def getDefaultLayouts(self): return {'view': Table('l-f'), 'edit': 'lrv-f'}
def isShowable(self, obj, layoutType):
res = Type.isShowable(self, obj, layoutType)
@ -1470,6 +1508,18 @@ class Ref(Type):
refs = [obj.uid_catalog(UID=uid)[0].getObject() for uid in uids]
exec 'obj.set%s%s(refs)' % (self.name[0].upper(), self.name[1:])
def clone(self, forTool=True):
'''Produces a clone of myself.'''
res = Type.clone(self, forTool)
res.back = copy.copy(self.back)
if not forTool: return res
res.link = True
res.add = False
res.back.attribute += 'DefaultValue'
res.back.show = False
res.select = None # Not callable from tool.
return res
class Computed(Type):
def __init__(self, validator=None, multiplicity=(0,1), index=None,
default=None, optional=False, editDefault=False, show='view',
@ -1491,18 +1541,17 @@ class Computed(Type):
def getValue(self, obj):
'''Computes the value instead of getting it in the database.'''
if not self.method: return ''
if not self.method: return
obj = obj.appy()
try:
res = self.method(obj)
if not isinstance(res, basestring):
res = repr(res)
return self.method(obj)
except Exception, e:
obj.log(Traceback.get(), type='error')
res = str(e)
return res
return str(e)
def getFormattedValue(self, obj, value): return value
def getFormattedValue(self, obj, value):
if not isinstance(value, basestring): return str(value)
return value
class Action(Type):
'''An action is a workflow-independent Python method that can be triggered