[gen] Changes in parameters of some basic field methods to enable field.languages to be defined dymanically via a method.

This commit is contained in:
Gaetan Delannay 2014-09-05 17:13:23 +02:00
parent 18afb4416c
commit f8a7103c7a
15 changed files with 153 additions and 112 deletions

View file

@ -63,7 +63,7 @@ class Field:
value=not isSearch and \
field.getFormattedValue(zobj, rawValue, showChanges);
requestValue=not isSearch and zobj.getRequestFieldValue(name);
inRequest=field.valueIsInRequest(req, name);
inRequest=field.valueIsInRequest(zobj, req, name);
error=req.get('%s_error' % name);
isMultiple=(field.multiplicity[1] == None) or \
(field.multiplicity[1] > 1);
@ -360,7 +360,7 @@ class Field:
else:
master, masterValue = masterData
if masterValue and callable(masterValue): return True
reqValue = master.getRequestValue(obj.REQUEST)
reqValue = master.getRequestValue(obj)
# reqValue can be a list or not
if type(reqValue) not in sutils.sequenceTypes:
return reqValue in masterValue
@ -517,7 +517,7 @@ class Field:
def getValue(self, obj):
'''Gets, on_obj, the value conforming to self's type definition.'''
value = getattr(obj.aq_base, self.name, None)
if self.isEmptyValue(value):
if self.isEmptyValue(obj, value):
# If there is no value, get the default value if any: return
# self.default, of self.default() if it is a method.
if callable(self.default):
@ -539,7 +539,7 @@ class Field:
purposes. Needs to be overridden by some child classes. If
p_showChanges is True, the result must also include the changes that
occurred on p_value across the ages.'''
if self.isEmptyValue(value): return ''
if self.isEmptyValue(obj, value): return ''
return value
def getIndexType(self):
@ -573,7 +573,7 @@ class Field:
res = str(res)
return res
def valueIsInRequest(self, request, name):
def valueIsInRequest(self, obj, request, name):
'''Is there a value corresponding to this field in the request? p_name
can be different from self.name (ie, if it is a field within another
(List) field). In most cases, checking that this p_name is in the
@ -581,7 +581,7 @@ class Field:
for string multilingual fields.'''
return request.has_key(name)
def getRequestValue(self, request, requestName=None):
def getRequestValue(self, obj, requestName=None):
'''Gets a value for this field as carried in the request object. In the
simplest cases, the request value is a single value whose name in the
request is the name of the field.
@ -595,15 +595,15 @@ class Field:
the container field). In this case, p_requestName must be used for
searching into the request, instead of the field name (self.name).'''
name = requestName or self.name
return request.get(name, None)
return obj.REQUEST.get(name, None)
def getStorableValue(self, value):
def getStorableValue(self, obj, value):
'''p_value is a valid value initially computed through calling
m_getRequestValue. So, it is a valid string (or list of strings)
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 self.isEmptyValue(value): return
if self.isEmptyValue(obj, value): return
return value
def getMasterData(self):
@ -634,11 +634,11 @@ class Field:
return 'updateSlaves(this,null,%s,%s,null,null%s)' % \
(q(zobj.absolute_url()), q(layoutType), cName)
def isEmptyValue(self, value, obj=None):
def isEmptyValue(self, obj, value):
'''Returns True if the p_value must be considered as an empty value.'''
return value in self.nullValues
def isCompleteValue(self, value, obj=None):
def isCompleteValue(self, obj, value):
'''Returns True if the p_value must be considered as "complete". While,
in most cases, a "complete" value simply means a "non empty" value
(see m_isEmptyValue above), in some special cases it is more subtle.
@ -648,7 +648,7 @@ class Field:
a Date with the "hour" part required will not be considered as empty
if the "day, month, year" part is present but will not be considered
as complete without the "hour, minute" part.'''
return not self.isEmptyValue(value, obj)
return not self.isEmptyValue(obj, value)
def validateValue(self, obj, value):
'''This method may be overridden by child classes and will be called at
@ -673,7 +673,7 @@ class Field:
definition. If it is the case, None is returned. Else, a translated
error message is returned.'''
# If the value is required, check that a (complete) value is present.
if not self.isCompleteValue(value, obj):
if not self.isCompleteValue(obj, value):
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.
@ -686,7 +686,7 @@ class Field:
message = self.validateValue(obj, value)
if message: return message
# Evaluate the custom validator if one has been specified
value = self.getStorableValue(value)
value = self.getStorableValue(obj, value)
if self.validator and (type(self.validator) in self.validatorTypes):
obj = obj.appy()
if type(self.validator) != self.validatorTypes[-1]:

View file

@ -117,8 +117,8 @@ class Boolean(Field):
def getFormattedValue(self, obj, value, showChanges=False):
return obj.translate(self.getValueLabel(value))
def getStorableValue(self, value):
if not self.isEmptyValue(value):
def getStorableValue(self, obj, value):
if not self.isEmptyValue(obj, value):
exec 'res = %s' % value
return res

View file

@ -207,7 +207,7 @@ class Date(Field):
return obj.translate('bad_date')
def getFormattedValue(self, obj, value, showChanges=False):
if self.isEmptyValue(value): return ''
if self.isEmptyValue(obj, value): return ''
tool = obj.getTool().appy()
# A problem may occur with some extreme year values. Replace the "year"
# part "by hand".
@ -219,7 +219,8 @@ class Date(Field):
res += ' %s' % value.strftime(tool.hourFormat)
return res
def getRequestValue(self, request, requestName=None):
def getRequestValue(self, obj, requestName=None):
request = obj.REQUEST
name = requestName or self.name
# Manage the "date" part
value = ''
@ -238,8 +239,8 @@ class Date(Field):
value = value[:-1]
return value
def getStorableValue(self, value):
if not self.isEmptyValue(value):
def getStorableValue(self, obj, value):
if not self.isEmptyValue(obj, value):
import DateTime
return DateTime.DateTime(value)

View file

@ -327,16 +327,15 @@ class File(Field):
historized, mapping, label, sdefault, scolspan, swidth,
sheight, True)
def getRequestValue(self, request, requestName=None):
def getRequestValue(self, obj, requestName=None):
name = requestName or self.name
return request.get('%s_file' % name)
return obj.REQUEST.get('%s_file' % name)
def getDefaultLayouts(self): return {'view':'l-f','edit':'lrv-f'}
def isEmptyValue(self, value, obj=None):
def isEmptyValue(self, obj, value):
'''Must p_value be considered as empty?'''
if not obj: return Field.isEmptyValue(self, value)
if value: return False
if value: return
# If "nochange", the value must not be considered as empty
return obj.REQUEST.get('%s_delete' % self.name) != 'nochange'

View file

@ -94,8 +94,8 @@ class Float(Field):
except ValueError:
return obj.translate('bad_%s' % self.pythonType.__name__)
def getStorableValue(self, value):
if not self.isEmptyValue(value):
def getStorableValue(self, obj, value):
if not self.isEmptyValue(obj, value):
for sep in self.sep: value = value.replace(sep, '.')
value = value.replace(self.tsep, '')
return self.pythonType(value)

View file

@ -68,10 +68,10 @@ class Integer(Field):
except ValueError:
return obj.translate('bad_%s' % self.pythonType.__name__)
def getStorableValue(self, value):
if not self.isEmptyValue(value): return self.pythonType(value)
def getStorableValue(self, obj, value):
if not self.isEmptyValue(obj, value): return self.pythonType(value)
def getFormattedValue(self, obj, value, showChanges=False):
if self.isEmptyValue(value): return ''
if self.isEmptyValue(obj, value): return ''
return str(value)
# ------------------------------------------------------------------------------

View file

@ -119,8 +119,9 @@ class List(Field):
res.append(elem)
return res
def getRequestValue(self, request, requestName=None):
def getRequestValue(self, obj, requestName=None):
'''Concatenates the list from distinct form elements in the request.'''
request = obj.REQUEST
name = requestName or self.name # A List may be into another List (?)
prefix = name + '*' + self.fields[0][0] + '*'
res = {}
@ -133,7 +134,7 @@ class List(Field):
if rowIndex == -1: continue # Ignore the template row.
for subName, subField in self.fields:
keyName = '%s*%s*%s' % (name, subName, rowIndex)
v = subField.getRequestValue(request, requestName=keyName)
v = subField.getRequestValue(obj, requestName=keyName)
setattr(row, subName, v)
res[rowIndex] = row
# Produce a sorted list.
@ -148,7 +149,7 @@ class List(Field):
request.set(name, res)
return res
def getStorableValue(self, value):
def getStorableValue(self, obj, value):
'''Gets p_value in a form that can be stored in the database.'''
res = []
for v in value:
@ -156,11 +157,11 @@ class List(Field):
for name, field in self.fields:
subValue = getattr(v, name)
try:
setattr(sv, name, field.getStorableValue(subValue))
setattr(sv, name, field.getStorableValue(obj, subValue))
except ValueError:
# The value for this field for this specific row is
# incorrect. It can happen in the process of validating the
# whole List field (a call to getStorableValue occurs at
# whole List field (a call to m_getStorableValue occurs at
# this time). We don't care about it, because later on we
# will have sub-field specific validation that will also
# detect the error and will prevent storing the wrong value

View file

@ -295,7 +295,7 @@ class Pod(Field):
tool = obj.tool
diskFolder = tool.getDiskFolder()
# Get the path to the pod template.
templatePath = os.path.join(diskFolder, template)
templatePath = sutils.resolvePath(os.path.join(diskFolder, template))
if not os.path.isfile(templatePath):
raise Exception(self.TEMPLATE_NOT_FOUND % templatePath)
# Get or compute the specific POD context

View file

@ -130,8 +130,8 @@ class String(Field):
pxMultilingual = Px('''
<!-- Horizontally-layouted multilingual field -->
<table if="mLayout == 'horizontal'" width="100%"
var="count=len(field.languages)">
<tr valign="top"><x for="lg in field.languages"><x>:field.pxLanguage</x>
var="count=len(languages)">
<tr valign="top"><x for="lg in languages"><x>:field.pxLanguage</x>
<td width=":'%d%%' % int(100.0/count)"
var="requestValue=requestValue[lg]|None;
value=value[lg]|emptyDefault">:field.subPx[layoutType][fmt]</td>
@ -139,7 +139,7 @@ class String(Field):
<!-- Vertically-layouted multilingual field -->
<table if="mLayout == 'vertical'">
<tr valign="top" height="20px" for="lg in field.languages">
<tr valign="top" height="20px" for="lg in languages">
<x>:field.pxLanguage</x>
<td var="requestValue=requestValue[lg]|None;
value=value[lg]|emptyDefault">:field.subPx[layoutType][fmt]</td>
@ -147,7 +147,8 @@ class String(Field):
pxView = Px('''
<x var="fmt=field.format; isUrl=field.isUrl;
multilingual=field.isMultilingual();
languages=field.getAttribute(zobj, 'languages');
multilingual=len(languages) &gt; 1;
mLayout=multilingual and field.getLanguagesLayout('view');
mayAjaxEdit=not showChanges and field.inlineEdit and \
zobj.mayEdit(field.writePermission)">
@ -193,7 +194,8 @@ class String(Field):
pxEdit = Px('''
<x var="fmt=field.format;
multilingual=field.isMultilingual();
languages=field.getAttribute(zobj, 'languages');
multilingual=len(languages) &gt; 1;
mLayout=multilingual and field.getLanguagesLayout('edit')">
<select if="field.isSelect"
var2="possibleValues=field.getPossibleValues(zobj, \
@ -447,7 +449,7 @@ class String(Field):
def checkParameters(self):
'''Ensures this String is correctly defined.'''
error = None
if self.isMultilingual():
if self.isMultilingual(None):
if self.isSelect:
error = "A selection field can't be multilingual."
elif self.format in (String.PASSWORD, String.CAPTCHA):
@ -468,7 +470,11 @@ class String(Field):
res = False
return res
def isMultilingual(self): return len(self.languages) > 1
def isMultilingual(self, obj):
'''Is this field multilingual ?.'''
# In the following case, impossible to know: we say no.
if not obj and callable(self.languages): return
return len(self.getAttribute(obj, 'languages')) > 1
def getDefaultLayouts(self):
'''Returns the default layouts for this type. Default layouts can vary
@ -507,45 +513,50 @@ class String(Field):
value = list(value)
return value
def valueIsInRequest(self, request, name):
if not self.isMultilingual():
return Field.valueIsInRequest(self, request, name)
return request.has_key('%s_%s' % (name, self.languages[0]))
def valueIsInRequest(self, obj, request, name):
languages = self.getAttribute(obj, 'languages')
if len(languages) == 1:
return Field.valueIsInRequest(self, obj, request, name)
# Is is sufficient to check that at least one of the language-specific
# values is in the request.
return request.has_key('%s_%s' % (name, languages[0]))
def getRequestValue(self, request, requestName=None):
def getRequestValue(self, obj, requestName=None):
'''The request value may be multilingual.'''
request = obj.REQUEST
name = requestName or self.name
languages = self.getAttribute(obj, 'languages')
# A unilingual field.
if not self.isMultilingual(): return request.get(name, None)
if len(languages) == 1: return request.get(name, None)
# A multilingual field.
res = {}
for language in self.languages:
for language in languages:
res[language] = request.get('%s_%s' % (name, language), None)
return res
def isEmptyValue(self, value, obj=None):
def isEmptyValue(self, obj, value):
'''Returns True if the p_value must be considered as an empty value.'''
if not self.isMultilingual():
return Field.isEmptyValue(self, value, obj)
if not self.isMultilingual(obj):
return Field.isEmptyValue(self, obj, value)
# For a multilingual value, as soon as a value is not empty for a given
# language, the whole value is considered as not being empty.
if not value: return True
for v in value.itervalues():
if not Field.isEmptyValue(self, v, obj): return
if not Field.isEmptyValue(self, obj, v): return
return True
def isCompleteValue(self, value, obj=None):
def isCompleteValue(self, obj, value):
'''Returns True if the p_value must be considered as complete. For a
unilingual field, being complete simply means not being empty. For a
multilingual field, being complete means that a value is present for
every language'''
if not self.isMultilingual():
return Field.isCompleteValue(self, value, obj)
every language.'''
if not self.isMultilingual(obj):
return Field.isCompleteValue(self, obj, value)
# As soon as a given language value is empty, the global value is not
# complete.
if not value: return True
for v in value.itervalues():
if Field.isEmptyValue(self, v, obj): return
if Field.isEmptyValue(self, obj, v): return
return True
def getDiffValue(self, obj, value, language):
@ -581,7 +592,7 @@ class String(Field):
m_getFormattedValue for getting a non-multilingual value (ie, in
most cases). Else, this method returns a formatted value for the
p_language-specific part of a multilingual value.'''
if Field.isEmptyValue(self, value): return ''
if Field.isEmptyValue(self, obj, value): return ''
res = value
if self.isSelect:
if isinstance(self.validator, Selection):
@ -609,13 +620,14 @@ class String(Field):
return res
def getFormattedValue(self, obj, value, showChanges=False):
if not self.isMultilingual():
languages = self.getAttribute(obj, 'languages')
if len(languages) == 1:
return self.getUnilingualFormattedValue(obj, value, showChanges)
# Return the dict of values whose individual, language-specific values
# have been formatted via m_getUnilingualFormattedValue.
if not value: return value
res = {}
for lg in self.languages:
for lg in languages:
res[lg] = self.getUnilingualFormattedValue(obj, value[lg],
showChanges, lg)
return res
@ -631,7 +643,7 @@ class String(Field):
'''Pure text must be extracted from rich content; multilingual content
must be concatenated.'''
isXhtml = self.format == String.XHTML
if self.isMultilingual():
if self.isMultilingual(obj):
res = self.getValue(obj)
if res:
vals = []
@ -775,9 +787,9 @@ class String(Field):
elif self.transform == 'capitalize': return value.capitalize()
return value
def getUnilingualStorableValue(self, value):
def getUnilingualStorableValue(self, obj, value):
isString = isinstance(value, basestring)
isEmpty = Field.isEmptyValue(self, value)
isEmpty = Field.isEmptyValue(self, obj, value)
# Apply transform if required
if isString and not isEmpty and (self.transform != 'none'):
value = self.applyTransform(value)
@ -804,21 +816,23 @@ class String(Field):
value = [value]
return value
def getStorableValue(self, value):
if not self.isMultilingual():
return self.getUnilingualStorableValue(value)
def getStorableValue(self, obj, value):
languages = self.getAttribute(obj, 'languages')
if len(languages) == 1:
return self.getUnilingualStorableValue(obj, value)
# A multilingual value is stored as a dict whose keys are ISO 2-letters
# language codes and whose values are strings storing content in the
# language ~{s_language: s_content}~.
if not value: return
for lg in self.languages:
value[lg] = self.getUnilingualStorableValue(value[lg])
for lg in languages:
value[lg] = self.getUnilingualStorableValue(obj, value[lg])
return value
def store(self, obj, value):
'''Stores p_value on p_obj for this field.'''
if self.isMultilingual() and value and \
(not isinstance(value, dict) or (len(value) != len(self.languages))):
languages = self.getAttribute(obj, 'languages')
if (len(languages) > 1) and value and \
(not isinstance(value, dict) or (len(value) != len(languages))):
raise Exception('Multilingual field "%s" accepts a dict whose '\
'keys are in field.languages and whose ' \
'values are strings.' % self.name)
@ -832,16 +846,16 @@ class String(Field):
requestValue = rq['fieldContent']
# Remember previous value if the field is historized.
previousData = obj.rememberPreviousData([self])
if self.isMultilingual():
if self.isMultilingual(obj):
# We take a copy of previousData because it is mutable (dict).
previousData[self.name] = previousData[self.name].copy()
# We get a partial value, for one language only.
language = rq['languageOnly']
v = self.getUnilingualStorableValue(requestValue)
v = self.getUnilingualStorableValue(obj, requestValue)
getattr(obj.aq_base, self.name)[language] = v
part = ' (%s)' % language
else:
self.store(obj, self.getStorableValue(requestValue))
self.store(obj, self.getStorableValue(obj, requestValue))
part = ''
# Update the object history when relevant
if previousData: obj.historizeData(previousData)
@ -892,11 +906,12 @@ class String(Field):
'fi': 'fi_FI', 'fr': 'fr_FR', 'de': 'de_DE', 'el': 'el_GR',
'it': 'it_IT', 'nb': 'nb_NO', 'pt': 'pt_PT', 'es': 'es_ES',
'sv': 'sv_SE'}
def getCkLanguage(self, language):
def getCkLanguage(self, obj, language):
'''Gets the language for CK editor SCAYT. p_language is one of
self.languages if the field is multilingual, None else. If p_language
is not supported by CK, we use english.'''
if not language: language = self.languages[0]
if not language:
language = self.getAttribute(obj, 'languages')[0]
if language in self.ckLanguages: return self.ckLanguages[language]
return 'en_US'
@ -904,7 +919,7 @@ class String(Field):
'''Gets the base params to set on a rich text field.'''
ckAttrs = {'toolbar': 'Appy',
'format_tags': ';'.join(self.styles),
'scayt_sLang': self.getCkLanguage(language)}
'scayt_sLang': self.getCkLanguage(obj, language)}
if self.width: ckAttrs['width'] = self.width
if self.spellcheck: ckAttrs['scayt_autoStartup'] = True
if self.allowImageUpload: