228 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #
 | |
| #  Copyright (c) 2011 Helmut Merz helmutm@cy55.de
 | |
| #
 | |
| #  This program is free software; you can redistribute it and/or modify
 | |
| #  it under the terms of the GNU General Public License as published by
 | |
| #  the Free Software Foundation; either version 2 of the License, or
 | |
| #  (at your option) any later version.
 | |
| #
 | |
| #  This program is distributed in the hope that it will be useful,
 | |
| #  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| #  GNU General Public License for more details.
 | |
| #
 | |
| #  You should have received a copy of the GNU General Public License
 | |
| #  along with this program; if not, write to the Free Software
 | |
| #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| #
 | |
| 
 | |
| """
 | |
| Basic classes for report management.
 | |
| """
 | |
| 
 | |
| import operator as standard_operators
 | |
| from zope.interface import implements
 | |
| 
 | |
| from cybertools.composer.base import Component, Element, Compound
 | |
| from cybertools.composer.base import Template
 | |
| from cybertools.composer.report import field
 | |
| from cybertools.composer.report.interfaces import IReportManager, IReport
 | |
| from cybertools.composer.report.interfaces import IQueryCriteria, ILeafQueryCriteria
 | |
| from cybertools.composer.report.interfaces import ICompoundQueryCriteria
 | |
| from cybertools.util.jeep import Jeep
 | |
| from cybertools.util.randomname import generateName
 | |
| 
 | |
| 
 | |
| class ReportManager(object):
 | |
| 
 | |
|     implements(IReportManager)
 | |
| 
 | |
|     reports = manager = None
 | |
|     reportsFactory = dict
 | |
| 
 | |
|     def getManager(self):
 | |
|         return self.manager
 | |
| 
 | |
|     def addReport(self, report):
 | |
|         if self.reports is None:
 | |
|             self.reports = self.reportsFactory()
 | |
|         id = report.identifier
 | |
|         if not id:
 | |
|             id = generateName(self.checkId)
 | |
|             report.identifier = id
 | |
|         self.reports[id] = report
 | |
|         report.manager = self
 | |
|         return report
 | |
| 
 | |
|     def checkId(self, id):
 | |
|         return id not in self.reports.keys()
 | |
| 
 | |
|     def getReport(self, id):
 | |
|         if self.reports is None:
 | |
|             return None
 | |
|         return self.reports.get(id)
 | |
| 
 | |
| 
 | |
| class Report(Template):
 | |
| 
 | |
|     implements(IReport)
 | |
| 
 | |
|     name = identifier = u''
 | |
|     #title = description = u''
 | |
|     type = 'generic'
 | |
|     manager = None
 | |
| 
 | |
|     fields = Jeep((field.label,))
 | |
|     hiddenQueryFields = ()
 | |
|     defaultOutputFields = (field.label,)
 | |
|     defaultSortCriteria = (field.label,)
 | |
|     presentationFormat = None
 | |
| 
 | |
|     renderers = ()
 | |
|     queryCriteria = None
 | |
|     outputFields = ()
 | |
|     sortCriteria = ()
 | |
|     limits = None
 | |
| 
 | |
| 
 | |
|     def __init__(self, name):
 | |
|         self.name = name
 | |
| 
 | |
|     @property
 | |
|     def components(self):
 | |
|         return self.fields
 | |
| 
 | |
|     def getAllQueryFields(self):
 | |
|         return [f for f in self.fields if 'query' in f.executionSteps]
 | |
| 
 | |
|     def getQueryFields(self, include=None, exclude=None):
 | |
|         result = [f for f in self.fields if 'query' in f.executionSteps]
 | |
|         if include:
 | |
|             result = [f for f in result if f.fieldType in include]
 | |
|         if exclude:
 | |
|             result = [f for f in result if f.fieldType not in exclude]
 | |
|         return [f for f in result if f not in self.hiddenQueryFields]
 | |
| 
 | |
|     def getOutputFields(self):
 | |
|         return [f for f in self.fields if 'output' in f.executionSteps]
 | |
| 
 | |
|     def getActiveOutputFields(self):
 | |
|         if not self.outputFields:
 | |
|             fieldNames = [f.name for f in self.getOutputFields()]
 | |
|             return [f for f in self.defaultOutputFields
 | |
|                       if f.name in fieldNames]
 | |
|         return self.outputFields
 | |
| 
 | |
|     def getAvailableOutputFields(self):
 | |
|         activeNames = [f.name for f in self.getActiveOutputFields()]
 | |
|         return [f for f in self.getOutputFields()
 | |
|                   if f.name not in activeNames]
 | |
| 
 | |
|     def getSortFields(self):
 | |
|         return [f for f in self.fields if 'sort' in f.executionSteps]
 | |
| 
 | |
|     def getSortCriteria(self):
 | |
|         if not self.sortCriteria:
 | |
|             fieldNames = [f.name for f in self.getSortFields()]
 | |
|             return [f for f in self.defaultSortCriteria
 | |
|                       if f.name in fieldNames]
 | |
|         return self.sortCriteria
 | |
| 
 | |
|     def getAvailableSortFields(self):
 | |
|         sortCriteria = [f.name for f in self.getSortCriteria()]
 | |
|         return [f for f in self.getSortFields() if f.name not in sortCriteria]
 | |
| 
 | |
|     def getPresentationFormats(self):
 | |
|         return [dict(renderer='default', title='Default')]
 | |
|     
 | |
|     def getGroupFields(self):
 | |
|         return [f for f in self.fields if 'group' in f.executionSteps]
 | |
|     
 | |
|     def getTotalsFields(self):
 | |
|         return [f for f in self.fields if 'totals' in f.executionSteps]
 | |
| 
 | |
| 
 | |
| class BaseQueryCriteria(Component):
 | |
| 
 | |
|     implements(IQueryCriteria)
 | |
| 
 | |
|     def check(self, obj):
 | |
|         return True
 | |
| 
 | |
| 
 | |
| class LeafQueryCriteria(BaseQueryCriteria, Element):
 | |
| 
 | |
|     implements(ILeafQueryCriteria)
 | |
| 
 | |
|     def __init__(self, name, operator, comparisonValue, field):
 | |
|         self.name = name
 | |
|         self.operator = operator
 | |
|         self.comparisonValue = comparisonValue
 | |
|         self.field = field
 | |
| 
 | |
|     def check(self, row):
 | |
|         comparisonValue = self.comparisonValue
 | |
|         if comparisonValue in (None, '',):
 | |
|             comparisonValue = self.field.defaultComparisonValue
 | |
|             if comparisonValue in (None, '',):
 | |
|                 return True
 | |
|         value = self.field.getSelectValue(row)
 | |
|         op = operators.get(self.operator)
 | |
|         if op is None:
 | |
|             op = getattr(standard_operators, self.operator, None)
 | |
|         if op is None:
 | |
|             # TODO: log warning
 | |
|             return True
 | |
|         return op(value, comparisonValue)
 | |
| 
 | |
|     def showComparisonValue(self):
 | |
|         if self.field.fieldType == 'selection' and self.comparisonValue:
 | |
|             return ', '.join([v for v in self.comparisonValue])
 | |
|         return self.comparisonValue
 | |
| 
 | |
|     def showOperator(self):
 | |
|         op = self.operator
 | |
|         for item in self.field.operators:
 | |
|             if item['token'] == op:
 | |
|                 return item['label']
 | |
|         return op
 | |
| 
 | |
| 
 | |
| def checkOnly(value, compValue):
 | |
|     if not value:
 | |
|         return 'none' in compValue
 | |
|     for v in value:
 | |
|         if v not in compValue:
 | |
|             return False
 | |
|     return True
 | |
| 
 | |
| def checkIn(value, compValue):
 | |
|     return value in compValue
 | |
| 
 | |
| def checkAny(value, compValue):
 | |
|     for v in value:
 | |
|         if v in compValue:
 | |
|             return True
 | |
|     return False
 | |
| 
 | |
| def checkNotAny(value, compValue):
 | |
|     return not checkAny(value, compValue)
 | |
| 
 | |
| operators = {'any': checkAny, 'not_any': checkNotAny,
 | |
|              'in': checkIn, 'only': checkOnly}
 | |
| 
 | |
| 
 | |
| class CompoundQueryCriteria(BaseQueryCriteria, Compound):
 | |
| 
 | |
|     implements(ICompoundQueryCriteria)
 | |
| 
 | |
|     logicalOperator = 'and'
 | |
| 
 | |
|     def __init__(self, parts):
 | |
|         self.parts = Jeep(parts)
 | |
| 
 | |
|     def check(self, obj):
 | |
|         for p in self.parts:
 | |
|             if not p.check(obj):
 | |
|                 return False
 | |
|         return True
 |