Upload the contribution of vstf as bottleneck network framework.
[bottlenecks.git] / vstf / vstf / controller / reporters / report / pdf / element.py
1 #!/usr/bin/python
2 # -*- coding: utf8 -*-
3 # author: wly
4 # date: 2015-05-04
5 # see license for license details
6 __version__ = ''' '''
7 __doc__ = """
8 it contains the base element for pdf
9 eImage is used to draw picture on the pdf document
10 eDataTable is used to draw table on the pdf document
11 eGraphicsTable is used to draw plot on the pdf document
12 eParagraph is used to draw text on the pdf document
13 """
14 from reportlab.platypus import Image, Table
15 from reportlab.graphics.shapes import Drawing
16 from reportlab.graphics.charts.lineplots import LinePlot
17 from reportlab.graphics.charts.linecharts import HorizontalLineChart
18 from reportlab.platypus.paragraph import Paragraph
19 from reportlab.graphics.widgets.markers import makeMarker
20 from reportlab.graphics.charts.legends import Legend
21 from reportlab.graphics.charts.textlabels import Label
22 from reportlab.graphics.charts.axes import XValueAxis
23 from reportlab.graphics.shapes import Group
24 from reportlab.graphics.charts.barcharts import VerticalBarChart
25 from vstf.controller.reporters.report.pdf.styles import *
26
27
28 class eImage(Image):
29     """ an image(digital picture)which contains the function of auto zoom picture """
30
31     def __init__(self, filename, width=None, height=None, kind='direct', mask="auto", lazy=1, hAlign='CENTRE',
32                  vAlign='BOTTOM'):
33         Image.__init__(self, filename, None, None, kind, mask, lazy)
34         print height, width
35         print self.drawHeight, self.drawWidth
36         if self.drawWidth * height > self.drawHeight * width:
37             self.drawHeight = width * self.drawHeight / self.drawWidth
38             self.drawWidth = width
39         else:
40             self.drawWidth = height * self.drawWidth / self.drawHeight
41             self.drawHeight = height
42         self.hAlign = hAlign
43         self.vAlign = vAlign
44         print self.drawHeight, self.drawWidth
45
46
47 class eTable(object):
48     """ an abstract table class, which is contains the base functions to create table """
49
50     def __init__(self, data, style=TableStyle(name="default")):
51         self._tablestyle = style
52         self._table = []
53         self._spin = False
54         self._colWidths = None
55         self._data = self.analysisData(data)
56         if self._data:
57             self.create()
58
59     def analysisData(self, data):
60         raise NotImplementedError("abstract eTable")
61
62     def create(self):
63         self._table = Table(self._data, style=self._style, splitByRow=1)
64         self._table.hAlign = self._tablestyle.table_hAlign
65         self._table.vAlign = self._tablestyle.table_vAlign
66         self._table.colWidths = self._tablestyle.table_colWidths
67         if self._spin or self._colWidths:
68             self._table.colWidths = self._colWidths
69         self._table.rowHeights = self._tablestyle.table_rowHeights
70
71     @property
72     def table(self):
73         return self._table
74
75
76 class eCommonTable(eTable):
77     def analysisData(self, data):
78         self._style = [
79             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
80             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
81             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
82             ('BOX', (0, 0), (-1, -1), 1.2, colors.black)
83         ]
84         return data
85
86
87 class eConfigTable(eTable):
88     def analysisData(self, data):
89         self._style = [
90             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
91             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
92             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
93             ('BOX', (0, 0), (-1, -1), 1, colors.black),
94             ('SPAN', (2, 0), (3, 0)),
95             ('SPAN', (2, 1), (3, 1)),
96             ('SPAN', (2, 8), (3, 8)),
97             ('SPAN', (2, 9), (3, 9)),
98             ('SPAN', (2, 10), (3, 10)),
99             ('SPAN', (0, 0), (0, 7)),
100             ('SPAN', (0, 8), (0, 10)),
101             ('SPAN', (0, 11), (0, 19)),
102             ('SPAN', (1, 2), (1, 6)),
103             ('SPAN', (1, 12), (1, 13)),
104             ('SPAN', (1, 14), (1, 16)),
105             ('SPAN', (1, 17), (1, 19)),
106             ('SPAN', (2, 3), (2, 6))
107         ]
108         return data
109
110
111 class eSummaryTable(eTable):
112     def analysisData(self, data):
113         self._style = [
114             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
115             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
116             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
117             ('BOX', (0, 0), (-1, -1), 1, colors.black),
118             ('SPAN', (0, 0), (0, 1)),
119             ('SPAN', (1, 0), (4, 0)),
120             ('SPAN', (5, 0), (-1, 0))
121         ]
122         return data
123
124
125 class eGitInfoTable(eTable):
126     def analysisData(self, data):
127         self._style = [
128             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
129             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
130             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
131             ('BOX', (0, 0), (-1, -1), 1, colors.black),
132             ('SPAN', (0, 0), (0, 2)),
133             ('SPAN', (0, 3), (0, 5)),
134             ('SPAN', (0, 6), (0, 8))
135         ]
136         return data
137
138
139 class eScenarioTable(eTable):
140     def analysisData(self, data):
141         self._style = [
142             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
143             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
144             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
145             ('BOX', (0, 0), (-1, -1), 1, colors.black),
146             ('ALIGN', (2, 1), (-1, -1), 'LEFT'),
147             ('SPAN', (0, 1), (0, 6)),
148             ('SPAN', (0, 7), (0, 12)),
149             ('SPAN', (0, 13), (0, 16)),
150             ('SPAN', (0, 17), (0, 20))
151         ]
152         return data
153
154
155 class eOptionsTable(eTable):
156     def analysisData(self, data):
157         self._style = [
158             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
159             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
160             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
161             ('BOX', (0, 0), (-1, -1), 1, colors.black),
162             ('SPAN', (2, 0), (4, 0)),
163             ('SPAN', (2, 1), (4, 1)),
164             ('SPAN', (0, 0), (0, -1)),
165             ('SPAN', (1, 2), (1, 16)),
166             ('SPAN', (1, 17), (1, 19)),
167             ('SPAN', (1, 20), (1, 22)),
168             ('SPAN', (1, 23), (1, 24)),
169             ('SPAN', (2, 2), (2, 4)),
170             ('SPAN', (2, 5), (2, 12)),
171             ('SPAN', (2, 13), (2, 16)),
172             ('SPAN', (2, 17), (2, 19)),
173             ('SPAN', (2, 20), (2, 22)),
174             ('SPAN', (2, 23), (2, 24))
175         ]
176         return data
177
178
179 class eProfileTable(eTable):
180     def analysisData(self, data):
181         self._style = [
182             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
183             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
184             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
185             ('BOX', (0, 0), (-1, -1), 1, colors.black),
186             ('SPAN', (0, 1), (0, -1)),
187             ('SPAN', (1, 0), (2, 0)),
188         ]
189         return data
190
191
192 class eDataTable(eTable):
193     def analysisData(self, data):
194         result = data
195         self._style = [
196             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
197             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
198             ('LEADING', (0, 0), (-1, -1), 18),
199             ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
200             ('BOX', (0, 0), (-1, -1), 1, colors.black),
201             ('LINEBEFORE', (1, 0), (1, -1), 0.8, colors.black),
202             # ('LINEBEFORE', (3, 0), (3, -1), 1, colors.black),
203             # ('LINEBEFORE', (5, 0), (5, -1), 1, colors.black),
204             ('LINEBELOW', (0, 0), (-1, 0), 0.8, colors.black),
205             # ('SPAN', (0, 0), (0, 1)),
206             # ('SPAN', (1, 0), (2, 0)),
207             # ('SPAN', (3, 0), (4, 0))
208         ]
209         if self._spin is True:
210             print "start spin"
211             result = map(list, zip(*result))
212             style = []
213             for value in self._style:
214                 value = list(value)
215                 value[1] = (value[1][1], value[1][0])
216                 value[2] = (value[2][1], value[2][0])
217                 if value[0] == 'LINEBELOW':
218                     value[0] = 'LINEAFTER'
219                 elif value[0] == 'LINEBEFORE':
220                     value[0] = 'LINEABOVE'
221                 value = tuple(value)
222                 style.append(value)
223             self._style = style
224         return result
225
226
227 class eGraphicsTable(eTable):
228     def analysisData(self, data):
229         self._style = [
230             ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
231             ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')
232         ]
233         return data
234
235
236 class noScaleXValueAxis(XValueAxis):
237     def __init__(self):
238         XValueAxis.__init__(self)
239
240     def makeTickLabels(self):
241         g = Group()
242         if not self.visibleLabels: return g
243
244         f = self._labelTextFormat  # perhaps someone already set it
245         if f is None:
246             f = self.labelTextFormat or (self._allIntTicks() and '%.0f' or str)
247         elif f is str and self._allIntTicks():
248             f = '%.0f'
249         elif hasattr(f, 'calcPlaces'):
250             f.calcPlaces(self._tickValues)
251         post = self.labelTextPostFormat
252         scl = self.labelTextScale
253         pos = [self._x, self._y]
254         d = self._dataIndex
255         pos[1 - d] = self._labelAxisPos()
256         labels = self.labels
257         if self.skipEndL != 'none':
258             if self.isXAxis:
259                 sk = self._x
260             else:
261                 sk = self._y
262             if self.skipEndL == 'start':
263                 sk = [sk]
264             else:
265                 sk = [sk, sk + self._length]
266                 if self.skipEndL == 'end':
267                     del sk[0]
268         else:
269             sk = []
270
271         nticks = len(self._tickValues)
272         nticks1 = nticks - 1
273         for i, tick in enumerate(self._tickValues):
274             label = i - nticks
275             if label in labels:
276                 label = labels[label]
277             else:
278                 label = labels[i]
279             if f and label.visible:
280                 v = self.scale(i)
281                 if sk:
282                     for skv in sk:
283                         if abs(skv - v) < 1e-6:
284                             v = None
285                             break
286                 if v is not None:
287                     if scl is not None:
288                         t = tick * scl
289                     else:
290                         t = tick
291                     if isinstance(f, str):
292                         txt = f % t
293                     elif isSeq(f):
294                         # it's a list, use as many items as we get
295                         if i < len(f):
296                             txt = f[i]
297                         else:
298                             txt = ''
299                     elif hasattr(f, '__call__'):
300                         if isinstance(f, TickLabeller):
301                             txt = f(self, t)
302                         else:
303                             txt = f(t)
304                     else:
305                         raise ValueError('Invalid labelTextFormat %s' % f)
306                     if post: txt = post % txt
307                     pos[d] = v
308                     label.setOrigin(*pos)
309                     label.setText(txt)
310
311                     # special property to ensure a label doesn't project beyond the bounds of an x-axis
312                     if self.keepTickLabelsInside:
313                         if isinstance(self, XValueAxis):  # not done yet for y axes
314                             a_x = self._x
315                             if not i:  # first one
316                                 x0, y0, x1, y1 = label.getBounds()
317                                 if x0 < a_x:
318                                     label = label.clone(dx=label.dx + a_x - x0)
319                             if i == nticks1:  # final one
320                                 a_x1 = a_x + self._length
321                                 x0, y0, x1, y1 = label.getBounds()
322                                 if x1 > a_x1:
323                                     label = label.clone(dx=label.dx - x1 + a_x1)
324                     g.add(label)
325
326         return g
327
328     def ___calcScaleFactor(self):
329         """Calculate the axis' scale factor.
330         This should be called only *after* the axis' range is set.
331         Returns a number.
332         """
333         self._scaleFactor = self._length / (len(self._tickValues) + 1)
334         return self._scaleFactor
335
336     def scale(self, value):
337         """Converts a numeric value to a plotarea position.
338         The chart first configures the axis, then asks it to
339         """
340         assert self._configured, "Axis cannot scale numbers before it is configured"
341         if value is None: value = 0
342         # this could be made more efficient by moving the definition of org and sf into the configuration
343         org = (self._x, self._y)[self._dataIndex]
344         sf = self._length / (len(self._tickValues) + 1)
345         if self.reverseDirection:
346             sf = -sf
347             org += self._length
348         return org + sf * (value + 1)
349
350
351 class noScaleLinePlot(LinePlot):
352     def __init__(self):
353         LinePlot.__init__(self)
354         self.xValueAxis = noScaleXValueAxis()
355
356     def calcPositions(self):
357         """Works out where they go.
358
359         Sets an attribute _positions which is a list of
360         lists of (x, y) matching the data.
361         """
362         self._seriesCount = len(self.data)
363         self._rowLength = max(map(len, self.data))
364
365         self._positions = []
366         for rowNo in range(len(self.data)):
367             line = []
368             len_row = len(self.data[rowNo])
369             for colNo in range(len_row):
370                 datum = self.data[rowNo][colNo]  # x, y value
371                 x = self.x + self.width / (len_row + 1) * (colNo + 1)
372                 self.xValueAxis.labels[colNo].x = self.x + self.width / (len_row + 1) * (colNo + 1)
373                 y = self.yValueAxis.scale(datum[1])
374                 #               print self.width, " ", x
375                 line.append((x, y))
376             self._positions.append(line)
377
378
379 # def _innerDrawLabel(self, rowNo, colNo, x, y):
380 #        return None
381 class eLinePlot(object):
382     def __init__(self, data, style):
383         self._lpstyle = style
384         self._linename = data[0]
385         self._data = self.analysisData(data[1:])
386         if self._data:
387             self.create()
388
389     @property
390     def draw(self):
391         return self._draw
392
393     def analysisData(self, data):
394         columns = len(data)
395         # print data
396         data = map(list, zip(*data))
397         rows = len(data)
398
399         for i in range(rows):
400             for j in range(columns):
401                 data[i][j] = float(data[i][j])
402         self._linename = self._linename[1:]
403         """
404         delcnt = 0
405         delrows = []
406         for i in range(columns):
407             delrows.append(0.0)
408         del_line = [self._linename[0]]
409         for i in range(rows):
410            for j in range(columns):
411               data[i][j] = float(data[i][j])
412            if data[i] == delrows:
413                delcnt += 1
414                del_line.append(self._linename[i])
415         for i in range(delcnt):
416             data.remove(delrows)
417         for name in del_line:
418             self._linename.remove(name)
419
420         rows = len(data)
421         """
422         # print rows
423         # print data
424         xvalueSteps = data[0]
425         xvalueMin = data[0][0]
426         xvalueMax = data[0][0]
427         yvalueMin = data[1][0]
428         yvalueMax = data[1][0]
429         yvalueSteps = []
430         result = []
431         for j in range(columns):
432             if xvalueMin > data[0][j]:
433                 xvalueMin = data[0][j]
434             if xvalueMax < data[0][j]:
435                 xvalueMax = data[0][j]
436
437         for i in range(rows - 1):
438             lst = []
439             for j in range(columns):
440                 lst.append((data[0][j], data[i + 1][j]))
441                 if yvalueMin > data[i + 1][j]:
442                     yvalueMin = data[i + 1][j]
443                 if yvalueMax < data[i + 1][j]:
444                     yvalueMax = data[i + 1][j]
445                 yvalueSteps.append(int(data[i + 1][j] * 2.5) / 2.5)
446             result.append(tuple(lst))
447         xvalueMin = int(xvalueMin) / 100 * 100
448         xvalueMax = int(xvalueMax) / 100 * 100 + 200
449         yvalueMin = int(yvalueMin) * 1.0 - 1
450         if yvalueMin < 0:
451             yvalueMin = 0.0
452         yvalueMax = int(yvalueMax) + 2.0
453         yvalueSteps.append(yvalueMin)
454         yvalueSteps.append(yvalueMax)
455         yvalueSteps = {}.fromkeys(yvalueSteps).keys()
456
457         self._xvalue = (xvalueMin, xvalueMax, xvalueSteps)
458         self._yvalue = (yvalueMin, yvalueMax, yvalueSteps)
459         print result
460         return result
461
462     def create(self):
463         lpw = self._lpstyle.width
464         lph = self._lpstyle.height
465         draw = Drawing(lpw, lph)
466         line_cnts = len(self._linename)
467         #        lp = noScaleLinePlot()
468         lp = LinePlot()
469         lg_line = (line_cnts + 3) / 4
470         lp.x = self._lpstyle.left
471         lp.y = self._lpstyle.bottom
472
473         lp.height = lph - self._lpstyle.bottom * (lg_line + 1.5)
474         lp.width = lpw - lp.x * 2
475         lp.data = self._data
476         lp.joinedLines = 1
477         lp.strokeWidth = self._lpstyle.strokeWidth
478         line_cnts = len(self._data)
479         sytle_cnts = len(self._lpstyle.linestyle)
480         color_paris = []
481         for i in range(line_cnts):
482             styleIndex = i % sytle_cnts
483             lp.lines[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
484             lp.lines[i].symbol = makeMarker(self._lpstyle.linestyle[styleIndex][1])
485             lp.lines[i].strokeWidth = self._lpstyle.linestyle[styleIndex][2]
486             color_paris.append((self._lpstyle.linestyle[styleIndex][0], self._linename[i]))
487         #            lp.lineLabels[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
488
489         lp.lineLabelFormat = self._lpstyle.format[0]
490
491         lp.strokeColor = self._lpstyle.strokeColor
492
493         lp.xValueAxis.valueMin, lp.xValueAxis.valueMax, lp.xValueAxis.valueSteps = self._xvalue
494         #       valueMin, valueMax, xvalueSteps = self._xvalue
495         #       lp.xValueAxis.valueStep = (lp.xValueAxis.valueMax - lp.xValueAxis.valueMin)/len(xvalueSteps)
496         #       lp.xValueAxis.valueSteps = map(lambda x: str(x), xvalueSteps)
497
498         lp.yValueAxis.valueMin, lp.yValueAxis.valueMax, lp.yValueAxis.valueSteps = self._yvalue
499
500
501
502         #       lp.xValueAxis.forceZero = 0
503         #       lp.xValueAxis.avoidBoundFrac = 1
504         #       lp.xValueAxis.tickDown = 3
505         #       lp.xValueAxis.visibleGrid = 1
506         #       lp.xValueAxis.categoryNames = '64 256 512 1400 1500 4096'.split(' ')
507
508         lp.xValueAxis.labelTextFormat = self._lpstyle.format[1]
509         lp.yValueAxis.labelTextFormat = self._lpstyle.format[2]
510
511         delsize = int(lp.xValueAxis.valueMax / 2000)
512         lp.xValueAxis.labels.fontSize = self._lpstyle.labelsfont
513         lp.xValueAxis.labels.angle = 25
514
515         lp.yValueAxis.labels.fontSize = self._lpstyle.labelsfont
516         lp.lineLabels.fontSize = self._lpstyle.labelsfont - delsize
517         draw.add(lp)
518
519         lg = Legend()
520         lg.colorNamePairs = color_paris
521         lg.fontName = 'Helvetica'
522         lg.fontSize = 7
523
524         lg.x = self._lpstyle.left * 3
525         lg.y = self._lpstyle.bottom * (1 + lg_line) + lp.height
526
527         lg.dxTextSpace = 5
528         lg.dy = 5
529         lg.dx = 20
530         lg.deltax = 60
531         lg.deltay = 0
532         lg.columnMaximum = 1
533         lg.alignment = 'right'
534         draw.add(lg)
535         self._draw = draw
536
537
538 class eHorizontalLineChart(object):
539     def __init__(self, data, style):
540         self._lcstyle = style
541         if len(data) < 1:
542             return
543         self._linename = data[0]
544         self._data = self.analysisData(data[1:])
545         if self._data:
546             self.create()
547
548     @property
549     def draw(self):
550         return self._draw
551
552     def analysisData(self, data):
553         columns = len(data)
554         data = map(list, zip(*data))
555         self._catNames = data[0]
556         self._linename = self._linename[1:]
557         data = data[1:]
558         rows = len(data)
559
560         yvalueMin = float(data[0][0])
561         yvalueMax = float(data[0][0])
562         yvalueSteps = []
563         result = []
564
565         for rowNo in range(rows):
566             for columnNo in range(columns):
567                 data[rowNo][columnNo] = float(data[rowNo][columnNo])
568                 if yvalueMin > data[rowNo][columnNo]:
569                     yvalueMin = data[rowNo][columnNo]
570                 if yvalueMax < data[rowNo][columnNo]:
571                     yvalueMax = data[rowNo][columnNo]
572                 yvalueSteps.append(int(data[rowNo][columnNo] * 1.0) / 1.0)
573             result.append(tuple(data[rowNo]))
574
575         yvalueMin = int(yvalueMin) * 1.0 - 1
576         if yvalueMin < 0:
577             yvalueMin = 0.0
578         yvalueMax = int(yvalueMax) + 2.0
579         yvalueSteps.append(yvalueMin)
580         yvalueSteps.append(yvalueMax)
581         yvalueSteps = {}.fromkeys(yvalueSteps).keys()
582
583         self._value = (yvalueMin, yvalueMax, yvalueSteps)
584         print result
585         return result
586
587     def create(self):
588         dw = self._lcstyle.width
589         dh = self._lcstyle.height
590         draw = Drawing(dw, dh)
591
592         lc = HorizontalLineChart()
593         line_cnts = len(self._linename)
594
595         lg_line = (line_cnts + 3) / 4
596         lc.height = dh - self._lcstyle.bottom * (lg_line + 1.5)
597         lc.width = dw - lc.x * 2
598         lc.x = self._lcstyle.left
599         lc.y = self._lcstyle.bottom
600
601         lc.data = self._data
602
603         lc.strokeColor = self._lcstyle.strokeColor
604         lc.strokeWidth = self._lcstyle.strokeWidth
605         lc.useAbsolute = 1
606         lc.groupSpacing = lc.width * 2.0 / len(self._catNames)
607         lc.joinedLines = 1
608         lc.lineLabelFormat = self._lcstyle.format[0]
609
610         lc.valueAxis.valueMin, lc.valueAxis.valueMax, lc.valueAxis.valueSteps = self._value
611         lc.valueAxis.labelTextFormat = self._lcstyle.format[1]
612         lc.valueAxis.labels.fontSize = self._lcstyle.labelsfont
613
614         lc.categoryAxis.categoryNames = self._catNames
615         lc.categoryAxis.labels.boxAnchor = 'ne'
616         lc.categoryAxis.labels.dx = lc.width / 2.0 / len(self._catNames)
617         lc.categoryAxis.labels.dy = -6
618         lc.categoryAxis.labels.angle = 10
619         lc.categoryAxis.labels.fontSize = self._lcstyle.labelsfont
620         #        lc.categoryAxis.visibleGrid = 1
621         #        lc.categoryAxis.tickUp = 100
622         #        lc.categoryAxis.tickDown = 50
623         #        lc.categoryAxis.gridEnd = dh
624         sytle_cnts = len(self._lcstyle.linestyle)
625         color_paris = []
626         for i in range(line_cnts):
627             styleIndex = i % sytle_cnts
628             lc.lines[i].strokeColor = self._lcstyle.linestyle[styleIndex][0]
629             lc.lines[i].symbol = makeMarker(self._lcstyle.linestyle[styleIndex][1])
630             lc.lines[i].strokeWidth = self._lcstyle.linestyle[styleIndex][2]
631             color_paris.append((self._lcstyle.linestyle[styleIndex][0], self._linename[i]))
632
633         lc.lineLabels.fontSize = self._lcstyle.labelsfont - 2
634
635         draw.add(lc)
636
637         lg = Legend()
638         lg.colorNamePairs = color_paris
639         lg.fontName = 'Helvetica'
640         lg.fontSize = 7
641         #        lg.x = dw /2
642         #        lg.y = self._lcstyle.bottom *(1.5 + lg_line)
643
644         lg.x = self._lcstyle.left * 3
645         lg.y = self._lcstyle.bottom * (1 + lg_line) + lc.height
646
647         lg.dxTextSpace = 5
648         lg.dy = 5
649         lg.dx = 20
650         lg.deltax = 60
651         lg.deltay = 0
652         lg.columnMaximum = 1
653         lg.alignment = 'right'
654         draw.add(lg)
655         self._draw = draw
656
657
658 class eBarChartColumn(object):
659     def __init__(self, data, style):
660         self._bcstyle = style
661         if len(data) < 4:
662             return
663         self._data = self.analysisData(data)
664         if self._data:
665             self.create()
666
667     @property
668     def draw(self):
669         return self._draw
670
671     def analysisData(self, data):
672         self._ytitle = data[0]
673         self._name = data[1]
674         self._bar = data[2]
675         bar_data = data[3]
676         result = []
677         for bar in bar_data:
678             bar = map(lambda x: float(x), bar)
679             result.append(tuple(bar))
680         return result
681
682     def create(self):
683         dw = self._bcstyle.width
684         dh = self._bcstyle.height
685         draw = Drawing(dw, dh)
686
687         bc = VerticalBarChart()
688         bar_cnt = len(self._bar)
689         lg_line = (bar_cnt + 3) / 4
690
691         bc.width = dw - self._bcstyle.left - self._bcstyle.right
692         bc.height = dh - self._bcstyle.top - self._bcstyle.bottom
693         if bar_cnt > 1:
694             bc.height -= lg_line * 15
695
696         bc.x = self._bcstyle.left
697         bc.y = self._bcstyle.bottom
698         color_paris = []
699         for i in range(bar_cnt):
700             bc.bars[i].fillColor = self._bcstyle.pillarstyle[self._bar[i]][0]
701             color_paris.append((self._bcstyle.pillarstyle[self._bar[i]][0], self._bar[i]))
702
703         bc.fillColor = self._bcstyle.background
704         bc.barLabels.fontName = 'Helvetica'
705         bc.barLabelFormat = self._bcstyle.pillarstyle[self._bar[0]][1]
706         bc.barLabels.fontSize = self._bcstyle.labelsfont
707         bc.barLabels.dy = self._bcstyle.labelsfont
708         bc.valueAxis.labels.fontName = 'Helvetica'
709         bc.valueAxis.labels.fontSize = self._bcstyle.labelsfont
710         bc.valueAxis.forceZero = 1
711         bc.valueAxis.valueMin = 0
712
713         bc.data = self._data
714         bc.barSpacing = self._bcstyle.barSpacing
715         bc.groupSpacing = self._bcstyle.groupSpacing / bar_cnt
716         bc.valueAxis.avoidBoundFrac = 1
717         bc.valueAxis.gridEnd = dw - self._bcstyle.right
718         bc.valueAxis.tickLeft = self._bcstyle.tick
719         bc.valueAxis.visibleGrid = 1
720         bc.categoryAxis.categoryNames = self._name
721         bc.categoryAxis.tickDown = self._bcstyle.tick
722         bc.categoryAxis.labels.fontName = 'Helvetica'
723         bc.categoryAxis.labels.fontSize = self._bcstyle.labelsfont
724         bc.categoryAxis.labels.dy = -27
725         bc.categoryAxis.labels.angle = -90
726         draw.add(bc)
727         lb = Label()
728         lb.fontName = 'Helvetica'
729         lb.fontSize = 7
730         lb.x = 12
731         lb.y = 80
732         lb.angle = 90
733         lb.textAnchor = 'middle'
734         lb.maxWidth = 100
735         lb.height = 20
736         lb._text = self._ytitle
737         draw.add(lb)
738         if bar_cnt > 1:
739             lg = Legend()
740             lg.colorNamePairs = color_paris
741             lg.fontName = 'Helvetica'
742             lg.fontSize = 7
743
744             lg.x = self._bcstyle.left + bc.width / (bar_cnt + 1)
745             lg.y = dh - self._bcstyle.top - lg_line * 5
746
747             lg.dxTextSpace = 5
748             lg.dy = 5
749             lg.dx = 25
750             lg.deltax = 80
751             lg.deltay = 0
752             lg.columnMaximum = 1
753             lg.alignment = 'right'
754             draw.add(lg)
755
756         self._draw = draw
757
758
759 class eParagraph(object):
760     def __init__(self, data, style):
761         self._pstyle = style
762         self._data = self.analysisData(data)
763         self.create()
764
765     def analysisData(self, data):
766         result = ""
767         for dstr in data:
768             if self._pstyle.name == 'ps_body':
769                 #               dstr = "<i>" + dstr + "</i><br/>"
770                 dstr = dstr + "<br/>"
771             else:
772                 dstr = dstr + "<br/>"
773             result += dstr
774         return result
775
776     def create(self):
777         self._para = Paragraph(self._data, self._pstyle)
778
779     @property
780     def para(self):
781         return self._para