diff --git a/doc/AppyManifesto.odt b/doc/AppyManifesto.odt index ddd08e9..418f670 100644 Binary files a/doc/AppyManifesto.odt and b/doc/AppyManifesto.odt differ diff --git a/gen/__init__.py b/gen/__init__.py index 8cae21c..4c448a3 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -233,24 +233,26 @@ class Group: if self.group and (self.group not in walkedGroups) and \ not self.group.label: # We remember walked groups for avoiding infinite recursion. - self.group.generateLabels(messages, classDescr, walkedGroups) + self.group.generateLabels(messages, classDescr, walkedGroups, + forSearch=forSearch) - def insertInto(self, widgets, groupDescrs, page, metaType): + def insertInto(self, widgets, groupDescrs, page, metaType, forSearch=False): '''Inserts the GroupDescr instance corresponding to this Group instance into p_widgets, the recursive structure used for displaying all - widgets in a given p_page, and returns this GroupDescr instance.''' + widgets in a given p_page (or all searches), and returns this + GroupDescr instance.''' # First, create the corresponding GroupDescr if not already in # p_groupDescrs. if self.name not in groupDescrs: - groupDescr = groupDescrs[self.name] = GroupDescr(self, page, - metaType).get() + groupDescr = groupDescrs[self.name] = \ + GroupDescr(self, page, metaType, forSearch=forSearch).get() # Insert the group at the higher level (ie, directly in p_widgets) # if the group is not itself in a group. if not self.group: widgets.append(groupDescr) else: outerGroupDescr = self.group.insertInto(widgets, groupDescrs, - page, metaType) + page, metaType, forSearch=forSearch) GroupDescr.addWidget(outerGroupDescr, groupDescr) else: groupDescr = groupDescrs[self.name] @@ -291,7 +293,7 @@ class Import: class Search: '''Used for specifying a search for a given type.''' def __init__(self, name, group=None, sortBy='', sortOrder='asc', limit=None, - default=False, **fields): + default=False, colspan=1, **fields): self.name = name # Searches may be visually grouped in the portlet. self.group = Group.get(group) @@ -301,6 +303,7 @@ class Search: # If this search is the default one, it will be triggered by clicking # on main link. self.default = default + self.colspan = colspan # In the dict below, keys are indexed field names and values are # search values. self.fields = fields diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index 2c63060..2313e75 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -2,8 +2,8 @@ import os, os.path, sys, re, time, random, types, base64, urllib from appy import Object import appy.gen -from appy.gen import Type, Search, Selection, String -from appy.gen.utils import SomeObjects, getClassName +from appy.gen import Type, Search, Selection, String, Page +from appy.gen.utils import SomeObjects, getClassName, GroupDescr from appy.gen.mixins import BaseMixin from appy.gen.wrappers import AbstractWrapper from appy.gen.descriptors import ClassDescriptor @@ -672,7 +672,7 @@ class ToolMixin(BaseMixin): obj = self.getObject(objectUid) return obj, fieldName - def getSearches(self, contentType): + def getGroupedSearches(self, contentType): '''Returns an object with 2 attributes: * "searches" stores the searches that are defined for p_contentType; * "default" stores the search defined as the default one. @@ -680,37 +680,27 @@ class ToolMixin(BaseMixin): search or about a group of searches. ''' appyClass = self.getAppyClass(contentType) - searches = [] + res = [] default = None # Also retrieve the default one here. - visitedGroups = {} # Names of already visited search groups + groups = {} # The already encountered groups + page = Page('main') # A dummy page required by class GroupDescr for search in ClassDescriptor.getSearches(appyClass): - # Determine first group label, we will need it. - groupLabel = None - groupName = None - if search.group: - groupName = search.group.name - groupLabel = '%s_searchgroup_%s' % (contentType, groupName) - # Add an item representing the search group if relevant - if groupName and (groupName not in visitedGroups): - group = {'name': groupName, 'isGroup': True, - 'labelId': groupLabel, 'searches': [], - 'label': self.translate(groupLabel), - 'descr': self.translate('%s_descr' % groupLabel), - } - searches.append(group) - visitedGroups[groupName] = group - # Add the search itself + # Compute the dict representing this search searchLabel = '%s_search_%s' % (contentType, search.name) - dSearch = {'name': search.name, 'isGroup': False, + dSearch = {'name': search.name, 'type': 'search', + 'colspan': search.colspan, 'label': self.translate(searchLabel), 'descr': self.translate('%s_descr' % searchLabel)} - if groupName: - visitedGroups[groupName]['searches'].append(dSearch) + if not search.group: + # Insert the search at the highest level, not in any group. + res.append(dSearch) else: - searches.append(dSearch) - if search.default: - default = dSearch - return Object(searches=searches, default=default).__dict__ + groupDescr = search.group.insertInto(res, groups, page, + contentType, forSearch=True) + GroupDescr.addWidget(groupDescr, dSearch) + # Is this search the default search? + if search.default: default = dSearch + return Object(searches=res, default=default).__dict__ def getQueryUrl(self, contentType, searchName, startNumber=None): '''This method creates the URL that allows to perform a (non-Ajax) diff --git a/gen/ui/appy.css b/gen/ui/appy.css index d8be619..e7f298e 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -80,7 +80,7 @@ img { border: 0; vertical-align: middle} .portletPage { font-style: italic; } .portletGroup { font-variant: small-caps; font-weight: bold; font-style: normal; margin-top: 0.1em } -.portletSearch { font-size: 90%; font-style: italic; padding-left: 1em} +.portletSearch { font-size: 90%; font-style: italic } .phase { border-style: dashed; border-width: thin; padding: 4px 0.6em 5px 1em;} .phaseSelected { background-color: #F4F5F6; } .content { padding: 14px 14px 9px 15px; background-color: #f1f1f1 } diff --git a/gen/ui/portlet.pt b/gen/ui/portlet.pt index d81795c..b5575bc 100644 --- a/gen/ui/portlet.pt +++ b/gen/ui/portlet.pt @@ -1,9 +1,51 @@ - - This macro displays the content of the application portlet. - +Macro for displaying a search +
+ +
+ +Macro for displaying a group of searches + + Group name +
+ + +
+ Group content +
+ + + An inner group within this group + + + + + + + + + + + + +
+
+ +Macro displaying the whole portlet - + One section for every searchable root class. @@ -26,7 +68,7 @@
-
+
Section title (link triggers the default search), with action icons - Searches for this content type. - - - - Group name -
- - -
- Group searches -
-
- -
-
-
-
-
- -
-
+ Searches for this content type + + + + + + + + + +
diff --git a/gen/utils.py b/gen/utils.py index 4bd7b46..a13bae7 100644 --- a/gen/utils.py +++ b/gen/utils.py @@ -59,8 +59,8 @@ class Descr: def get(self): return self.__dict__ class GroupDescr(Descr): - def __init__(self, group, page, metaType): - '''Creates the data structure manipulated in ZPTs from p_group, the + def __init__(self, group, page, metaType, forSearch=False): + '''Creates the data structure manipulated in ZPTs for p_group, the Group instance used in the field definition.''' self.type = 'group' # All p_group attributes become self attributes. @@ -77,7 +77,9 @@ class GroupDescr(Descr): else: # It is a tuple (metaType, name) if group.label[1]: labelName = group.label[1] if group.label[0]: prefix = group.label[0] - self.labelId = '%s_group_%s' % (prefix, labelName) + if forSearch: gp = 'searchgroup' + else: gp = 'group' + self.labelId = '%s_%s_%s' % (prefix, gp, labelName) self.descrId = self.labelId + '_descr' self.helpId = self.labelId + '_help' # The name of the page where the group lies