From de97208137e75cde3c077c2aa70c2b5e1be02f27 Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Thu, 27 Oct 2016 16:07:07 +0200 Subject: [PATCH] listbox: sorting by CAST type (float) Only 'float' supported for the moment. This should cover the case of integers. Example of 'Sortable Columns' value in a ListBox: id | float title | Since there's a fallback to 'Searchable Columns' when 'Sortable Columns' is empty, the cast type can also be specified there, in order to avoid duplication. --- .../Folder_viewSortOnDialog/sort_type.xml | 16 +---- product/ERP5Form/ListBox.py | 59 ++++++++++------- product/ERP5Form/Tool/SelectionTool.py | 65 +++++++++---------- 3 files changed, 72 insertions(+), 68 deletions(-) diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Folder_viewSortOnDialog/sort_type.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Folder_viewSortOnDialog/sort_type.xml index 14495d6602..111e71432c 100644 --- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Folder_viewSortOnDialog/sort_type.xml +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Folder_viewSortOnDialog/sort_type.xml @@ -237,13 +237,9 @@ <string>Default</string> <string>default</string> </tuple> - <tuple> - <string>Alphabetical</string> - <string>CHAR</string> - </tuple> <tuple> <string>Numerical</string> - <string>SIGNED</string> + <string>float</string> </tuple> </list> </value> @@ -276,19 +272,13 @@ </record> <record id="2" aka="AAAAAAAAAAI="> <pickle> - <tuple> - <tuple> - <string>Products.Formulator.TALESField</string> - <string>TALESMethod</string> - </tuple> - <none/> - </tuple> + <global name="TALESMethod" module="Products.Formulator.TALESField"/> </pickle> <pickle> <dictionary> <item> <key> <string>_text</string> </key> - <value> <string>python: [(here.Base_translateString(\'Default Sort\'), \'\'),(here.Base_translateString(\'Alphabetical\'), \'CHAR\'), (here.Base_translateString(\'Numerical\'), \'SIGNED\')]</string> </value> + <value> <string>python: [(here.Base_translateString(k), v) for k,v in field.get_orig_value("sort_columns")]</string> </value> </item> </dictionary> </pickle> diff --git a/product/ERP5Form/ListBox.py b/product/ERP5Form/ListBox.py index 04643ee625..0c8526c759 100644 --- a/product/ERP5Form/ListBox.py +++ b/product/ERP5Form/ListBox.py @@ -956,23 +956,37 @@ class ListBoxRenderer: getPageNavigationMode = getPageNavigationTemplate @lazyMethod - def getSearchColumnIdSet(self): - """Return the set of the ids of the search columns. Fall back to the catalog schema, if not defined. + def getSearchColumnDict(self): + """Return search columns + + The dict values are useful when getSortColumnDict falls back on this value. + Fall back to the catalog schema, if not defined. """ search_columns = self.field.get_value('search_columns') if search_columns: - return {c[0] for c in search_columns} + return dict(search_columns) isValidColumn = self.getCatalogTool().getSQLCatalog().isValidColumn - return {id for id, title in self.getAllColumnList() if isValidColumn(id)} + return {id: '' for id, _ in self.getAllColumnList() if isValidColumn(id)} @lazyMethod - def getSortColumnIdSet(self): - """Return the set of the ids of the sort columns. Fall back to search column ids, if not defined. + def getSortColumnDict(self): + """Return sort columns with their cast types as dict values + + Cast types are prefixed by ':' for convenience. + Fall back to search columns, if not defined. """ - sort_columns = self.field.get_value('sort_columns') - if sort_columns: - return {c[0] for c in sort_columns} - return self.getSearchColumnIdSet() + sort_dict = {} + for c, cast in (self.field.get_value('sort_columns') or + self.getSearchColumnDict().iteritems()): + if cast == 'float': + sort_dict[c] = ':' + cast + else: + if cast: + warn('Each line of the "Sortable Columns" field property must be' + ' in the form "<column_id> | <cast_type>", where <cast_type>' + " is one of ('', 'float').", DeprecationWarning) + sort_dict[c] = '' + return sort_dict @lazyMethod def getEditableColumnIdSet(self): @@ -1034,8 +1048,8 @@ class ListBoxRenderer: selection.edit(default_sort_on = self.getDefaultSortColumnList()) # Filter out non-sortable items. - sort_column_id_set = self.getSortColumnIdSet() - sort_list = [c for c in selection.sort_on if c[0] in sort_column_id_set] + sort_column_dict = self.getSortColumnDict() + sort_list = [c for c in selection.sort_on if c[0] in sort_column_dict] if len(selection.sort_on) != len(sort_list): selection.sort_on = sort_list @@ -1557,17 +1571,18 @@ class ListBoxRenderer: set to None, otherwise to a string. """ sort_list = self.getSelectionTool().getSelectionSortOrder(self.getSelectionName()) - sort_dict = {} - for sort_item in sort_list: - sort_dict[sort_item[0]] = sort_item[1] # sort_item can be couple or a triplet - sort_column_id_set = self.getSortColumnIdSet() + # sort_item can be couple or a triplet + sort_dict = {sort_item[0]: sort_item[1] for sort_item in sort_list} + sort_column_dict = self.getSortColumnDict() value_list = [] for c in self.getSelectedColumnList(): - if c[0] in sort_column_id_set: - value_list.append((c[0], c[1], sort_dict.get(c[0]))) - else: + column_id = c[0] + as_type = sort_column_dict.get(column_id) + if as_type is None: value_list.append((None, c[1], None)) + else: + value_list.append((column_id + as_type, c[1], sort_dict.get(column_id))) return value_list @@ -1576,7 +1591,7 @@ class ListBoxRenderer: If a column is not searchable, the alias is set to None, otherwise to a string. If a search field is not present, it is set to None. """ - search_column_id_set = self.getSearchColumnIdSet() + search_column_id_set = self.getSearchColumnDict() if param_dict is None: param_dict = self.getParamDict() @@ -2575,8 +2590,8 @@ class ListBoxHTMLRenderer(ListBoxRenderer): for original_listbox_argument in listbox_arguments_list: listbox_argument = original_listbox_argument.replace('%s_' %field_id, '', 1) listbox_argument_value = form_dict.get(original_listbox_argument, None) - if listbox_argument in list(self.getSearchColumnIdSet()) and \ - listbox_argument_value not in (None,): + if listbox_argument in self.getSearchColumnDict() and \ + listbox_argument_value is not None: update_selection = True listbox_kw[listbox_argument] = listbox_argument_value if update_selection: diff --git a/product/ERP5Form/Tool/SelectionTool.py b/product/ERP5Form/Tool/SelectionTool.py index 353d596c7e..e76542c3a7 100644 --- a/product/ERP5Form/Tool/SelectionTool.py +++ b/product/ERP5Form/Tool/SelectionTool.py @@ -553,17 +553,26 @@ class SelectionTool( BaseTool, SimpleItem ): listbox_id, sort_on = form["setSelectionQuickSortOrder"].split(".", 1) # Sort order can be specified in sort_on. - forced_sort_order = None - if sort_on is not None: - if sort_on.endswith(':asc'): - forced_sort_order = 'ascending' - sort_on = sort_on[:-4] - elif sort_on.endswith(':desc'): - forced_sort_order = 'descending' - sort_on = sort_on[:-5] - elif sort_on.endswith(':none'): - forced_sort_order = 'none' - sort_on = sort_on[:-5] + if sort_on.endswith(':asc'): + order = 'ascending' + sort_on = sort_on[:-4] + elif sort_on.endswith(':desc'): + order = 'descending' + sort_on = sort_on[:-5] + elif sort_on.endswith(':none'): + order = 'none' + sort_on = sort_on[:-5] + else: + order = None + # ... as well as cast type + i = sort_on.find(':') + if i < 0: + as_type = None + else: + as_type = sort_on[i+1:] + if as_type != 'float': + return + sort_on = sort_on[:i] if REQUEST is not None: if listbox_id is not None: @@ -574,33 +583,23 @@ class SelectionTool( BaseTool, SimpleItem ): selection = self.getSelectionFor(selection_name, REQUEST=REQUEST) if selection is not None: - if forced_sort_order is not None: - if forced_sort_order == 'none': - temporary_new_sort_on = [] - else: - temporary_new_sort_on = [(sort_on, forced_sort_order)] + if order is not None: # Allow user to sort by multiple columns - new_sort_on = [s - for s in self.getSelectionSortOrder(selection_name) - if s[0]!=sort_on] - new_sort_on.extend(temporary_new_sort_on) + new_sort_on = [s for s in selection.sort_on if s[0] != sort_on] + if order != 'none': + new_sort_on.append((sort_on, order, as_type) if as_type else + (sort_on, order)) else: - current_sort_on = self.getSelectionSortOrder(selection_name) # We must first switch from asc to desc and vice-versa if sort_order exists # in selection - n = 0 - for current in current_sort_on: + order = 'ascending' + for current in selection.sort_on: if current[0] == sort_on: - n = 1 - if current[1] == 'ascending': - new_sort_on = [(sort_on, 'descending')] - break - else: - new_sort_on = [(sort_on,'ascending')] - break - # And if no one exists, we just set sort - if n == 0: - new_sort_on = [(sort_on, 'ascending')] + if current[1] == order: + order = 'descending' + break + new_sort_on = ((sort_on, order, as_type) if as_type else + (sort_on, order),) selection.edit(sort_on=new_sort_on) if REQUEST is not None: -- 2.30.9