diff --git a/gen/plone25/descriptors.py b/gen/plone25/descriptors.py index f10de81..a8c3f8c 100644 --- a/gen/plone25/descriptors.py +++ b/gen/plone25/descriptors.py @@ -12,7 +12,8 @@ import appy.gen import appy.gen.descriptors from appy.gen.po import PoMessage from appy.gen import Date, String, State, Transition, Type, Search -from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage +from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage, \ + sequenceTypes TABS = 4 # Number of blanks in a Python indentation. # ------------------------------------------------------------------------------ @@ -100,6 +101,9 @@ class ArchetypeFieldDescriptor: self.fieldType = 'LinesField' self.widgetType = 'MultiSelectionWidget' self.fieldParams['multiValued'] = True + if (type(self.appyType.validator) in sequenceTypes) and \ + len(self.appyType.validator) <= 5: + self.widgetParams['format'] = 'checkbox' else: self.fieldType = 'StringField' self.widgetType = 'SelectionWidget' diff --git a/gen/plone25/mixins/ToolMixin.py b/gen/plone25/mixins/ToolMixin.py index 5a637ac..6d96e6f 100644 --- a/gen/plone25/mixins/ToolMixin.py +++ b/gen/plone25/mixins/ToolMixin.py @@ -106,7 +106,8 @@ class ToolMixin(AbstractMixin): _sortFields = {'title': 'sortable_title'} def executeQuery(self, contentType, flavourNumber=1, searchName=None, - startNumber=0, search=None, remember=False): + startNumber=0, search=None, remember=False, + brainsOnly=False, maxResults=None): '''Executes a query on a given p_contentType (or several, separated with commas) in Plone's portal_catalog. Portal types are from the flavour numbered p_flavourNumber. If p_searchName is specified, it @@ -115,7 +116,16 @@ class ToolMixin(AbstractMixin): p_startNumber. If p_search is defined, it corresponds to a custom Search instance (instead of a predefined named search like in p_searchName). If both p_searchName and p_search are given, p_search - is ignored.''' + is ignored. This method returns a list of objects in the form of the + __dict__ attribute of an instance of SomeObjects (see in + appy.gen.utils). We return the __dict__ attribute instead of real + instance: that way, it can be used in ZPTs without security problems. + If p_brainsOnly is True, it returns a list of brains instead (can be + useful for some usages like knowing the number of objects without + needing to get information about them). If no p_maxResults is + specified, the method returns maximum + self.getNumberOfResultsPerPage(). p_maxResults is ignored if + p_brainsOnly is True.''' # Is there one or several content types ? if contentType.find(',') != -1: # Several content types are specified @@ -125,7 +135,8 @@ class ToolMixin(AbstractMixin): for pt in portalTypes] else: portalTypes = contentType - params = {'portal_type': portalTypes, 'batch': True} + params = {'portal_type': portalTypes} + if not brainsOnly: params['batch'] = True # Manage additional criteria from a search when relevant if searchName or search: # In this case, contentType must contain a single content type. @@ -151,7 +162,9 @@ class ToolMixin(AbstractMixin): if self._sortFields.has_key(sb): sb = self._sortFields[sb] params['sort_on'] = sb brains = self.portal_catalog.searchResults(**params) - res = SomeObjects(brains, self.getNumberOfResultsPerPage(), startNumber) + if brainsOnly: return brains + if not maxResults: maxResults = self.getNumberOfResultsPerPage() + res = SomeObjects(brains, maxResults, startNumber) res.brainsToObjects() # In some cases (p_remember=True), we need to keep some information # about the query results in the current user's session, allowing him diff --git a/gen/plone25/mixins/__init__.py b/gen/plone25/mixins/__init__.py index 8866a6b..bff5621 100644 --- a/gen/plone25/mixins/__init__.py +++ b/gen/plone25/mixins/__init__.py @@ -54,9 +54,8 @@ class AbstractMixin: pass # Manage "add" permissions obj._appy_managePermissions() - # Re/unindex object - if obj._appy_meta_type == 'tool': self.unindexObject() - else: obj.reindexObject() + # Reindex object + obj.reindexObject() return obj def delete(self): diff --git a/gen/plone25/skin/arrowDown.png b/gen/plone25/skin/arrowDown.png index 6ea82c1..dbfc3c5 100644 Binary files a/gen/plone25/skin/arrowDown.png and b/gen/plone25/skin/arrowDown.png differ diff --git a/gen/plone25/skin/arrowUp.png b/gen/plone25/skin/arrowUp.png index 5e8f241..5277081 100644 Binary files a/gen/plone25/skin/arrowUp.png and b/gen/plone25/skin/arrowUp.png differ diff --git a/gen/plone25/skin/delete.png b/gen/plone25/skin/delete.png new file mode 100644 index 0000000..67a9af0 Binary files /dev/null and b/gen/plone25/skin/delete.png differ diff --git a/gen/plone25/skin/macros.pt b/gen/plone25/skin/macros.pt index 515dca5..40ad487 100644 --- a/gen/plone25/skin/macros.pt +++ b/gen/plone25/skin/macros.pt @@ -118,8 +118,8 @@ - - + @@ -132,7 +132,7 @@ - + - + @@ -617,7 +617,7 @@ tal:condition="python: searchName and descr">

- + Appy (top) navigation @@ -723,8 +723,9 @@ Delete the element + title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer" + tal:attributes="src string: $portal_url/skyn/delete.png; + onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/> diff --git a/gen/plone25/skin/ref.pt b/gen/plone25/skin/ref.pt index e725b5c..1ed1c97 100644 --- a/gen/plone25/skin/ref.pt +++ b/gen/plone25/skin/ref.pt @@ -18,17 +18,6 @@ referenced object (edit, delete, etc). - Edit the element - - Delete the element - Arrows for moving objects up or down + Edit the element + + Delete the element +
- - - - + + + +
diff --git a/gen/plone25/wrappers/__init__.py b/gen/plone25/wrappers/__init__.py index 8abf341..d024608 100644 --- a/gen/plone25/wrappers/__init__.py +++ b/gen/plone25/wrappers/__init__.py @@ -97,6 +97,10 @@ class AbstractWrapper: klass = property(get_klass) def get_url(self): return self.o.absolute_url()+'/skyn/view' url = property(get_url) + def get_history(self): + key = self.o.workflow_history.keys()[0] + return self.o.workflow_history[key] + history = property(get_history) def link(self, fieldName, obj): '''This method links p_obj to this one through reference field @@ -245,19 +249,33 @@ class AbstractWrapper: replaced with normal chars.''' return unicodedata.normalize('NFKD', s).encode("ascii","ignore") - def search(self, klass, sortBy='', **fields): + def search(self, klass, sortBy='', maxResults=None, **fields): '''Searches objects of p_klass. p_sortBy must be the name of an indexed field (declared with indexed=True); every param in p_fields must take the name of an indexed field and take a possible value of this - field.''' + field. You can optionally specify a maximum number of results in + p_maxResults.''' # Find the content type corresponding to p_klass flavour = self.flavour contentType = flavour.o.getPortalType(klass) # Create the Search object search = Search('customSearch', sortBy=sortBy, **fields) - res = self.tool.o.executeQuery(contentType,flavour.number,search=search) + res = self.tool.o.executeQuery(contentType,flavour.number,search=search, + maxResults=maxResults) return [o.appy() for o in res['objects']] + def count(self, klass, **fields): + '''Identical to m_search above, but returns the number of objects that + match the search instead of returning the objects themselves. Use + this method instead of writing len(self.search(...)).''' + flavour = self.flavour + contentType = flavour.o.getPortalType(klass) + search = Search('customSearch', **fields) + res = self.tool.o.executeQuery(contentType,flavour.number,search=search, + brainsOnly=True) + if res: return res._len # It is a LazyMap instance + else: return 0 + def reindex(self): '''Asks a direct object reindexing. In most cases you don't have to reindex objects "manually" with this method. When an object is