diff --git a/gen/__init__.py b/gen/__init__.py index 2a967a0..e46057c 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -1762,7 +1762,7 @@ class Ref(Type): maxChars=None, colspan=1, master=None, masterValue=None, focus=False, historized=False, mapping=None, label=None, queryable=False, queryFields=None, queryNbCols=1, - navigable=False): + navigable=False, searchSelect=None): self.klass = klass self.attribute = attribute # May the user add new objects through this ref ? @@ -1830,6 +1830,11 @@ class Ref(Type): self.queryNbCols = queryNbCols # Within the portlet, will referred elements appear ? self.navigable = navigable + # The search select method is used if self.indexed is True. In this + # case, we need to know among which values we can search on this field, + # in the search screen. Those values are returned by self.searchSelect, + # which must be a static method accepting the tool as single arg. + self.searchSelect = searchSelect Type.__init__(self, validator, multiplicity, index, default, optional, editDefault, show, page, group, layouts, move, indexed, False, specificReadPermission, specificWritePermission, @@ -1911,6 +1916,23 @@ class Ref(Type): def getFormattedValue(self, obj, value): return value + def getIndexType(self): return 'ZCTextIndex' + + def getIndexValue(self, obj, forSearch=False): + '''Value for indexing is the list of UIDs of linked objects. If + p_forSearch is True, it will return a "string" version made of the + titles of linked objects.''' + if not forSearch: + res = getattr(obj.aq_base, self.name, '') + if res: res = ' '.join(res) + return res + else: + # For the global search: concatenate titles of linked objects + titles = [] + for obj in self.getValue(type='objects'): + titles.append(obj.title) + return ' '.join(titles) + def validateValue(self, obj, value): if not self.link: return None # We only check "link" Refs because in edit views, "add" Refs are diff --git a/gen/installer.py b/gen/installer.py index b02f9d2..4527e8c 100644 --- a/gen/installer.py +++ b/gen/installer.py @@ -250,7 +250,6 @@ class ZopeInstaller: # Create the admin user if it does not exist. if not appyTool.count('User', noSecurity=True, login='admin'): - print 'No admin!' appyTool.create('users', noSecurity=True, login='admin', password1='admin', password2='admin', email='admin@appyframework.org', roles=['Manager']) diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index 0990308..5bcb506 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -1138,4 +1138,13 @@ class ToolMixin(BaseMixin): sendMail(appyTool, email, subject, body) os.remove(tokenFile) return self.goto(siteUrl, self.translate('new_password_sent')) + + def getSearchValues(self, name, className): + '''Gets the possible values for selecting a value for searching field + p_name belonging to class p_className.''' + klass = self.getAppyClass(className, wrapper=True) + method = getattr(klass, name).searchSelect + tool = self.appy() + objects = method.__get__(tool)(tool) + return [(o.uid, o) for o in objects] # ------------------------------------------------------------------------------ diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index b556ee7..d688a50 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -518,17 +518,14 @@ class BaseMixin: return appyType.select(self.appy()) xhtmlToText = re.compile('<.*?>', re.S) - def getReferenceLabel(self, name, refObject): + def getReferenceLabel(self, name, refObject, className=None): '''p_name is the name of a Ref field with link=True. I need to display, on an edit view, the p_refObject in the listbox that will allow the user to choose which object(s) to link through the Ref. The information to display may only be the object title or more if field.shownInfo is used.''' - appyType = self.getAppyType(name) - res = refObject.title - if 'title' in appyType.shownInfo: - # We may place it at another place - res = '' + appyType = self.getAppyType(name, className=className) + res = '' for fieldName in appyType.shownInfo: refType = refObject.o.getAppyType(fieldName) value = getattr(refObject, fieldName) diff --git a/gen/ui/appy.css b/gen/ui/appy.css index 45f9b8e..e0f9669 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -65,7 +65,7 @@ img { border: 0; vertical-align: middle} width: 600px; border: 1px #F0C36D solid; padding: 6px 16px; background-color: #F9EDBE; text-align: center; border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9;} -.focus { font-size: 90%; padding: 6px 16px; background-color: #d7dee4; +.focus { font-size: 90%; margin: 7px; background-color: #d7dee4; border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9;} .focus td { padding: 4px 0px 4px 4px } .discreet { font-size: 90%; } diff --git a/gen/ui/widgets/ref.pt b/gen/ui/widgets/ref.pt index 5ee9c42..242aa8b 100644 --- a/gen/ui/widgets/ref.pt +++ b/gen/ui/widgets/ref.pt @@ -254,4 +254,26 @@ Search macro for a Ref. - + +
   + The "and" / "or" radio buttons + + + + +
+
+ The list of values + +
diff --git a/gen/wrappers/UserWrapper.py b/gen/wrappers/UserWrapper.py index baaa542..3c35139 100644 --- a/gen/wrappers/UserWrapper.py +++ b/gen/wrappers/UserWrapper.py @@ -169,8 +169,15 @@ class UserWrapper(AbstractWrapper): del self.o.__ac_local_roles__[None] return self._callCustom('onEdit', created) - def mayEdit(self): return self._callCustom('mayEdit') - def mayDelete(self): return self._callCustom('mayDelete') + def mayEdit(self): + custom = self._getCustomMethod('mayEdit') + if custom: return self._callCustom('mayEdit') + else: return True + + def mayDelete(self): + custom = self._getCustomMethod('mayDelete') + if custom: return self._callCustom('mayDelete') + else: return True def getZopeUser(self): '''Gets the Zope user corresponding to this user.''' diff --git a/gen/wrappers/__init__.py b/gen/wrappers/__init__.py index 5697574..3763ee8 100644 --- a/gen/wrappers/__init__.py +++ b/gen/wrappers/__init__.py @@ -132,16 +132,21 @@ class AbstractWrapper(object): if other: return cmp(self.o, other.o) return 1 + def _getCustomMethod(self, methodName): + '''See docstring of _callCustom below.''' + if len(self.__class__.__bases__) > 1: + # There is a custom user class + custom = self.__class__.__bases__[-1] + if custom.__dict__.has_key(methodName): + return custom.__dict__[methodName] + def _callCustom(self, methodName, *args, **kwargs): '''This wrapper implements some methods like "validate" and "onEdit". If the user has defined its own wrapper, its methods will not be called. So this method allows, from the methods here, to call the user versions.''' - if len(self.__class__.__bases__) > 1: - # There is a custom user class - customUser = self.__class__.__bases__[-1] - if customUser.__dict__.has_key(methodName): - return customUser.__dict__[methodName](self, *args, **kwargs) + custom = self._getCustomMethod(methodName) + if custom: return custom(self, *args, **kwargs) def getField(self, name): return self.o.getAppyType(name) def isEmpty(self, name):