00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 from PyQt4.QtCore import *
00030 from PyQt4.QtGui import *
00031 from Koo.KooChart import *
00032 from Koo import Rpc
00033 
00034 import datetime 
00035 import time
00036 import locale
00037 
00038 DT_FORMAT = '%Y-%m-%d'
00039 DHM_FORMAT = '%Y-%m-%d %H:%M:%S'
00040 HM_FORMAT = '%H:%M:%S'
00041 
00042 if not hasattr(locale, 'nl_langinfo'):
00043         locale.nl_langinfo = lambda *a: '%x'
00044 
00045 if not hasattr(locale, 'D_FMT'):
00046         locale.D_FMT = None
00047 
00048 
00049 class ChartGraphicsView( QGraphicsView ):
00050         def __init__(self, parent=None):
00051                 QGraphicsView.__init__(self, parent)
00052                 self.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform )
00053                 self.scene = QGraphicsScene(self)
00054                 self.setScene( self.scene )
00055                 self.chart = None
00056 
00057         def setModel(self, model):
00058                 self._model = model
00059 
00060         def setFields(self, fields):
00061                 self._fields = fields
00062 
00063         def setType(self, type):
00064                 self._type = type
00065 
00066         def setAxis(self, axis):
00067                 self._axis = axis
00068 
00069         def setGroups(self, groups):
00070                 self._groups = groups
00071 
00072         def setAxisData(self, axisData):
00073                 self._axisData = axisData
00074 
00075         def setAxisGroupField(self, axisGroupField):
00076                 self._axisGroupField = axisGroupField
00077 
00078         def setOrientation(self, orientation):
00079                 self._orientation = orientation
00080 
00081         def resizeEvent(self, event):
00082                 if self.chart:
00083                         self.chart.setSize( QSize( self.size().width() - 100, self.size().height() - 100 ) )
00084 
00085         def replaceFalse(self, l):
00086                 newList = []
00087                 for x in l:
00088                         if isinstance(x, bool):
00089                                 newList.append( '-' )
00090                         else:
00091                                 newList.append( unicode(x) )
00092                 return newList
00093 
00094         def display(self, models):
00095                 self._models = models
00096                 if not self.chart:
00097                         if self._type == 'pie': 
00098                                 self.chart = GraphicsPieChartItem()
00099                         else:
00100                                 self.chart = GraphicsBarChartItem()
00101                                 if self._orientation == Qt.Horizontal:
00102                                         self.chart.setAggregated( True )
00103                         self.chart.setSize( self.size() )
00104                         self.scene.addItem( self.chart )
00105 
00106                 
00107                 records = []
00108 
00109                 
00110                 if models:
00111                         
00112                         
00113                         
00114                         
00115                         
00116                         
00117                         
00118                         for m in models:
00119                                 res = {}
00120                                 for x in self._axisData.keys():
00121                                         type = self._fields[x]['type']
00122                                         if type in ('many2one', 'char','time','text'):
00123                                                 res[x] = m.value(x) 
00124                                         elif type == 'selection':
00125                                                 res[x] = ''
00126                                                 for y in self._fields[x]['selection']:
00127                                                         if y[0] == m.value(x):
00128                                                                 res[x] = unicode(y[1])
00129                                                                 break
00130                                         elif type == 'date':
00131                                                 date = time.strptime(m.value(x), DT_FORMAT)
00132                                                 res[x] = time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'), date)
00133                                         elif type == 'datetime':
00134                                                 date = time.strptime(m.value(x), DHM_FORMAT)
00135                                                 if 'tz' in Rpc.session.context:
00136                                                         try:
00137                                                                 import pytz
00138                                                                 lzone = pytz.timezone(Rpc.session.context['tz'])
00139                                                                 szone = pytz.timezone(Rpc.session.timezone)
00140                                                                 dt = datetime.datetime(date[0], date[1], date[2], date[3], date[4], date[5], date[6])
00141                                                                 sdt = szone.localize(dt, is_dst=True)
00142                                                                 ldt = sdt.astimezone(lzone)
00143                                                                 date = ldt.timetuple()
00144                                                         except:
00145                                                                 pass
00146                                                 res[x] = time.strftime(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')+' %H:%M:%S', date)
00147                                         else:
00148                                                 res[x] = float(m.value(x))
00149                                 records.append(res)
00150 
00151                 
00152                 operators = {
00153                         '+': lambda x,y: x+y,
00154                         '*': lambda x,y: x*y,
00155                         'min': lambda x,y: min(x,y),
00156                         'max': lambda x,y: max(x,y),
00157                         '**': lambda x,y: x**y
00158                 }
00159                 
00160                 
00161                 
00162                 
00163                 
00164                 
00165                 
00166                 
00167                 
00168                 
00169                 aggRecords = []
00170                 groups = {}
00171                 for field in self._axis[1:]:
00172                         data = {}
00173                         for d in records:
00174                                 data.setdefault( d[self._axis[0]], {} )
00175 
00176                                 groupEval = ','.join( self.replaceFalse([d[x] for x in self._groups]) )
00177                                 groups[groupEval] = 1
00178 
00179                                 if groupEval in data[d[self._axis[0]]]:
00180                                         oper = operators[self._axisData[field].get('operator', '+')]
00181                                         data[d[self._axis[0]]][groupEval] = oper(data[d[self._axis[0]]][groupEval], d[field])
00182                                 else:
00183                                         data[d[self._axis[0]]][groupEval] = d[field]
00184                         aggRecords.append(data)
00185                 groups = groups.keys()
00186                 groups.sort()
00187 
00188                 fields = set()
00189                 for field in self._axis[1:]:
00190                         fields.add( self._fields[field]['name'] )
00191                 fields = list(fields)
00192                 fields.sort()
00193 
00194                 labels = [self._fields[x]['string'] for x in self._axis[1:]]
00195 
00196                 categories = set()
00197                 for x in records:
00198                         categories.add( x[ self._axis[0] ] )
00199                 categories = list(categories)
00200                 categories.sort()
00201 
00202                 if self._type == 'pie': 
00203                         categories = data.keys()
00204                         values = [ reduce(lambda x,y=0: x+y, data[x].values(), 0) for x in categories ]
00205                         self.chart.setValues( values ) 
00206                         
00207                         self.chart.setLabels( self.replaceFalse(categories) )
00208                 else:
00209                         
00210                         
00211                         if groups and groups[0]:
00212                                 
00213                                 
00214                                 
00215                                 
00216                                 
00217                                 values = []
00218                                 for x in categories:
00219                                         value = []
00220                                         for y in groups:
00221                                                 for z in aggRecords:
00222                                                         value.append( z[ x ].get(y, 0.0) )
00223                                         values.append( value )  
00224                                 
00225                                 labels = groups
00226                         else:
00227                                 values = []
00228                                 for x in categories:
00229                                         value = []
00230                                         for y in aggRecords:
00231                                                 value.append( y[ x ][''] )
00232                                         values.append( value )  
00233 
00234                         self.chart.setValues( values )
00235                         
00236                         self.chart.setLabels( self.replaceFalse(labels) )
00237                         
00238                         self.chart.setCategories( self.replaceFalse(categories) )
00239