diff --git a/browser/base_macros.pt b/browser/base_macros.pt index afb7edd..21b927e 100644 --- a/browser/base_macros.pt +++ b/browser/base_macros.pt @@ -11,8 +11,8 @@ - + diff --git a/composer/report/base.py b/composer/report/base.py index 86b5cf3..fddcdb0 100644 --- a/composer/report/base.py +++ b/composer/report/base.py @@ -18,8 +18,6 @@ """ Basic classes for report management. - -$Id$ """ import operator as standard_operators diff --git a/composer/report/field.py b/composer/report/field.py index 0ed9531..cdfc4a9 100644 --- a/composer/report/field.py +++ b/composer/report/field.py @@ -47,7 +47,7 @@ class Field(Component): renderer = 'standard' operator = 'in' - executionSteps = ['query', 'sort', 'output'] + executionSteps = ['query', 'sort', 'output'] # , 'totals'] operators = [{'token': 'eq', 'label': '=='}, {'token': 'lt', 'label': '<'}, @@ -70,7 +70,7 @@ class Field(Component): return self.__name__ def getRawValue(self, row): - return getattr(row.context, self.name) + return row.getRawValue(self.name) def getSelectValue(self, row): return getattr(row, self.name, None) @@ -84,6 +84,9 @@ class Field(Component): return value return getattr(value, 'title', str(value)) + def getDisplayValue(self, row): + return self.getValue(row) + def getSortValue(self, row): # TODO: consider 'descending' flag, use raw value instead of formatted one return getattr(row, self.name, None) diff --git a/composer/report/interfaces.py b/composer/report/interfaces.py index 8d020f2..5d2b42c 100644 --- a/composer/report/interfaces.py +++ b/composer/report/interfaces.py @@ -53,7 +53,20 @@ class IReportManager(Interface): """ -class IReport(ITemplate): +class IReportParams(Interface): + """ Contains the real reporting parameters like query and sort criteria, + column definitions, etc. + """ + + queryCriteria = Attribute('The criteria to be used for executing the ' + 'query step.') + sortSpec = Attribute('A sequence of fields/sort directions to be used for ' + 'executing the sorting step.') + outputSpec = Attribute('A sequence of output fields (column/cell ' + 'specifications) to be used for presenting the result data.') + + +class IReport(ITemplate, IReportParams): """ A configurable report. """ @@ -90,13 +103,6 @@ class IReport(ITemplate): renderers = Attribute('An ordered collection of renderers available ' 'for this report type.') - queryCriteria = Attribute('The criteria to be used for executing the ' - 'query step.') - sortSpec = Attribute('A sequence of fields/sort directions to be used for ' - 'executing the sorting step.') - outputSpec = Attribute('A sequence of output fields (column/cell ' - 'specifications) to be used for presenting the result data.') - def getQueryFields(): """ Return a sequence of fields that may be used for setting up the query criteria. diff --git a/composer/report/result.py b/composer/report/result.py index 99605f2..7396fbe 100644 --- a/composer/report/result.py +++ b/composer/report/result.py @@ -18,8 +18,6 @@ """ Report result sets and related classes. - -$Id$ """ from zope.cachedescriptors.property import Lazy @@ -28,26 +26,45 @@ from cybertools.composer.interfaces import IInstance from cybertools.composer.report.base import BaseQueryCriteria -class Row(object): + +class BaseRow(object): def __init__(self, context, parent): self.context = context self.parent = parent + self.data = {} def __getattr__(self, attr): f = self.parent.context.fields[attr] return f.getValue(self) + def getRawValue(self, attr): + return self.data.get(attr) + + +class Row(BaseRow): + + attributeHandlers = {} + + def getRawValue(self, attr): + return self.attributeHandlers.get(attr, Row.getContextAttr)(self, attr) + + @staticmethod + def getContextAttr(obj, attr): + return getattr(obj.context, attr) + + class ResultSet(object): def __init__(self, context, data, rowFactory=Row, sortCriteria=None, queryCriteria=BaseQueryCriteria()): - self.context = context + self.context = context # the report or report instance self.data = data self.rowFactory = rowFactory self.sortCriteria = sortCriteria self.queryCriteria = queryCriteria + self.totals = BaseRow(None, self) def getResult(self): result = [self.rowFactory(item, self) for item in self.data] diff --git a/util/date.py b/util/date.py index 5613747..e774fb8 100644 --- a/util/date.py +++ b/util/date.py @@ -18,8 +18,6 @@ """ Date and time utilities. - -$Id$ """ import time @@ -30,6 +28,11 @@ def getTimeStamp(): return int(time.time()) +def timeStamp2Date(ts, useGM=False): + if ts is None: + ts = getTimeStamp() + return datetime.fromtimestamp(ts) + def timeStamp2ISO(ts, useGM=False, format='%Y-%m-%d %H:%M'): return formatTimeStamp(ts, useGM, format) @@ -38,8 +41,6 @@ def formatTimeStamp(ts, useGM=False, format='%Y-%m-%d %H:%M'): ts = getTimeStamp() fct = useGM and time.gmtime or time.localtime return time.strftime(format, fct(ts)) - #return time.strftime('%Y-%m-%d %H:%M', time.gmtime(ts)) - #return time.strftime('%Y-%m-%d %H:%M', time.localtime(ts)) def str2timeStamp(s):