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