Commit 3015f3e7 authored by Yoshinori Okuji's avatar Yoshinori Okuji

common review JPS/YO. Addition of stat_columns code. Incomplete url_columns....

common review JPS/YO. Addition of stat_columns code. Incomplete url_columns. Filtering empty string params now applies to all methods except objectValues. Renaming to selection_expression (instead of stat_query).


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1215 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 770e444b
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
# #
############################################################################## ##############################################################################
import string import string, types, sys
from Products.Formulator.DummyField import fields from Products.Formulator.DummyField import fields
from Products.Formulator import Widget, Validator from Products.Formulator import Widget, Validator
from Products.Formulator.Field import ZMIField from Products.Formulator.Field import ZMIField
...@@ -136,7 +136,7 @@ class ListBoxWidget(Widget.Widget): ...@@ -136,7 +136,7 @@ class ListBoxWidget(Widget.Widget):
""" """
property_names = Widget.Widget.property_names +\ property_names = Widget.Widget.property_names +\
['lines', 'columns', 'all_columns', 'search_columns', 'sort_columns', 'sort', ['lines', 'columns', 'all_columns', 'search_columns', 'sort_columns', 'sort',
'editable_columns', 'all_editable_columns', 'global_attributes', 'editable_columns', 'all_editable_columns', 'stat_columns', 'global_attributes',
'list_method', 'stat_method', 'selection_name', 'list_method', 'stat_method', 'selection_name',
'meta_types', 'portal_types', 'default_params', 'meta_types', 'portal_types', 'default_params',
'search', 'select', 'search', 'select',
...@@ -261,6 +261,20 @@ class ListBoxWidget(Widget.Widget): ...@@ -261,6 +261,20 @@ class ListBoxWidget(Widget.Widget):
default=[], default=[],
required=0) required=0)
stat_columns = fields.ListTextAreaField('stat_columns',
title="Stat Columns",
description=(
"An optional list of columns which can be used for statistics."),
default=[],
required=0)
url_columns = fields.ListTextAreaField('url_columns',
title="URL Columns",
description=(
"An optional list of columns which can provide a custom URL."),
default=[],
required=0)
global_attributes = fields.ListTextAreaField('global_attributes', global_attributes = fields.ListTextAreaField('global_attributes',
title="Global Attributes", title="Global Attributes",
description=( description=(
...@@ -326,6 +340,7 @@ class ListBoxWidget(Widget.Widget): ...@@ -326,6 +340,7 @@ class ListBoxWidget(Widget.Widget):
sort = field.get_value('sort') sort = field.get_value('sort')
editable_columns = field.get_value('editable_columns') editable_columns = field.get_value('editable_columns')
all_editable_columns = field.get_value('all_editable_columns') all_editable_columns = field.get_value('all_editable_columns')
stat_columns = field.get_value('stat_columns')
search_columns = field.get_value('search_columns') search_columns = field.get_value('search_columns')
sort_columns = field.get_value('sort_columns') sort_columns = field.get_value('sort_columns')
domain_tree = field.get_value('domain_tree') domain_tree = field.get_value('domain_tree')
...@@ -355,12 +370,17 @@ class ListBoxWidget(Widget.Widget): ...@@ -355,12 +370,17 @@ class ListBoxWidget(Widget.Widget):
sort_columns = search_columns sort_columns = search_columns
sort_columns_id_list = map(lambda x: x[0], sort_columns) sort_columns_id_list = map(lambda x: x[0], sort_columns)
# We only display stats if a stat button exsists # Display statistics if the button Parameter exists or stat columns are defined explicitly.
# XXXXXXXXXXXX This is not necessarily a good
# idea since we may want to hardcode stats in certain cases
filtered_actions = here.portal_actions.listFilteredActionsFor(here); filtered_actions = here.portal_actions.listFilteredActionsFor(here);
object_ui = filtered_actions.has_key('object_ui') object_ui = filtered_actions.has_key('object_ui')
show_stat = object_ui show_stat = (object_ui or stat_columns)
# If nothing is specified to stat_columns, assume that all columns are available.
# For compatibility, because there was no stat_columns before.
if not stat_columns:
stat_columns = []
for column in all_columns:
stat_columns.append((column[0], column[0]))
has_catalog_path = None has_catalog_path = None
for (k, v) in all_columns: for (k, v) in all_columns:
...@@ -487,12 +507,28 @@ class ListBoxWidget(Widget.Widget): ...@@ -487,12 +507,28 @@ class ListBoxWidget(Widget.Widget):
# Execute the query # Execute the query
kw = params kw = params
# XXX Remove selection_expression if present.
# This is necessary for now, because the actual selection expression in
# search catalog does not take the requested columns into account. If
# select_expression is passed, this can raise an exception, because stat
# method sets select_expression, and this might cause duplicated column
# names.
#
# In the future, this must be addressed in a clean way. selection_expression
# should be used for search catalog, and search catalog should not use
# catalog.* but only selection_expression. But this is a bit difficult,
# because there is no simple way to distinguish queried columns from callable
# objects in the current ListBox configuration.
if 'select_expression' in kw:
del kw['select_expression']
if hasattr(list_method, 'method_name'): if hasattr(list_method, 'method_name'):
if list_method.method_name == 'objectValues': if list_method.method_name == 'objectValues':
list_method = here.objectValues list_method = here.objectValues
kw = copy(params) kw = copy(params)
kw['spec'] = filtered_meta_types kw['spec'] = filtered_meta_types
elif list_method.method_name == 'portal_catalog': else:
# The Catalog Builds a Complex Query # The Catalog Builds a Complex Query
# So we should not pass too many variables # So we should not pass too many variables
kw = {} kw = {}
...@@ -512,28 +548,16 @@ class ListBoxWidget(Widget.Widget): ...@@ -512,28 +548,16 @@ class ListBoxWidget(Widget.Widget):
for cname in params.keys(): for cname in params.keys():
if params[cname] != '' and params[cname]!=None: if params[cname] != '' and params[cname]!=None:
kw[cname] = params[cname] kw[cname] = params[cname]
elif list_method in (None, ''): # Use current selection
# Use previously used list method
list_method = None
else:
# Include portal_type selection
if REQUEST.form.has_key('portal_type'):
kw['portal_type'] = REQUEST.form['portal_type']
elif REQUEST.has_key('portal_type'):
kw['portal_type'] = REQUEST['portal_type']
elif filtered_portal_types is not None:
kw['portal_type'] = filtered_portal_types
elif filtered_meta_types is not None:
kw['meta_type'] = filtered_meta_types
elif kw.has_key('portal_type'):
if kw['portal_type'] == '':
del kw['portal_type']
# Try to get the method through acquisition # Try to get the method through acquisition
try: try:
list_method = getattr(here, list_method.method_name) list_method = getattr(here, list_method.method_name)
except: except:
pass pass
elif list_method in (None, ''): # Use current selection
# Use previously used list method
list_method = None
# Lookup the stat_method # Lookup the stat_method
if hasattr(stat_method, 'method_name'): if hasattr(stat_method, 'method_name'):
...@@ -554,26 +578,7 @@ class ListBoxWidget(Widget.Widget): ...@@ -554,26 +578,7 @@ class ListBoxWidget(Widget.Widget):
else: else:
stat_method = here.portal_catalog.countResults stat_method = here.portal_catalog.countResults
# Build the stat query part which is common to each query of this script LOG('ListBox', 0, 'domain_tree = %s, selection.getSelectionDomainPath() = %s, selection.getSelectionDomainList() = %s' % (repr(domain_tree), repr(selection.getSelectionDomainPath()), repr(selection.getSelectionDomainList())))
if show_stat:
stats = here.portal_selections.getSelectionStats(selection_name, REQUEST=REQUEST)
stat_query = ''
index = 0
for (k,v) in columns:
try:
if stats[index] != ' ':
stat_query += stats[index] + '(' + k + ') AS ' + k + ','
else:
stat_query += '\' \' AS ' + k + ','
except:
stat_query += '\' \' AS ' + k + ','
index = index + 1
stat_query = stat_query[:len(stat_query) - 1]
kw['stat_query'] = stat_query
selection.edit( params = kw )
if domain_tree: if domain_tree:
selection_domain_path = selection.getSelectionDomainPath() selection_domain_path = selection.getSelectionDomainPath()
selection_domain_current = selection.getSelectionDomainList() selection_domain_current = selection.getSelectionDomainList()
...@@ -586,6 +591,8 @@ class ListBoxWidget(Widget.Widget): ...@@ -586,6 +591,8 @@ class ListBoxWidget(Widget.Widget):
pass pass
#LOG('ListBox', 0, 'list_method = %s, list_method.__dict__ = %s' % (repr(list_method), repr((list_method.__dict__))))
# When we build the body, we have to go through # When we build the body, we have to go through
# All report lines # All report lines
# This is made as a list of tuples # This is made as a list of tuples
...@@ -670,7 +677,7 @@ class ListBoxWidget(Widget.Widget): ...@@ -670,7 +677,7 @@ class ListBoxWidget(Widget.Widget):
report_sections = ( (None, 0, 0, object_list, len(object_list), 0), ) report_sections = ( (None, 0, 0, object_list, len(object_list), 0), )
object_uid_list = map(lambda x: getattr(x, 'uid', None), object_list) object_uid_list = map(lambda x: getattr(x, 'uid', None), object_list)
LOG('ListBox.render, object_uid_list:',0,object_uid_list) #LOG('ListBox.render, object_uid_list:',0,object_uid_list)
# Then construct the md5 corresponding this uid list # Then construct the md5 corresponding this uid list
# It is used in order to do some checks in scripts. # It is used in order to do some checks in scripts.
# For example, if we do delete objects, then we do have a list of # For example, if we do delete objects, then we do have a list of
...@@ -712,10 +719,10 @@ class ListBoxWidget(Widget.Widget): ...@@ -712,10 +719,10 @@ class ListBoxWidget(Widget.Widget):
if list_method is not None: if list_method is not None:
try: try:
method_path = getPath(here) + '/' + list_method.method_name method_path = getPath(here) + '/' + list_method.method_name
LOG('ListBox', 0, 'method_path = %s, getPath = %s, list_method.method_name = %s' % (repr(method_path), repr(getPath(here)), repr(list_method.method_name))) #LOG('ListBox', 0, 'method_path = %s, getPath = %s, list_method.method_name = %s' % (repr(method_path), repr(getPath(here)), repr(list_method.method_name)))
except: except:
method_path = getPath(here) + '/' + list_method.__name__ method_path = getPath(here) + '/' + list_method.__name__
LOG('ListBox', 0, 'method_path = %s, getPath = %s, list_method.__name__ = %s' % (repr(method_path), repr(getPath(here)), repr(list_method.__name__))) #LOG('ListBox', 0, 'method_path = %s, getPath = %s, list_method.__name__ = %s' % (repr(method_path), repr(getPath(here)), repr(list_method.__name__)))
# Sometimes the seltion name is a list ??? Why ???? # Sometimes the seltion name is a list ??? Why ????
if type(current_selection_name) in (type(()),type([])): if type(current_selection_name) in (type(()),type([])):
current_selection_name = current_selection_name[0] current_selection_name = current_selection_name[0]
...@@ -1046,9 +1053,14 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')"> ...@@ -1046,9 +1053,14 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')">
attribute_value = 'Object does not exist' attribute_value = 'Object does not exist'
if callable(attribute_value): if callable(attribute_value):
try: try:
attribute_value = attribute_value() try:
attribute_value = attribute_value(brain = o, selection = selection)
except TypeError:
attribute_value = attribute_value()
except: except:
LOG('ListBox', 0, '', error=sys.exc_info())
attribute_value = "Could not evaluate" attribute_value = "Could not evaluate"
#LOG('ListBox', 0, 'o = %s' % repr(dir(o)))
if type(attribute_value) is type(0.0): if type(attribute_value) is type(0.0):
if sql in editable_column_ids and form.has_field('%s_%s' % (field.id, alias) ): if sql in editable_column_ids and form.has_field('%s_%s' % (field.id, alias) ):
# Do not truncate if editable # Do not truncate if editable
...@@ -1106,6 +1118,31 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')"> ...@@ -1106,6 +1118,31 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')">
# Call the stat_method # Call the stat_method
if show_stat: if show_stat:
stats = here.portal_selections.getSelectionStats(selection_name, REQUEST=REQUEST)
select_expression = ''
index = 0
for (sql,title,alias) in extended_columns:
# XXX This might be slow.
for column in stat_columns:
if column[0] == sql:
break
else:
column = None
if column is not None and column[0] == column[1]:
try:
if stats[index] != ' ':
select_expression += stats[index] + '(' + sql + ') AS ' + alias + ','
else:
select_expression += '\' \' AS ' + alias + ','
except:
select_expression += '\' \' AS ' + alias + ','
index = index + 1
select_expression = select_expression[:len(select_expression) - 1]
kw['select_expression'] = select_expression
selection.edit( params = kw )
count_results = selection(selection_method = stat_method, count_results = selection(selection_method = stat_method,
context=here, REQUEST=REQUEST) context=here, REQUEST=REQUEST)
list_body = list_body + '<tr>' list_body = list_body + '<tr>'
...@@ -1115,13 +1152,34 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')"> ...@@ -1115,13 +1152,34 @@ onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')">
list_body += '<td class="Data">&nbsp;</td>' list_body += '<td class="Data">&nbsp;</td>'
for n in range((len(extended_columns))): for n in range((len(extended_columns))):
try: try:
alias = extended_columns[n][2] sql = extended_columns[n][0]
value = getattr(count_results[0],alias,'') for column in stat_columns:
if callable(value): value=value() if column[0] == sql:
if type(value) is type(1.0): break
list_body += '<td class="Data" align="right">%.2f</td>' % value else:
column = None
#LOG('ListBox', 0, 'n = %s, extended_columns = %s, stat_columns = %s, column = %s' % (repr(n), repr(extended_columns), repr(stat_columns), repr(column)))
if column is not None:
if column[0] == column[1]:
alias = extended_columns[n][2]
value = getattr(count_results[0],alias,'')
else:
value = getattr(here, column[1])
#LOG('ListBox', 0, 'column = %s, value = %s' % (repr(column), repr(value)))
if callable(value):
try:
params = dict(kw)
#params['operator'] = stats[n]
value=value(**params)
except:
LOG('ListBox', 0, 'WARNING: Could not call %s with %s: ' % (repr(value), repr(params)), error=sys.exc_info())
pass
if type(value) is type(1.0):
list_body += '<td class="Data" align="right">%.2f</td>' % value
else:
list_body += '<td class="Data">' + str(value) + '</td>'
else: else:
list_body += '<td class="Data">' + str(value) + '</td>' list_body += '<td class="Data">&nbsp;</td>'
except: except:
list_body += '<td class="Data">&nbsp;</td>' list_body += '<td class="Data">&nbsp;</td>'
list_body += '</tr>' list_body += '</tr>'
...@@ -1217,8 +1275,8 @@ class ListBoxValidator(Validator.Validator): ...@@ -1217,8 +1275,8 @@ class ListBoxValidator(Validator.Validator):
o = newTempBase(portal, uid[4:]) # Arghhh - XXX acquisition problem - use portal root o = newTempBase(portal, uid[4:]) # Arghhh - XXX acquisition problem - use portal root
o.uid = uid o.uid = uid
listbox[uid[4:]] = {} listbox[uid[4:]] = {}
# We first try to set a listbox corresponding to all things # We first try to set a listbox corresponding to all things
# we can validate, so that we can use the same list # we can validate, so that we can use the same list
# as the one used for displaying the listbox # as the one used for displaying the listbox
for sql in editable_column_ids: for sql in editable_column_ids:
alias = '_'.join(sql.split('.')) alias = '_'.join(sql.split('.'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment