appy.gen: use new index 'getState' for indexing object states; reduced size of generated file config.py; optimized debug mode: class reload is not done automatically: a 'refresh' icon is available on view and edit views.
This commit is contained in:
parent
9258b76bdf
commit
b6dcc42038
|
@ -326,7 +326,6 @@ class Search:
|
||||||
elif fieldName == 'description':
|
elif fieldName == 'description':
|
||||||
if usage == 'search': return 'Description'
|
if usage == 'search': return 'Description'
|
||||||
else: return None
|
else: return None
|
||||||
elif fieldName == 'state': return 'review_state'
|
|
||||||
else:
|
else:
|
||||||
return 'get%s%s'% (fieldName[0].upper(),fieldName[1:])
|
return 'get%s%s'% (fieldName[0].upper(),fieldName[1:])
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -487,24 +486,27 @@ class Type:
|
||||||
called for storing the name of the Appy field (p_name) and other
|
called for storing the name of the Appy field (p_name) and other
|
||||||
attributes that are based on the name of the Appy p_klass, and the
|
attributes that are based on the name of the Appy p_klass, and the
|
||||||
application name (p_appName).'''
|
application name (p_appName).'''
|
||||||
|
if hasattr(self, 'name'): return # Already initialized
|
||||||
self.name = name
|
self.name = name
|
||||||
|
# Determine prefix for this class
|
||||||
|
if not klass: prefix = appName
|
||||||
|
else: prefix = getClassName(klass, appName)
|
||||||
# Recompute the ID (and derived attributes) that may have changed if
|
# Recompute the ID (and derived attributes) that may have changed if
|
||||||
# we are in debug mode (because we recreate new Type instances).
|
# we are in debug mode (because we recreate new Type instances).
|
||||||
self.id = id(self)
|
self.id = id(self)
|
||||||
if self.slaves: self.master_css = 'appyMaster master_%s' % self.id
|
if self.slaves: self.master_css = 'appyMaster master_%s' % self.id
|
||||||
# Determine ids of i18n labels for this field
|
# Determine ids of i18n labels for this field
|
||||||
labelName = name
|
labelName = name
|
||||||
prefix = None
|
trPrefix = None
|
||||||
if self.label:
|
if self.label:
|
||||||
if isinstance(self.label, basestring): prefix = self.label
|
if isinstance(self.label, basestring): trPrefix = self.label
|
||||||
else: # It is a tuple (prefix, name)
|
else: # It is a tuple (trPrefix, name)
|
||||||
if self.label[1]: labelName = self.label[1]
|
if self.label[1]: labelName = self.label[1]
|
||||||
if self.label[0]: prefix = self.label[0]
|
if self.label[0]: trPrefix = self.label[0]
|
||||||
if not prefix:
|
if not trPrefix:
|
||||||
if not klass: prefix = appName
|
trPrefix = prefix
|
||||||
else: prefix = getClassName(klass, appName)
|
|
||||||
# Determine name to use for i18n
|
# Determine name to use for i18n
|
||||||
self.labelId = '%s_%s' % (prefix, labelName)
|
self.labelId = '%s_%s' % (trPrefix, labelName)
|
||||||
self.descrId = self.labelId + '_descr'
|
self.descrId = self.labelId + '_descr'
|
||||||
self.helpId = self.labelId + '_help'
|
self.helpId = self.labelId + '_help'
|
||||||
# Determine read and write permissions for this field
|
# Determine read and write permissions for this field
|
||||||
|
@ -522,9 +524,10 @@ class Type:
|
||||||
self.writePermission = wp
|
self.writePermission = wp
|
||||||
else:
|
else:
|
||||||
self.writePermission = 'Modify portal content'
|
self.writePermission = 'Modify portal content'
|
||||||
if isinstance(self, Ref):
|
|
||||||
self.backd = self.back.__dict__
|
|
||||||
if isinstance(self, Ref) and not self.isBack:
|
if isinstance(self, Ref) and not self.isBack:
|
||||||
|
# We must initialise the corresponding back reference
|
||||||
|
self.back.klass = klass
|
||||||
|
self.back.init(self.back.attribute, self.klass, appName)
|
||||||
self.back.relationship = '%s_%s_rel' % (prefix, name)
|
self.back.relationship = '%s_%s_rel' % (prefix, name)
|
||||||
|
|
||||||
def reload(self, klass, obj):
|
def reload(self, klass, obj):
|
||||||
|
@ -534,6 +537,7 @@ class Type:
|
||||||
module has been performed.'''
|
module has been performed.'''
|
||||||
res = getattr(klass, self.name, None)
|
res = getattr(klass, self.name, None)
|
||||||
if not res: return self
|
if not res: return self
|
||||||
|
if isinstance(self, Ref) and self.isBack: return self
|
||||||
res.init(self.name, klass, obj.getProductConfig().PROJECTNAME)
|
res.init(self.name, klass, obj.getProductConfig().PROJECTNAME)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -1693,6 +1697,7 @@ class Ref(Type):
|
||||||
back.isBack = True
|
back.isBack = True
|
||||||
back.back = self
|
back.back = self
|
||||||
back.backd = self.__dict__
|
back.backd = self.__dict__
|
||||||
|
setattr(klass, back.attribute, back)
|
||||||
# When displaying a tabular list of referenced objects, must we show
|
# When displaying a tabular list of referenced objects, must we show
|
||||||
# the table headers?
|
# the table headers?
|
||||||
self.showHeaders = showHeaders
|
self.showHeaders = showHeaders
|
||||||
|
@ -2487,7 +2492,7 @@ class Transition:
|
||||||
targetState.updatePermissions(wf, obj)
|
targetState.updatePermissions(wf, obj)
|
||||||
# Refresh catalog-related security if required
|
# Refresh catalog-related security if required
|
||||||
if not obj.isTemporary():
|
if not obj.isTemporary():
|
||||||
obj.reindexObject(idxs=('allowedRolesAndUsers','review_state'))
|
obj.reindexObject(idxs=('allowedRolesAndUsers', 'getState'))
|
||||||
# Execute the related action if needed
|
# Execute the related action if needed
|
||||||
msg = ''
|
msg = ''
|
||||||
if doAction and self.action: msg = self.executeAction(obj, wf)
|
if doAction and self.action: msg = self.executeAction(obj, wf)
|
||||||
|
@ -2654,12 +2659,4 @@ class Config:
|
||||||
# Language that will be used as a basis for translating to other
|
# Language that will be used as a basis for translating to other
|
||||||
# languages.
|
# languages.
|
||||||
self.sourceLanguage = 'en'
|
self.sourceLanguage = 'en'
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# Special field "type" is mandatory for every class. If one class does not
|
|
||||||
# define it, we will add a copy of the instance defined below.
|
|
||||||
title = String(multiplicity=(1,1), show='edit')
|
|
||||||
title.init('title', None, 'appy')
|
|
||||||
state = String()
|
|
||||||
state.init('state', None, 'appy')
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -370,40 +370,21 @@ class Generator(AbstractGenerator):
|
||||||
# Compute the list of ordered attributes (forward and backward,
|
# Compute the list of ordered attributes (forward and backward,
|
||||||
# inherited included) for every Appy class.
|
# inherited included) for every Appy class.
|
||||||
attributes = []
|
attributes = []
|
||||||
attributesDict = []
|
|
||||||
for classDescr in classesAll:
|
for classDescr in classesAll:
|
||||||
titleFound = False
|
titleFound = False
|
||||||
attrs = []
|
names = []
|
||||||
attrNames = []
|
|
||||||
for name, appyType, klass in classDescr.getOrderedAppyAttributes():
|
for name, appyType, klass in classDescr.getOrderedAppyAttributes():
|
||||||
attrs.append(self.getAppyTypePath(name, appyType, klass))
|
names.append(name)
|
||||||
attrNames.append(name)
|
|
||||||
if name == 'title': titleFound = True
|
if name == 'title': titleFound = True
|
||||||
# Add the "title" mandatory field if not found
|
# Add the "title" mandatory field if not found
|
||||||
if not titleFound:
|
if not titleFound: names.insert(0, 'title')
|
||||||
attrs.insert(0, 'copy.deepcopy(appy.gen.title)')
|
|
||||||
attrNames.insert(0, 'title')
|
|
||||||
# Any backward attributes to append?
|
# Any backward attributes to append?
|
||||||
if classDescr.name in self.referers:
|
if classDescr.name in self.referers:
|
||||||
for field, rel in self.referers[classDescr.name]:
|
for field, rel in self.referers[classDescr.name]:
|
||||||
try:
|
names.append(field.appyType.back.attribute)
|
||||||
getattr(field.classDescr.klass, field.fieldName)
|
qNames = ['"%s"' % name for name in names]
|
||||||
klass = field.classDescr.klass
|
attributes.append('"%s":[%s]' % (classDescr.name, ','.join(qNames)))
|
||||||
except AttributeError:
|
|
||||||
klass = field.classDescr.modelClass
|
|
||||||
attrs.append(self.getAppyTypePath(field.fieldName,
|
|
||||||
field.appyType, klass, isBack=True))
|
|
||||||
attrNames.append(field.appyType.back.attribute)
|
|
||||||
attributes.append('"%s":[%s]' % (classDescr.name,','.join(attrs)))
|
|
||||||
aDict = ''
|
|
||||||
i = -1
|
|
||||||
for attr in attrs:
|
|
||||||
i += 1
|
|
||||||
aDict += '"%s":attributes["%s"][%d],' % \
|
|
||||||
(attrNames[i], classDescr.name, i)
|
|
||||||
attributesDict.append('"%s":{%s}' % (classDescr.name, aDict))
|
|
||||||
repls['attributes'] = ',\n '.join(attributes)
|
repls['attributes'] = ',\n '.join(attributes)
|
||||||
repls['attributesDict'] = ',\n '.join(attributesDict)
|
|
||||||
# Compute list of used roles for registering them if needed
|
# Compute list of used roles for registering them if needed
|
||||||
specificRoles = self.getAllUsedRoles(plone=False)
|
specificRoles = self.getAllUsedRoles(plone=False)
|
||||||
repls['roles'] = ','.join(['"%s"' % r.name for r in specificRoles])
|
repls['roles'] = ','.join(['"%s"' % r.name for r in specificRoles])
|
||||||
|
|
|
@ -6,7 +6,7 @@ import os, os.path, time
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from sets import Set
|
from sets import Set
|
||||||
import appy
|
import appy
|
||||||
from appy.gen import Type, Ref
|
from appy.gen import Type, Ref, String
|
||||||
from appy.gen.po import PoParser
|
from appy.gen.po import PoParser
|
||||||
from appy.gen.utils import produceNiceMessage
|
from appy.gen.utils import produceNiceMessage
|
||||||
from appy.gen.plone25.utils import updateRolesForPermission
|
from appy.gen.plone25.utils import updateRolesForPermission
|
||||||
|
@ -231,10 +231,11 @@ class PloneInstaller:
|
||||||
'''Creates or updates the POD templates in the tool according to pod
|
'''Creates or updates the POD templates in the tool according to pod
|
||||||
declarations in the application classes.'''
|
declarations in the application classes.'''
|
||||||
# Creates the templates for Pod fields if they do not exist.
|
# Creates the templates for Pod fields if they do not exist.
|
||||||
for contentType, appyTypes in self.attributes.iteritems():
|
for contentType in self.attributes.iterkeys():
|
||||||
appyClass = self.tool.getAppyClass(contentType)
|
appyClass = self.tool.getAppyClass(contentType)
|
||||||
if not appyClass: continue # May be an abstract class
|
if not appyClass: continue # May be an abstract class
|
||||||
for appyType in appyTypes:
|
wrapperClass = self.tool.getAppyClass(contentType, wrapper=True)
|
||||||
|
for appyType in wrapperClass.__fields__:
|
||||||
if appyType.type != 'Pod': continue
|
if appyType.type != 'Pod': continue
|
||||||
# Find the attribute that stores the template, and store on
|
# Find the attribute that stores the template, and store on
|
||||||
# it the default one specified in the appyType if no
|
# it the default one specified in the appyType if no
|
||||||
|
@ -290,6 +291,7 @@ class PloneInstaller:
|
||||||
nvProps.manage_changeProperties(**{'idsNotToList': current})
|
nvProps.manage_changeProperties(**{'idsNotToList': current})
|
||||||
|
|
||||||
self.tool = getattr(self.ploneSite, self.toolInstanceName)
|
self.tool = getattr(self.ploneSite, self.toolInstanceName)
|
||||||
|
self.tool.refreshSecurity()
|
||||||
self.appyTool = self.tool.appy()
|
self.appyTool = self.tool.appy()
|
||||||
if self.reinstall:
|
if self.reinstall:
|
||||||
self.tool.createOrUpdate(False, None)
|
self.tool.createOrUpdate(False, None)
|
||||||
|
@ -413,9 +415,12 @@ class PloneInstaller:
|
||||||
def manageIndexes(self):
|
def manageIndexes(self):
|
||||||
'''For every indexed field, this method installs and updates the
|
'''For every indexed field, this method installs and updates the
|
||||||
corresponding index if it does not exist yet.'''
|
corresponding index if it does not exist yet.'''
|
||||||
indexInfo = {}
|
# Create a special index for object state, that does not correspond to
|
||||||
for className, appyTypes in self.attributes.iteritems():
|
# a field.
|
||||||
for appyType in appyTypes:
|
indexInfo = {'getState': 'FieldIndex'}
|
||||||
|
for className in self.attributes.iterkeys():
|
||||||
|
wrapperClass = self.tool.getAppyClass(className, wrapper=True)
|
||||||
|
for appyType in wrapperClass.__fields__:
|
||||||
if not appyType.indexed or (appyType.name == 'title'): continue
|
if not appyType.indexed or (appyType.name == 'title'): continue
|
||||||
n = appyType.name
|
n = appyType.name
|
||||||
indexName = 'get%s%s' % (n[0].upper(), n[1:])
|
indexName = 'get%s%s' % (n[0].upper(), n[1:])
|
||||||
|
@ -553,17 +558,25 @@ class ZopeInstaller:
|
||||||
def completeAppyTypes(self):
|
def completeAppyTypes(self):
|
||||||
'''We complete here the initialisation process of every Appy type of
|
'''We complete here the initialisation process of every Appy type of
|
||||||
every gen-class of the application.'''
|
every gen-class of the application.'''
|
||||||
|
appName = self.productName
|
||||||
for klass in self.classes:
|
for klass in self.classes:
|
||||||
|
# Store on wrapper class the ordered list of Appy types
|
||||||
|
wrapperClass = klass.wrapperClass
|
||||||
|
if not hasattr(wrapperClass, 'title'):
|
||||||
|
# Special field "type" is mandatory for every class.
|
||||||
|
title = String(multiplicity=(1,1), show='edit', indexed=True)
|
||||||
|
title.init('title', None, 'appy')
|
||||||
|
setattr(wrapperClass, 'title', title)
|
||||||
|
names = self.config.attributes[wrapperClass.__name__[:-8]]
|
||||||
|
wrapperClass.__fields__ = [getattr(wrapperClass, n) for n in names]
|
||||||
|
# Post-initialise every Appy type
|
||||||
for baseClass in klass.wrapperClass.__bases__:
|
for baseClass in klass.wrapperClass.__bases__:
|
||||||
|
if baseClass.__name__ == 'AbstractWrapper': continue
|
||||||
for name, appyType in baseClass.__dict__.iteritems():
|
for name, appyType in baseClass.__dict__.iteritems():
|
||||||
if isinstance(appyType, Type):
|
if not isinstance(appyType, Type) or \
|
||||||
appyType.init(name, baseClass, self.productName)
|
(isinstance(appyType, Ref) and appyType.isBack):
|
||||||
# Do not forget back references
|
continue # Back refs are initialised within fw refs
|
||||||
if isinstance(appyType, Ref):
|
appyType.init(name, baseClass, appName)
|
||||||
bAppyType = appyType.back
|
|
||||||
bAppyType.init(bAppyType.attribute, appyType.klass,
|
|
||||||
self.productName)
|
|
||||||
bAppyType.klass = baseClass
|
|
||||||
|
|
||||||
def installApplication(self):
|
def installApplication(self):
|
||||||
'''Performs some application-wide installation steps.'''
|
'''Performs some application-wide installation steps.'''
|
||||||
|
|
|
@ -79,10 +79,9 @@ class ToolMixin(BaseMixin):
|
||||||
def _appy_getAllFields(self, contentType):
|
def _appy_getAllFields(self, contentType):
|
||||||
'''Returns the (translated) names of fields of p_contentType.'''
|
'''Returns the (translated) names of fields of p_contentType.'''
|
||||||
res = []
|
res = []
|
||||||
for appyType in self.getProductConfig().attributes[contentType]:
|
for appyType in self.getAllAppyTypes(className=contentType):
|
||||||
if appyType.name != 'title': # Will be included by default.
|
if appyType.name == 'title': continue # Will be included by default.
|
||||||
label = '%s_%s' % (contentType, appyType.name)
|
res.append((appyType.name, self.translate(appyType.labelId)))
|
||||||
res.append((appyType.name, self.translate(label)))
|
|
||||||
# Add object state
|
# Add object state
|
||||||
res.append(('workflowState', self.translate('workflow_state')))
|
res.append(('workflowState', self.translate('workflow_state')))
|
||||||
return res
|
return res
|
||||||
|
@ -91,7 +90,7 @@ class ToolMixin(BaseMixin):
|
||||||
'''Returns the (translated) names of fields that may be searched on
|
'''Returns the (translated) names of fields that may be searched on
|
||||||
objects of type p_contentType (=indexed fields).'''
|
objects of type p_contentType (=indexed fields).'''
|
||||||
res = []
|
res = []
|
||||||
for appyType in self.getProductConfig().attributes[contentType]:
|
for appyType in self.getAllAppyTypes(className=contentType):
|
||||||
if appyType.indexed:
|
if appyType.indexed:
|
||||||
res.append((appyType.name, self.translate(appyType.labelId)))
|
res.append((appyType.name, self.translate(appyType.labelId)))
|
||||||
return res
|
return res
|
||||||
|
@ -343,26 +342,23 @@ class ToolMixin(BaseMixin):
|
||||||
def getPublishedObject(self):
|
def getPublishedObject(self):
|
||||||
'''Gets the currently published object, if its meta_class is among
|
'''Gets the currently published object, if its meta_class is among
|
||||||
application classes.'''
|
application classes.'''
|
||||||
rq = self.REQUEST
|
obj = self.REQUEST['PUBLISHED']
|
||||||
obj = rq['PUBLISHED']
|
|
||||||
parent = obj.getParentNode()
|
parent = obj.getParentNode()
|
||||||
if parent.id == 'skyn':
|
if parent.id == 'skyn': obj = parent.getParentNode()
|
||||||
obj = parent.getParentNode()
|
if obj.meta_type in self.getProductConfig().attributes: return obj
|
||||||
if obj.meta_type in self.getProductConfig().attributes:
|
|
||||||
return obj
|
|
||||||
return None
|
|
||||||
|
|
||||||
def getAppyClass(self, contentType):
|
def getAppyClass(self, contentType, wrapper=False):
|
||||||
'''Gets the Appy Python class that is related to p_contentType.'''
|
'''Gets the Appy Python class that is related to p_contentType.'''
|
||||||
# Retrieve first the Archetypes class corresponding to p_ContentType
|
# Retrieve first the Archetypes class corresponding to p_ContentType
|
||||||
portalType = self.portal_types.get(contentType)
|
portalType = self.portal_types.get(contentType)
|
||||||
if not portalType: return None
|
if not portalType: return
|
||||||
atClassName = portalType.getProperty('content_meta_type')
|
atClassName = portalType.getProperty('content_meta_type')
|
||||||
appName = self.getProductConfig().PROJECTNAME
|
appName = self.getProductConfig().PROJECTNAME
|
||||||
exec 'from Products.%s.%s import %s as atClass' % \
|
exec 'from Products.%s.%s import %s as atClass' % \
|
||||||
(appName, atClassName, atClassName)
|
(appName, atClassName, atClassName)
|
||||||
# Get then the Appy Python class
|
# Get then the Appy Python class
|
||||||
return atClass.wrapperClass.__bases__[-1]
|
if wrapper: return atClass.wrapperClass
|
||||||
|
else: return atClass.wrapperClass.__bases__[-1]
|
||||||
|
|
||||||
def getCreateMeans(self, contentTypeOrAppyClass):
|
def getCreateMeans(self, contentTypeOrAppyClass):
|
||||||
'''Gets the different ways objects of p_contentTypeOrAppyClass (which
|
'''Gets the different ways objects of p_contentTypeOrAppyClass (which
|
||||||
|
@ -395,6 +391,8 @@ class ToolMixin(BaseMixin):
|
||||||
'''This method checks if the currently logged user can trigger searches
|
'''This method checks if the currently logged user can trigger searches
|
||||||
on a given p_rootClass. This is done by calling method "maySearch"
|
on a given p_rootClass. This is done by calling method "maySearch"
|
||||||
on the class. If no such method exists, we return True.'''
|
on the class. If no such method exists, we return True.'''
|
||||||
|
# When editign a form, one should avoid annoying the user with this.
|
||||||
|
if self.REQUEST['ACTUAL_URL'].endswith('/edit'): return
|
||||||
pythonClass = self.getAppyClass(rootClass)
|
pythonClass = self.getAppyClass(rootClass)
|
||||||
if 'maySearch' in pythonClass.__dict__:
|
if 'maySearch' in pythonClass.__dict__:
|
||||||
return pythonClass.maySearch(self.appy())
|
return pythonClass.maySearch(self.appy())
|
||||||
|
|
|
@ -51,10 +51,7 @@ class BaseMixin:
|
||||||
for appyType in self.getAppyTypes('edit', rq.get('page')):
|
for appyType in self.getAppyTypes('edit', rq.get('page')):
|
||||||
value = getattr(values, appyType.name, None)
|
value = getattr(values, appyType.name, None)
|
||||||
appyType.store(obj, value)
|
appyType.store(obj, value)
|
||||||
if created:
|
if created: obj.unmarkCreationFlag()
|
||||||
# Now we have a title for the object, so we derive a nice id
|
|
||||||
obj.unmarkCreationFlag()
|
|
||||||
obj._renameAfterCreation(check_auto_id=True)
|
|
||||||
if previousData:
|
if previousData:
|
||||||
# Keep in history potential changes on historized fields
|
# Keep in history potential changes on historized fields
|
||||||
self.historizeData(previousData)
|
self.historizeData(previousData)
|
||||||
|
@ -499,7 +496,6 @@ class BaseMixin:
|
||||||
'''Are we in debug mode ?'''
|
'''Are we in debug mode ?'''
|
||||||
for arg in sys.argv:
|
for arg in sys.argv:
|
||||||
if arg == 'debug-mode=on': return True
|
if arg == 'debug-mode=on': return True
|
||||||
return False
|
|
||||||
|
|
||||||
def getClass(self, reloaded=False):
|
def getClass(self, reloaded=False):
|
||||||
'''Returns the Appy class that dictates self's behaviour.'''
|
'''Returns the Appy class that dictates self's behaviour.'''
|
||||||
|
@ -524,30 +520,34 @@ class BaseMixin:
|
||||||
def getAppyType(self, name, asDict=False, className=None):
|
def getAppyType(self, name, asDict=False, className=None):
|
||||||
'''Returns the Appy type named p_name. If no p_className is defined, the
|
'''Returns the Appy type named p_name. If no p_className is defined, the
|
||||||
field is supposed to belong to self's class.'''
|
field is supposed to belong to self's class.'''
|
||||||
className = className or self.__class__.__name__
|
if not className:
|
||||||
attrs = self.getProductConfig().attributesDict[className]
|
klass = self.__class__.wrapperClass
|
||||||
appyType = attrs.get(name, None)
|
else:
|
||||||
if appyType and asDict: return appyType.__dict__
|
klass = self.getTool().getAppyClass(className, wrapper=True)
|
||||||
return appyType
|
res = getattr(klass, name, None)
|
||||||
|
if res and asDict: return res.__dict__
|
||||||
|
return res
|
||||||
|
|
||||||
def getAllAppyTypes(self, className=None):
|
def getAllAppyTypes(self, className=None):
|
||||||
'''Returns the ordered list of all Appy types for self's class if
|
'''Returns the ordered list of all Appy types for self's class if
|
||||||
p_className is not specified, or for p_className else.'''
|
p_className is not specified, or for p_className else.'''
|
||||||
className = className or self.__class__.__name__
|
if not className:
|
||||||
return self.getProductConfig().attributes[className]
|
klass = self.__class__.wrapperClass
|
||||||
|
else:
|
||||||
|
klass = self.getTool().getAppyClass(className, wrapper=True)
|
||||||
|
return klass.__fields__
|
||||||
|
|
||||||
def getGroupedAppyTypes(self, layoutType, pageName):
|
def getGroupedAppyTypes(self, layoutType, pageName):
|
||||||
'''Returns the fields sorted by group. For every field, the appyType
|
'''Returns the fields sorted by group. For every field, the appyType
|
||||||
(dict version) is given.'''
|
(dict version) is given.'''
|
||||||
res = []
|
res = []
|
||||||
groups = {} # The already encountered groups
|
groups = {} # The already encountered groups
|
||||||
# In debug mode, reload the module containing self's class.
|
# If param "refresh" is there, we must reload the Python class
|
||||||
debug = self.isDebug()
|
refresh = ('refresh' in self.REQUEST)
|
||||||
if debug:
|
if refresh:
|
||||||
klass = self.getClass(reloaded=True)
|
klass = self.getClass(reloaded=True)
|
||||||
for appyType in self.getAllAppyTypes():
|
for appyType in self.getAllAppyTypes():
|
||||||
if debug:
|
if refresh: appyType = appyType.reload(klass, self)
|
||||||
appyType = appyType.reload(klass, self)
|
|
||||||
if appyType.page.name != pageName: continue
|
if appyType.page.name != pageName: continue
|
||||||
if not appyType.isShowable(self, layoutType): continue
|
if not appyType.isShowable(self, layoutType): continue
|
||||||
if not appyType.group:
|
if not appyType.group:
|
||||||
|
@ -594,16 +594,17 @@ class BaseMixin:
|
||||||
the result.'''
|
the result.'''
|
||||||
res = []
|
res = []
|
||||||
for name in fieldNames:
|
for name in fieldNames:
|
||||||
appyType = self.getAppyType(name, asDict)
|
if name == 'state':
|
||||||
if appyType: res.append(appyType)
|
|
||||||
elif name == 'state':
|
|
||||||
# We do not return a appyType if the attribute is not a *real*
|
# We do not return a appyType if the attribute is not a *real*
|
||||||
# attribute, but the workfow state.
|
# attribute, but the workfow state.
|
||||||
res.append({'name': name, 'labelId': 'workflow_state',
|
res.append({'name': name, 'labelId': 'workflow_state',
|
||||||
'filterable': False})
|
'filterable': False})
|
||||||
else:
|
else:
|
||||||
self.appy().log('Field "%s", used as shownInfo in a Ref, ' \
|
appyType = self.getAppyType(name, asDict)
|
||||||
'was not found.' % name, type='warning')
|
if appyType: res.append(appyType)
|
||||||
|
else:
|
||||||
|
self.appy().log('Field "%s", used as shownInfo in a Ref, ' \
|
||||||
|
'was not found.' % name, type='warning')
|
||||||
if addTitle and ('title' not in fieldNames):
|
if addTitle and ('title' not in fieldNames):
|
||||||
res.insert(0, self.getAppyType('title', asDict))
|
res.insert(0, self.getAppyType('title', asDict))
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -183,10 +183,8 @@ class Tool(ModelClass):
|
||||||
listBoxesMaximumWidth = Integer(default=100)
|
listBoxesMaximumWidth = Integer(default=100)
|
||||||
def refreshSecurity(self): pass # Real method in the wrapper
|
def refreshSecurity(self): pass # Real method in the wrapper
|
||||||
refreshSecurity = Action(action=refreshSecurity, confirm=True)
|
refreshSecurity = Action(action=refreshSecurity, confirm=True)
|
||||||
# First arg of Ref field below is None because we don't know yet if it will
|
# Ref(User) will maybe be transformed into Ref(CustomUserClass).
|
||||||
# link to the predefined User class or a custom class defined in the
|
users = Ref(User, multiplicity=(0,None), add=True, link=False,
|
||||||
# application.
|
|
||||||
users = Ref(None, multiplicity=(0,None), add=True, link=False,
|
|
||||||
back=Ref(attribute='toTool'), page='users', queryable=True,
|
back=Ref(attribute='toTool'), page='users', queryable=True,
|
||||||
queryFields=('login',), showHeaders=True,
|
queryFields=('login',), showHeaders=True,
|
||||||
shownInfo=('login', 'title', 'roles'))
|
shownInfo=('login', 'title', 'roles'))
|
||||||
|
|
|
@ -670,7 +670,7 @@
|
||||||
isEdit python: layoutType == 'edit';
|
isEdit python: layoutType == 'edit';
|
||||||
pageInfo python: phaseInfo['pagesInfo'][page]">
|
pageInfo python: phaseInfo['pagesInfo'][page]">
|
||||||
<br/>
|
<br/>
|
||||||
<tal:previousButton condition="python: previousPage and pageInfo['showPrevious']">
|
<tal:previous condition="python: previousPage and pageInfo['showPrevious']">
|
||||||
<tal:button condition="isEdit">
|
<tal:button condition="isEdit">
|
||||||
<input type="image" class="imageInput" style="cursor:pointer" name="buttonPrevious"
|
<input type="image" class="imageInput" style="cursor:pointer" name="buttonPrevious"
|
||||||
title="label_previous" i18n:attributes="title" i18n:domain="plone"
|
title="label_previous" i18n:attributes="title" i18n:domain="plone"
|
||||||
|
@ -683,28 +683,34 @@
|
||||||
title="label_previous" i18n:attributes="title" i18n:domain="plone"/>
|
title="label_previous" i18n:attributes="title" i18n:domain="plone"/>
|
||||||
</a>
|
</a>
|
||||||
</tal:link>
|
</tal:link>
|
||||||
</tal:previousButton>
|
</tal:previous>
|
||||||
|
|
||||||
<tal:saveButton condition="python: isEdit and pageInfo['showSave']">
|
<tal:save condition="python: isEdit and pageInfo['showSave']">
|
||||||
<input type="image" class="imageInput" style="cursor:pointer" name="buttonOk"
|
<input type="image" class="imageInput" style="cursor:pointer" name="buttonOk"
|
||||||
title="label_save" i18n:attributes="title" i18n:domain="plone"
|
title="label_save" i18n:attributes="title" i18n:domain="plone"
|
||||||
tal:attributes="src string:$portal_url/skyn/save.png"/>
|
tal:attributes="src string:$portal_url/skyn/save.png"/>
|
||||||
</tal:saveButton>
|
</tal:save>
|
||||||
|
|
||||||
<tal:cancelButton condition="python: isEdit and pageInfo['showCancel']">
|
<tal:cancel condition="python: isEdit and pageInfo['showCancel']">
|
||||||
<input type="image" class="imageInput" style="cursor:pointer" name="buttonCancel"
|
<input type="image" class="imageInput" style="cursor:pointer" name="buttonCancel"
|
||||||
title="label_cancel" i18n:attributes="title" i18n:domain="plone"
|
title="label_cancel" i18n:attributes="title" i18n:domain="plone"
|
||||||
tal:attributes="src string:$portal_url/skyn/cancel.png"/>
|
tal:attributes="src string:$portal_url/skyn/cancel.png"/>
|
||||||
</tal:cancelButton>
|
</tal:cancel>
|
||||||
|
|
||||||
<tal:editLink condition="python: not isEdit and pageInfo['showOnEdit']">
|
<tal:edit condition="python: not isEdit and pageInfo['showOnEdit']">
|
||||||
<img title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
|
<img title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
|
||||||
tal:attributes="onClick python: 'href: window.location=\'%s\'' % contextObj.getUrl(mode='edit', page=page);
|
tal:attributes="onClick python: 'href: window.location=\'%s\'' % contextObj.getUrl(mode='edit', page=page);
|
||||||
src string: $portal_url/skyn/editBig.png"
|
src string: $portal_url/skyn/editBig.png"
|
||||||
tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
|
tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
|
||||||
</tal:editLink>
|
</tal:edit>
|
||||||
|
|
||||||
<tal:nextButton condition="python: nextPage and pageInfo['showNext']">
|
<tal:refresh condition="contextObj/isDebug">
|
||||||
|
<img title="Refresh" style="cursor:pointer"
|
||||||
|
tal:attributes="onClick python: 'href: window.location=\'%s\'' % contextObj.getUrl(mode=layoutType, page=page, refresh='yes');
|
||||||
|
src string: $portal_url/skyn/refresh.png"/>
|
||||||
|
</tal:refresh>
|
||||||
|
|
||||||
|
<tal:next condition="python: nextPage and pageInfo['showNext']">
|
||||||
<tal:button condition="isEdit">
|
<tal:button condition="isEdit">
|
||||||
<input type="image" class="imageInput" style="cursor:pointer" name="buttonNext"
|
<input type="image" class="imageInput" style="cursor:pointer" name="buttonNext"
|
||||||
title="label_next" i18n:attributes="title" i18n:domain="plone"
|
title="label_next" i18n:attributes="title" i18n:domain="plone"
|
||||||
|
@ -717,7 +723,7 @@
|
||||||
title="label_next" i18n:attributes="title" i18n:domain="plone"/>
|
title="label_next" i18n:attributes="title" i18n:domain="plone"/>
|
||||||
</a>
|
</a>
|
||||||
</tal:link>
|
</tal:link>
|
||||||
</tal:nextButton>
|
</tal:next>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tal:comment replace="nothing">
|
<tal:comment replace="nothing">
|
||||||
|
|
BIN
gen/plone25/skin/refresh.png
Normal file
BIN
gen/plone25/skin/refresh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -59,9 +59,6 @@ catalogMap = {}
|
||||||
# In the following dict, we store, for every Appy class, the ordered list of
|
# In the following dict, we store, for every Appy class, the ordered list of
|
||||||
# appy types (included inherited ones).
|
# appy types (included inherited ones).
|
||||||
attributes = {<!attributes!>}
|
attributes = {<!attributes!>}
|
||||||
# In the following dict, we store, for every Appy class, a dict of appy types
|
|
||||||
# keyed by their names.
|
|
||||||
attributesDict = {<!attributesDict!>}
|
|
||||||
|
|
||||||
# Application roles
|
# Application roles
|
||||||
applicationRoles = [<!roles!>]
|
applicationRoles = [<!roles!>]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
import os, os.path, time, mimetypes, random
|
import os, os.path, time, mimetypes, random
|
||||||
import appy.pod
|
import appy.pod
|
||||||
from appy.gen import Type, Search, Ref
|
from appy.gen import Type, Search, Ref, String
|
||||||
from appy.gen.utils import sequenceTypes
|
from appy.gen.utils import sequenceTypes
|
||||||
from appy.shared.utils import getOsTempFolder, executeCommand, normalizeString
|
from appy.shared.utils import getOsTempFolder, executeCommand, normalizeString
|
||||||
from appy.shared.xml_parser import XmlMarshaller
|
from appy.shared.xml_parser import XmlMarshaller
|
||||||
|
@ -41,7 +41,6 @@ class AbstractWrapper(object):
|
||||||
elif name == 'typeName': return self.__class__.__bases__[-1].__name__
|
elif name == 'typeName': return self.__class__.__bases__[-1].__name__
|
||||||
elif name == 'id': return self.o.id
|
elif name == 'id': return self.o.id
|
||||||
elif name == 'uid': return self.o.UID()
|
elif name == 'uid': return self.o.UID()
|
||||||
elif name == 'title': return self.o.Title()
|
|
||||||
elif name == 'klass': return self.__class__.__bases__[-1]
|
elif name == 'klass': return self.__class__.__bases__[-1]
|
||||||
elif name == 'url': return self.o.absolute_url()
|
elif name == 'url': return self.o.absolute_url()
|
||||||
elif name == 'state': return self.o.getState()
|
elif name == 'state': return self.o.getState()
|
||||||
|
@ -57,12 +56,7 @@ class AbstractWrapper(object):
|
||||||
return self.o.portal_membership.getAuthenticatedMember()
|
return self.o.portal_membership.getAuthenticatedMember()
|
||||||
elif name == 'fields': return self.o.getAllAppyTypes()
|
elif name == 'fields': return self.o.getAllAppyTypes()
|
||||||
# Now, let's try to return a real attribute.
|
# Now, let's try to return a real attribute.
|
||||||
try:
|
res = object.__getattribute__(self, name)
|
||||||
res = object.__getattribute__(self, name)
|
|
||||||
except AttributeError, ae:
|
|
||||||
# Maybe a back reference?
|
|
||||||
res = self.o.getAppyType(name)
|
|
||||||
if not res: raise ae
|
|
||||||
# If we got an Appy type, return the value of this type for this object
|
# If we got an Appy type, return the value of this type for this object
|
||||||
if isinstance(res, Type):
|
if isinstance(res, Type):
|
||||||
o = self.o
|
o = self.o
|
||||||
|
|
Loading…
Reference in a new issue