]>
Commit | Line | Data |
---|---|---|
1 | #---------------------------------------------------------------------------- | |
2 | # Name: printout.py | |
3 | # Purpose: preview and printing class -> table/grid printing | |
4 | # | |
5 | # Author: Lorne White (email: lorne.white@telusplanet.net) | |
6 | # | |
7 | # Created: | |
8 | # Version 0.75 | |
9 | # Date: May 15, 2002 | |
10 | # Licence: wxWindows license | |
11 | #---------------------------------------------------------------------------- | |
12 | # Release Notes | |
13 | ||
14 | # fixed bug for string wider than print region | |
15 | # add index to data list after parsing total pages for paging | |
16 | #---------------------------------------------------------------------------- | |
17 | # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
18 | # | |
19 | # o 2.5 compatability update. | |
20 | # | |
21 | ||
22 | import copy | |
23 | import os | |
24 | import sys | |
25 | ||
26 | import wx | |
27 | ||
28 | class PrintBase: | |
29 | def SetPrintFont(self, font): # set the DC font parameters | |
30 | fattr = font["Attr"] | |
31 | if fattr[0] == 1: | |
32 | weight = wx.BOLD | |
33 | else: | |
34 | weight = wx.NORMAL | |
35 | ||
36 | if fattr[1] == 1: | |
37 | set_style = wx.ITALIC | |
38 | else: | |
39 | set_style = wx.NORMAL | |
40 | ||
41 | underline = fattr[2] | |
42 | fcolour = self.GetFontColour(font) | |
43 | self.DC.SetTextForeground(fcolour) | |
44 | ||
45 | setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline) | |
46 | setfont.SetFaceName(font["Name"]) | |
47 | self.DC.SetFont(setfont) | |
48 | ||
49 | def GetFontColour(self, font): | |
50 | fcolour = font["Colour"] | |
51 | return wx.Colour(fcolour[0], fcolour[1], fcolour[2]) | |
52 | ||
53 | def OutTextRegion(self, textout, txtdraw = True): | |
54 | textlines = textout.split('\n') | |
55 | y = copy.copy(self.y) + self.pt_space_before | |
56 | for text in textlines: | |
57 | remain = 'X' | |
58 | while remain != "": | |
59 | vout, remain = self.SetFlow(text, self.region) | |
60 | if self.draw == True and txtdraw == True: | |
61 | test_out = self.TestFull(vout) | |
62 | if self.align == wx.ALIGN_LEFT: | |
63 | self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y) | |
64 | ||
65 | elif self.align == wx.ALIGN_CENTRE: | |
66 | diff = self.GetCellDiff(test_out, self.region) | |
67 | self.DC.DrawText(test_out, self.indent+diff/2, y) | |
68 | ||
69 | elif self.align == wx.ALIGN_RIGHT: | |
70 | diff = self.GetCellDiff(test_out, self.region) | |
71 | self.DC.DrawText(test_out, self.indent+diff, y) | |
72 | ||
73 | else: | |
74 | self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y) | |
75 | text = remain | |
76 | y = y + self.space | |
77 | return y - self.space + self.pt_space_after | |
78 | ||
79 | def GetCellDiff(self, text, width): # get the remaining cell size for adjustment | |
80 | w, h = self.DC.GetTextExtent(text) | |
81 | diff = width - w | |
82 | if diff < 0: | |
83 | diff = 0 | |
84 | return diff | |
85 | ||
86 | def TestFull(self, text_test): | |
87 | w, h = self.DC.GetTextExtent(text_test) | |
88 | if w > self.region: # trouble fitting into cell | |
89 | return self.SetChar(text_test, self.region) # fit the text to the cell size | |
90 | else: | |
91 | return text_test | |
92 | ||
93 | def SetFlow(self, ln_text, width): | |
94 | width = width - self.pcell_right_margin | |
95 | text = "" | |
96 | split = ln_text.split() | |
97 | if len(split) == 1: | |
98 | return ln_text, "" | |
99 | ||
100 | try: | |
101 | w, h = self.DC.GetTextExtent(" " + split[0]) | |
102 | if w >= width: | |
103 | return ln_text, "" | |
104 | except: | |
105 | pass | |
106 | ||
107 | cnt = 0 | |
108 | for word in split: | |
109 | bword = " " + word # blank + word | |
110 | length = len(bword) | |
111 | ||
112 | w, h = self.DC.GetTextExtent(text + bword) | |
113 | if w < width: | |
114 | text = text + bword | |
115 | cnt = cnt + 1 | |
116 | else: | |
117 | remain = ' '.join(split[cnt:]) | |
118 | text = text.strip() | |
119 | return text, remain | |
120 | ||
121 | remain = ' '.join(split[cnt:]) | |
122 | vout = text.strip() | |
123 | return vout, remain | |
124 | ||
125 | def SetChar(self, ln_text, width): # truncate string to fit into width | |
126 | width = width - self.pcell_right_margin - self.pcell_left_margin | |
127 | text = "" | |
128 | for val in ln_text: | |
129 | w, h = self.DC.GetTextExtent(text + val) | |
130 | if w > width: | |
131 | text = text + ".." | |
132 | return text # fitted text value | |
133 | text = text + val | |
134 | return text | |
135 | ||
136 | def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True): | |
137 | textlines = textout.split('\n') | |
138 | y = copy.copy(y_out) | |
139 | ||
140 | pagew = self.parent.page_width * self.pwidth # full page width | |
141 | w, h = self.DC.GetTextExtent(textout) | |
142 | y_line = h | |
143 | ||
144 | for text in textlines: | |
145 | remain = 'X' | |
146 | while remain != "": | |
147 | vout, remain = self.SetFlow(text, pagew) | |
148 | if self.draw == True and txtdraw == True: | |
149 | test_out = vout | |
150 | if align == wx.ALIGN_LEFT: | |
151 | self.DC.DrawText(test_out, indent, y) | |
152 | ||
153 | elif align == wx.ALIGN_CENTRE: | |
154 | diff = self.GetCellDiff(test_out, pagew) | |
155 | self.DC.DrawText(test_out, indent+diff/2, y) | |
156 | ||
157 | elif align == wx.ALIGN_RIGHT: | |
158 | diff = self.GetCellDiff(test_out, pagew) | |
159 | self.DC.DrawText(test_out, indent+diff, y) | |
160 | ||
161 | else: | |
162 | self.DC.DrawText(test_out, indent, y_out) | |
163 | text = remain | |
164 | y = y + y_line | |
165 | return y - y_line | |
166 | ||
167 | def GetDate(self): | |
168 | date, time = self.GetNow() | |
169 | return date | |
170 | ||
171 | def GetDateTime(self): | |
172 | date, time = self.GetNow() | |
173 | return date + ' ' + time | |
174 | ||
175 | def GetNow(self): | |
176 | now = wx.DateTime.Now() | |
177 | date = now.FormatDate() | |
178 | time = now.FormatTime() | |
179 | return date, time | |
180 | ||
181 | def SetPreview(self, preview): | |
182 | self.preview = preview | |
183 | ||
184 | def SetPSize(self, width, height): | |
185 | self.pwidth = width/self.scale | |
186 | self.pheight = height/self.scale | |
187 | ||
188 | def SetScale(self, scale): | |
189 | self.scale = scale | |
190 | ||
191 | def SetPTSize(self, width, height): | |
192 | self.ptwidth = width | |
193 | self.ptheight = height | |
194 | ||
195 | def getWidth(self): | |
196 | return self.sizew | |
197 | ||
198 | def getHeight(self): | |
199 | return self.sizeh | |
200 | ||
201 | ||
202 | class PrintTableDraw(wx.ScrolledWindow, PrintBase): | |
203 | def __init__(self, parent, DC, size): | |
204 | self.parent = parent | |
205 | self.DC = DC | |
206 | self.scale = parent.scale | |
207 | self.width = size[0] | |
208 | self.height = size[1] | |
209 | self.SetDefaults() | |
210 | ||
211 | def SetDefaults(self): | |
212 | self.page = 1 | |
213 | self.total_pages = None | |
214 | ||
215 | self.page_width = self.parent.page_width | |
216 | self.page_height = self.parent.page_height | |
217 | ||
218 | self.left_margin = self.parent.left_margin | |
219 | self.right_margin = self.parent.right_margin | |
220 | ||
221 | self.top_margin = self.parent.top_margin | |
222 | self.bottom_margin = self.parent.bottom_margin | |
223 | self.cell_left_margin = self.parent.cell_left_margin | |
224 | self.cell_right_margin = self.parent.cell_right_margin | |
225 | ||
226 | self.label_colour = self.parent.label_colour | |
227 | ||
228 | self.row_line_colour = self.parent.row_line_colour | |
229 | self.row_line_size = self.parent.row_line_size | |
230 | ||
231 | self.row_def_line_colour = self.parent.row_def_line_colour | |
232 | self.row_def_line_size = self.parent.row_def_line_size | |
233 | ||
234 | self.column_line_colour = self.parent.column_line_colour | |
235 | self.column_line_size = self.parent.column_line_size | |
236 | ||
237 | self.column_def_line_size = self.parent.column_def_line_size | |
238 | self.column_def_line_colour = self.parent.column_def_line_colour | |
239 | ||
240 | self.text_font = self.parent.text_font | |
241 | ||
242 | self.label_font = self.parent.label_font | |
243 | ||
244 | def AdjustValues(self): | |
245 | self.vertical_offset = self.pheight * self.parent.vertical_offset | |
246 | self.horizontal_offset = self.pheight * self.parent.horizontal_offset | |
247 | ||
248 | self.pcell_left_margin = self.pwidth * self.cell_left_margin | |
249 | self.pcell_right_margin = self.pwidth * self.cell_right_margin | |
250 | self.ptop_margin = self.pheight * self.top_margin | |
251 | self.pbottom_margin = self.pheight * self.bottom_margin | |
252 | ||
253 | self.pheader_margin = self.pheight * self.parent.header_margin | |
254 | self.pfooter_margin = self.pheight * self.parent.footer_margin | |
255 | ||
256 | self.cell_colour = self.parent.set_cell_colour | |
257 | self.cell_text = self.parent.set_cell_text | |
258 | ||
259 | self.column = [] | |
260 | self.column_align = [] | |
261 | self.column_bgcolour = [] | |
262 | self.column_txtcolour = [] | |
263 | ||
264 | set_column_align = self.parent.set_column_align | |
265 | set_column_bgcolour = self.parent.set_column_bgcolour | |
266 | set_column_txtcolour = self.parent.set_column_txtcolour | |
267 | ||
268 | pos_x = self.left_margin * self.pwidth + self.horizontal_offset # left margin | |
269 | self.column.append(pos_x) | |
270 | ||
271 | if self.set_column == []: | |
272 | table_width = self.page_width - self.left_margin - self.right_margin | |
273 | width = table_width/(len(self.label)) | |
274 | for val in self.label: | |
275 | column_width = width * self.pwidth | |
276 | pos_x = pos_x + column_width | |
277 | self.column.append(pos_x) # position of each column | |
278 | else: | |
279 | for val in self.set_column: | |
280 | column_width = val * self.pwidth | |
281 | pos_x = pos_x + column_width | |
282 | self.column.append(pos_x) # position of each column | |
283 | ||
284 | if pos_x > self.page_width * self.pwidth: # check if it fits in page | |
285 | print "Warning, Too Wide for Page" | |
286 | return | |
287 | ||
288 | if self.label != []: | |
289 | if len(self.column) -1 != len(self.label): | |
290 | print "Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label) | |
291 | return | |
292 | ||
293 | first_value = self.data[0] | |
294 | column_total = len(first_value) | |
295 | if column_total != len(self.column) -1: | |
296 | print "Column Settings Incorrect", first_value, self.column | |
297 | return | |
298 | ||
299 | col = 0 | |
300 | for col in range(column_total): | |
301 | try: | |
302 | align = set_column_align[col] # check if custom column alignment | |
303 | except: | |
304 | align = wx.ALIGN_LEFT | |
305 | self.column_align.append(align) | |
306 | ||
307 | try: | |
308 | colour = set_column_bgcolour[col] # check if custom column background colour | |
309 | except: | |
310 | colour = self.parent.column_colour | |
311 | self.column_bgcolour.append(colour) | |
312 | ||
313 | try: | |
314 | colour = set_column_txtcolour[col] # check if custom column text colour | |
315 | except: | |
316 | colour = self.GetFontColour(self.parent.text_font) | |
317 | ||
318 | self.column_txtcolour.append(colour) | |
319 | ||
320 | col = col + 1 | |
321 | ||
322 | def SetPointAdjust(self): | |
323 | f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL) # setup using 10 point | |
324 | self.DC.SetFont(f) | |
325 | f.SetFaceName(self.text_font["Name"]) | |
326 | x, y = self.DC.GetTextExtent("W") | |
327 | ||
328 | self.label_pt_space_before = self.parent.label_pt_adj_before * y/10 # extra spacing for label per point value | |
329 | self.label_pt_space_after = self.parent.label_pt_adj_after * y/10 | |
330 | ||
331 | self.text_pt_space_before = self.parent.text_pt_adj_before * y/10 # extra spacing for row text per point value | |
332 | self.text_pt_space_after = self.parent.text_pt_adj_after * y/10 | |
333 | ||
334 | def SetPage(self, page): | |
335 | self.page = page | |
336 | ||
337 | def SetColumns(self, col): | |
338 | self.column = col | |
339 | ||
340 | def OutCanvas(self): | |
341 | self.AdjustValues() | |
342 | self.SetPointAdjust() | |
343 | ||
344 | self.y_start = self.ptop_margin + self.vertical_offset | |
345 | self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset | |
346 | ||
347 | self.SetPrintFont(self.label_font) | |
348 | ||
349 | x, y = self.DC.GetTextExtent("W") | |
350 | self.label_space = y | |
351 | ||
352 | self.SetPrintFont(self.text_font) | |
353 | ||
354 | x, y = self.DC.GetTextExtent("W") | |
355 | self.space = y | |
356 | ||
357 | if self.total_pages is None: | |
358 | self.GetTotalPages() # total pages for display/printing | |
359 | ||
360 | self.data_cnt = self.page_index[self.page-1] | |
361 | ||
362 | self.draw = True | |
363 | self.PrintHeader() | |
364 | self.PrintFooter() | |
365 | self.OutPage() | |
366 | ||
367 | def GetTotalPages(self): | |
368 | self.data_cnt = 0 | |
369 | self.draw = False | |
370 | self.page_index = [0] | |
371 | ||
372 | cnt = 0 | |
373 | while 1: | |
374 | test = self.OutPage() | |
375 | self.page_index.append(self.data_cnt) | |
376 | if test == False: | |
377 | break | |
378 | cnt = cnt + 1 | |
379 | ||
380 | self.total_pages = cnt + 1 | |
381 | ||
382 | def OutPage(self): | |
383 | self.y = self.y_start | |
384 | self.end_x = self.column[-1] | |
385 | ||
386 | if self.data_cnt < len(self.data): # if there data for display on the page | |
387 | if self.label != []: # check if header defined | |
388 | self.PrintLabel() | |
389 | else: | |
390 | return False | |
391 | ||
392 | for val in self.data: | |
393 | try: | |
394 | row_val = self.data[self.data_cnt] | |
395 | except: | |
396 | self.FinishDraw() | |
397 | return False | |
398 | ||
399 | max_y = self.PrintRow(row_val, False) # test to see if row will fit in remaining space | |
400 | test = max_y + self.space | |
401 | ||
402 | if test > self.y_end: | |
403 | break | |
404 | ||
405 | self.ColourRowCells(max_y-self.y+self.space) # colour the row/column | |
406 | max_y = self.PrintRow(row_val, True) # row fits - print text | |
407 | self.DrawGridLine() # top line of cell | |
408 | self.y = max_y + self.space | |
409 | ||
410 | if self.y > self.y_end: | |
411 | break | |
412 | ||
413 | self.data_cnt = self.data_cnt + 1 | |
414 | ||
415 | self.FinishDraw() | |
416 | ||
417 | if self.data_cnt == len(self.data): # last value in list | |
418 | return False | |
419 | ||
420 | return True | |
421 | ||
422 | ||
423 | def PrintLabel(self): | |
424 | self.pt_space_before = self.label_pt_space_before # set the point spacing | |
425 | self.pt_space_after = self.label_pt_space_after | |
426 | ||
427 | self.LabelColorRow(self.label_colour) | |
428 | self.SetPrintFont(self.label_font) | |
429 | ||
430 | self.col = 0 | |
431 | max_y = 0 | |
432 | for vtxt in self.label: | |
433 | self.region = self.column[self.col+1] - self.column[self.col] | |
434 | self.indent = self.column[self.col] | |
435 | ||
436 | self.align = wx.ALIGN_LEFT | |
437 | ||
438 | max_out = self.OutTextRegion(vtxt, True) | |
439 | if max_out > max_y: | |
440 | max_y = max_out | |
441 | self.col = self.col + 1 | |
442 | ||
443 | self.DrawGridLine() # top line of label | |
444 | self.y = max_y + self.label_space | |
445 | ||
446 | def PrintHeader(self): # print the header array | |
447 | if self.draw == False: | |
448 | return | |
449 | ||
450 | for val in self.parent.header: | |
451 | self.SetPrintFont(val["Font"]) | |
452 | ||
453 | header_indent = val["Indent"] * self.pwidth | |
454 | text = val["Text"] | |
455 | ||
456 | htype = val["Type"] | |
457 | if htype == "Date": | |
458 | addtext = self.GetDate() | |
459 | elif htype == "Date & Time": | |
460 | addtext = self.GetDateTime() | |
461 | else: | |
462 | addtext = "" | |
463 | ||
464 | self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True) | |
465 | ||
466 | def PrintFooter(self): # print the header array | |
467 | if self.draw == False: | |
468 | return | |
469 | ||
470 | footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset | |
471 | for val in self.parent.footer: | |
472 | self.SetPrintFont(val["Font"]) | |
473 | ||
474 | footer_indent = val["Indent"] * self.pwidth | |
475 | text = val["Text"] | |
476 | ||
477 | ftype = val["Type"] | |
478 | if ftype == "Pageof": | |
479 | addtext = "Page " + str(self.page) + " of " + str(self.total_pages) | |
480 | elif ftype == "Page": | |
481 | addtext = "Page " + str(self.page) | |
482 | elif ftype == "Num": | |
483 | addtext = str(self.page) | |
484 | elif ftype == "Date": | |
485 | addtext = self.GetDate() | |
486 | elif ftype == "Date & Time": | |
487 | addtext = self.GetDateTime() | |
488 | else: | |
489 | addtext = "" | |
490 | ||
491 | self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True) | |
492 | ||
493 | ||
494 | def LabelColorRow(self, colour): | |
495 | brush = wx.Brush(colour, wx.SOLID) | |
496 | self.DC.SetBrush(brush) | |
497 | height = self.label_space + self.label_pt_space_before + self.label_pt_space_after | |
498 | self.DC.DrawRectangle(self.column[0], self.y, | |
499 | self.end_x-self.column[0]+1, height) | |
500 | ||
501 | def ColourRowCells(self, height): | |
502 | if self.draw == False: | |
503 | return | |
504 | ||
505 | col = 0 | |
506 | for colour in self.column_bgcolour: | |
507 | cellcolour = self.GetCellColour(self.data_cnt, col) | |
508 | if cellcolour is not None: | |
509 | colour = cellcolour | |
510 | ||
511 | brush = wx.Brush(colour, wx.SOLID) | |
512 | self.DC.SetBrush(brush) | |
513 | self.DC.SetPen(wx.Pen(wx.NamedColour('WHITE'), 0)) | |
514 | ||
515 | start_x = self.column[col] | |
516 | width = self.column[col+1] - start_x + 2 | |
517 | self.DC.DrawRectangle(start_x, self.y, width, height) | |
518 | col = col + 1 | |
519 | ||
520 | def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT): | |
521 | self.SetPrintFont(self.text_font) | |
522 | ||
523 | self.pt_space_before = self.text_pt_space_before # set the point spacing | |
524 | self.pt_space_after = self.text_pt_space_after | |
525 | ||
526 | self.col = 0 | |
527 | max_y = 0 | |
528 | for vtxt in row_val: | |
529 | self.region = self.column[self.col+1] - self.column[self.col] | |
530 | self.indent = self.column[self.col] | |
531 | self.align = self.column_align[self.col] | |
532 | ||
533 | fcolour = self.column_txtcolour[self.col] # set font colour | |
534 | celltext = self.GetCellText(self.data_cnt, self.col) | |
535 | if celltext is not None: | |
536 | fcolour = celltext # override the column colour | |
537 | ||
538 | self.DC.SetTextForeground(fcolour) | |
539 | ||
540 | max_out = self.OutTextRegion(vtxt, draw) | |
541 | if max_out > max_y: | |
542 | max_y = max_out | |
543 | self.col = self.col + 1 | |
544 | return max_y | |
545 | ||
546 | def GetCellColour(self, row, col): # check if custom colour defined for the cell background | |
547 | try: | |
548 | set = self.cell_colour[row] | |
549 | except: | |
550 | return None | |
551 | try: | |
552 | colour = set[col] | |
553 | return colour | |
554 | except: | |
555 | return None | |
556 | ||
557 | def GetCellText(self, row, col): # check if custom colour defined for the cell text | |
558 | try: | |
559 | set = self.cell_text[row] | |
560 | except: | |
561 | return None | |
562 | try: | |
563 | colour = set[col] | |
564 | return colour | |
565 | except: | |
566 | return None | |
567 | ||
568 | def FinishDraw(self): | |
569 | self.DrawGridLine() # draw last row line | |
570 | self.DrawColumns() # draw all vertical lines | |
571 | ||
572 | def DrawGridLine(self): | |
573 | if self.draw == True: | |
574 | try: | |
575 | size = self.row_line_size[self.data_cnt] | |
576 | except: | |
577 | size = self.row_def_line_size | |
578 | ||
579 | try: | |
580 | colour = self.row_line_colour[self.data_cnt] | |
581 | except: | |
582 | colour = self.row_def_line_colour | |
583 | ||
584 | self.DC.SetPen(wx.Pen(colour, size)) | |
585 | ||
586 | y_out = self.y | |
587 | # y_out = self.y + self.pt_space_before + self.pt_space_after # adjust for extra spacing | |
588 | self.DC.DrawLine(self.column[0], y_out, self.end_x, y_out) | |
589 | ||
590 | def DrawColumns(self): | |
591 | if self.draw == True: | |
592 | col = 0 | |
593 | for val in self.column: | |
594 | try: | |
595 | size = self.column_line_size[col] | |
596 | except: | |
597 | size = self.column_def_line_size | |
598 | ||
599 | try: | |
600 | colour = self.column_line_colour[col] | |
601 | except: | |
602 | colour = self.column_def_line_colour | |
603 | ||
604 | indent = val | |
605 | ||
606 | self.DC.SetPen(wx.Pen(colour, size)) | |
607 | self.DC.DrawLine(indent, self.y_start, indent, self.y) | |
608 | col = col + 1 | |
609 | ||
610 | def DrawText(self): | |
611 | self.DoRefresh() | |
612 | ||
613 | def DoDrawing(self, DC): | |
614 | size = DC.GetSize() | |
615 | self.DC = DC | |
616 | ||
617 | DC.BeginDrawing() | |
618 | self.DrawText() | |
619 | DC.EndDrawing() | |
620 | ||
621 | self.sizew = DC.MaxY() | |
622 | self.sizeh = DC.MaxX() | |
623 | ||
624 | ||
625 | class PrintTable: | |
626 | def __init__(self, parentFrame=None): | |
627 | self.data = [] | |
628 | self.set_column = [] | |
629 | self.label = [] | |
630 | self.header = [] | |
631 | self.footer = [] | |
632 | ||
633 | self.set_column_align = {} | |
634 | self.set_column_bgcolour = {} | |
635 | self.set_column_txtcolour = {} | |
636 | self.set_cell_colour = {} | |
637 | self.set_cell_text = {} | |
638 | self.column_line_size = {} | |
639 | self.column_line_colour = {} | |
640 | self.row_line_size = {} | |
641 | self.row_line_colour = {} | |
642 | ||
643 | self.parentFrame = parentFrame | |
644 | self.SetPreviewSize() | |
645 | ||
646 | self.printData = wx.PrintData() | |
647 | self.scale = 1.0 | |
648 | ||
649 | self.SetParms() | |
650 | self.SetColors() | |
651 | self.SetFonts() | |
652 | self.TextSpacing() | |
653 | ||
654 | self.SetPrinterOffset() | |
655 | self.SetHeaderValue() | |
656 | self.SetFooterValue() | |
657 | self.SetMargins() | |
658 | self.SetPortrait() | |
659 | ||
660 | def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"): | |
661 | if size == "Full": | |
662 | r = wx.GetClientDisplayRect() | |
663 | self.preview_frame_size = r.GetSize() | |
664 | self.preview_frame_pos = r.GetPosition() | |
665 | else: | |
666 | self.preview_frame_size = size | |
667 | self.preview_frame_pos = position | |
668 | ||
669 | def SetPaperId(self, paper): | |
670 | self.printData.SetPaperId(paper) | |
671 | ||
672 | def SetOrientation(self, orient): | |
673 | self.printData.SetOrientation(orient) | |
674 | ||
675 | def SetColors(self): | |
676 | self.row_def_line_colour = wx.NamedColour('BLACK') | |
677 | self.row_def_line_size = 1 | |
678 | ||
679 | self.column_def_line_colour = wx.NamedColour('BLACK') | |
680 | self.column_def_line_size = 1 | |
681 | self.column_colour = wx.NamedColour('WHITE') | |
682 | ||
683 | self.label_colour = wx.NamedColour('LIGHT GREY') | |
684 | ||
685 | def SetFonts(self): | |
686 | self.label_font = { "Name": self.default_font_name, "Size": 12, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } | |
687 | self.text_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } | |
688 | ||
689 | def TextSpacing(self): | |
690 | self.label_pt_adj_before = 0 # point adjustment before and after the label text | |
691 | self.label_pt_adj_after = 0 | |
692 | ||
693 | self.text_pt_adj_before = 0 # point adjustment before and after the row text | |
694 | self.text_pt_adj_after = 0 | |
695 | ||
696 | def SetLabelSpacing(self, before, after): # method to set the label space adjustment | |
697 | self.label_pt_adj_before = before | |
698 | self.label_pt_adj_after = after | |
699 | ||
700 | def SetRowSpacing(self, before, after): # method to set the row space adjustment | |
701 | self.text_pt_adj_before = before | |
702 | self.text_pt_adj_after = after | |
703 | ||
704 | def SetPrinterOffset(self): # offset to adjust for printer | |
705 | self.vertical_offset = -0.1 | |
706 | self.horizontal_offset = -0.1 | |
707 | ||
708 | def SetHeaderValue(self): | |
709 | self.header_margin = 0.25 | |
710 | self.header_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } | |
711 | self.header_align = wx.ALIGN_CENTRE | |
712 | self.header_indent = 0 | |
713 | self.header_type = "Text" | |
714 | ||
715 | def SetFooterValue(self): | |
716 | self.footer_margin = 0.7 | |
717 | self.footer_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } | |
718 | self.footer_align = wx.ALIGN_CENTRE | |
719 | self.footer_indent = 0 | |
720 | self.footer_type = "Pageof" | |
721 | ||
722 | def SetMargins(self): | |
723 | self.left_margin = 1.0 | |
724 | self.right_margin = 1.0 # only used if no column sizes | |
725 | ||
726 | self.top_margin = 0.8 | |
727 | self.bottom_margin = 1.0 | |
728 | self.cell_left_margin = 0.1 | |
729 | self.cell_right_margin = 0.1 | |
730 | ||
731 | def SetPortrait(self): | |
732 | self.printData.SetPaperId(wx.PAPER_LETTER) | |
733 | self.printData.SetOrientation(wx.PORTRAIT) | |
734 | self.page_width = 8.5 | |
735 | self.page_height = 11.0 | |
736 | ||
737 | def SetLandscape(self): | |
738 | self.printData.SetOrientation(wx.LANDSCAPE) | |
739 | self.page_width = 11.0 | |
740 | self.page_height = 8.5 | |
741 | ||
742 | def SetParms(self): | |
743 | self.ymax = 1 | |
744 | self.xmax = 1 | |
745 | self.page = 1 | |
746 | self.total_pg = 100 | |
747 | ||
748 | self.preview = None | |
749 | self.page = 0 | |
750 | ||
751 | self.default_font_name = "Arial" | |
752 | self.default_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] } | |
753 | ||
754 | def SetColAlignment(self, col, align=wx.ALIGN_LEFT): | |
755 | self.set_column_align[col] = align | |
756 | ||
757 | def SetColBackgroundColour(self, col, colour): | |
758 | self.set_column_bgcolour[col] = colour | |
759 | ||
760 | def SetColTextColour(self, col, colour): | |
761 | self.set_column_txtcolour[col] = colour | |
762 | ||
763 | def SetCellColour(self, row, col, colour): # cell background colour | |
764 | try: | |
765 | set = self.set_cell_colour[row] # test if row already exists | |
766 | try: | |
767 | set[col] = colour # test if column already exists | |
768 | except: | |
769 | set = { col: colour } # create the column value | |
770 | except: | |
771 | set = { col: colour } # create the column value | |
772 | ||
773 | self.set_cell_colour[row] = set # create dictionary item for colour settings | |
774 | ||
775 | def SetCellText(self, row, col, colour): # font colour for custom cells | |
776 | try: | |
777 | set = self.set_cell_text[row] # test if row already exists | |
778 | try: | |
779 | set[col] = colour # test if column already exists | |
780 | except: | |
781 | set = { col: colour } # create the column value | |
782 | except: | |
783 | set = { col: colour } # create the column value | |
784 | ||
785 | self.set_cell_text[row] = set # create dictionary item for colour settings | |
786 | ||
787 | def SetColumnLineSize(self, col, size): # column line size | |
788 | self.column_line_size[col] = size # create dictionary item for column line settings | |
789 | ||
790 | def SetColumnLineColour(self, col, colour): | |
791 | self.column_line_colour[col] = colour | |
792 | ||
793 | def SetRowLineSize(self, row, size): | |
794 | self.row_line_size[row] = size | |
795 | ||
796 | def SetRowLineColour(self, row, colour): | |
797 | self.row_line_colour[row] = colour | |
798 | ||
799 | def GetColour(self, colour): # returns colours based from wxColour value | |
800 | red = colour.Red() | |
801 | blue = colour.Blue() | |
802 | green = colour.Green() | |
803 | return [red, green, blue ] | |
804 | ||
805 | def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None): | |
806 | set = { "Text": text } | |
807 | ||
808 | if font is None: | |
809 | set["Font"] = copy.copy(self.default_font) | |
810 | else: | |
811 | set["Font"] = font | |
812 | ||
813 | if colour is not None: | |
814 | setfont = set["Font"] | |
815 | setfont["Colour"] = self.GetColour(colour) | |
816 | ||
817 | if size is not None: | |
818 | setfont = set["Font"] | |
819 | setfont["Size"] = size | |
820 | ||
821 | if align is None: | |
822 | set["Align"] = self.header_align | |
823 | else: | |
824 | set["Align"] = align | |
825 | ||
826 | if indent is None: | |
827 | set["Indent"] = self.header_indent | |
828 | else: | |
829 | set["Indent"] = indent | |
830 | ||
831 | if type is None: | |
832 | set["Type"] = self.header_type | |
833 | else: | |
834 | set["Type"] = type | |
835 | ||
836 | self.header.append(set) | |
837 | ||
838 | def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None): | |
839 | set = { "Text": text } | |
840 | ||
841 | if font is None: | |
842 | set["Font"] = copy.copy(self.default_font) | |
843 | else: | |
844 | set["Font"] = font | |
845 | ||
846 | if colour is not None: | |
847 | setfont = set["Font"] | |
848 | setfont["Colour"] = self.GetColour(colour) | |
849 | ||
850 | if size is not None: | |
851 | setfont = set["Font"] | |
852 | setfont["Size"] = size | |
853 | ||
854 | if align is None: | |
855 | set["Align"] = self.footer_align | |
856 | else: | |
857 | set["Align"] = align | |
858 | ||
859 | if indent is None: | |
860 | set["Indent"] = self.footer_indent | |
861 | else: | |
862 | set["Indent"] = indent | |
863 | ||
864 | if type is None: | |
865 | set["Type"] = self.footer_type | |
866 | else: | |
867 | set["Type"] = type | |
868 | ||
869 | self.footer.append(set) | |
870 | ||
871 | def Preview(self): | |
872 | printout = SetPrintout(self) | |
873 | printout2 = SetPrintout(self) | |
874 | self.preview = wx.PrintPreview(printout, printout2, self.printData) | |
875 | if not self.preview.Ok(): | |
876 | wxMessageBox("There was a problem printing!", "Printing", wx.OK) | |
877 | return | |
878 | ||
879 | self.preview.SetZoom(60) # initial zoom value | |
880 | ||
881 | frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview") | |
882 | ||
883 | frame.Initialize() | |
884 | if self.parentFrame: | |
885 | frame.SetPosition(self.preview_frame_pos) | |
886 | frame.SetSize(self.preview_frame_size) | |
887 | frame.Show(True) | |
888 | ||
889 | def Print(self): | |
890 | pdd = wx.PrintDialogData() | |
891 | pdd.SetPrintData(self.printData) | |
892 | printer = wx.Printer(pdd) | |
893 | printout = SetPrintout(self) | |
894 | if not printer.Print(self.parentFrame, printout): | |
895 | wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK) | |
896 | else: | |
897 | self.printData = printer.GetPrintDialogData().GetPrintData() | |
898 | printout.Destroy() | |
899 | ||
900 | def DoDrawing(self, DC): | |
901 | size = DC.GetSize() | |
902 | DC.BeginDrawing() | |
903 | ||
904 | table = PrintTableDraw(self, DC, size) | |
905 | table.data = self.data | |
906 | table.set_column = self.set_column | |
907 | table.label = self.label | |
908 | table.SetPage(self.page) | |
909 | ||
910 | if self.preview is None: | |
911 | table.SetPSize(size[0]/self.page_width, size[1]/self.page_height) | |
912 | table.SetPTSize(size[0], size[1]) | |
913 | table.SetPreview(False) | |
914 | else: | |
915 | if self.preview == 1: | |
916 | table.scale = self.scale | |
917 | table.SetPSize(size[0]/self.page_width, size[1]/self.page_height) | |
918 | else: | |
919 | table.SetPSize(self.pwidth, self.pheight) | |
920 | ||
921 | table.SetPTSize(self.ptwidth, self.ptheight) | |
922 | table.SetPreview(self.preview) | |
923 | ||
924 | table.OutCanvas() | |
925 | self.page_total = table.total_pages # total display pages | |
926 | ||
927 | DC.EndDrawing() | |
928 | ||
929 | self.ymax = DC.MaxY() | |
930 | self.xmax = DC.MaxX() | |
931 | ||
932 | self.sizeh = size[0] | |
933 | self.sizew = size[1] | |
934 | ||
935 | def GetTotalPages(self): | |
936 | self.page_total = 100 | |
937 | return self.page_total | |
938 | ||
939 | def HasPage(self, page): | |
940 | if page <= self.page_total: | |
941 | return True | |
942 | else: | |
943 | return False | |
944 | ||
945 | def SetPage(self, page): | |
946 | self.page = page | |
947 | ||
948 | def SetPageSize(self, width, height): | |
949 | self.pwidth, self.pheight = width, height | |
950 | ||
951 | def SetTotalSize(self, width, height): | |
952 | self.ptwidth, self.ptheight = width, height | |
953 | ||
954 | def SetPreview(self, preview, scale): | |
955 | self.preview = preview | |
956 | self.scale = scale | |
957 | ||
958 | def SetTotalSize(self, width, height): | |
959 | self.ptwidth = width | |
960 | self.ptheight = height | |
961 | ||
962 | class PrintGrid: | |
963 | def __init__(self, parent, grid, format = [], total_col = None, total_row = None): | |
964 | if total_row is None: | |
965 | total_row = grid.GetNumberRows() | |
966 | if total_col is None: | |
967 | total_col = grid.GetNumberCols() | |
968 | ||
969 | self.total_row = total_row | |
970 | self.total_col = total_col | |
971 | self.grid = grid | |
972 | ||
973 | data = [] | |
974 | for row in range(total_row): | |
975 | row_val = [] | |
976 | value = grid.GetRowLabelValue(row) | |
977 | row_val.append(value) | |
978 | ||
979 | for col in range(total_col): | |
980 | value = grid.GetCellValue(row, col) | |
981 | row_val.append(value) | |
982 | data.append(row_val) | |
983 | ||
984 | label = [""] | |
985 | for col in range(total_col): | |
986 | value = grid.GetColLabelValue(col) | |
987 | label.append(value) | |
988 | ||
989 | self.table = PrintTable(parent) | |
990 | self.table.cell_left_margin = 0.0 | |
991 | self.table.cell_right_margin = 0.0 | |
992 | ||
993 | self.table.label = label | |
994 | self.table.set_column = format | |
995 | self.table.data = data | |
996 | ||
997 | def GetTable(self): | |
998 | return self.table | |
999 | ||
1000 | def SetAttributes(self): | |
1001 | for row in range(self.total_row): | |
1002 | for col in range(self.total_col): | |
1003 | colour = self.grid.GetCellTextColour(row, col-1) | |
1004 | self.table.SetCellText(row, col, colour) | |
1005 | ||
1006 | colour = self.grid.GetCellBackgroundColour(row, col-1) | |
1007 | self.table.SetCellColour(row, col, colour) | |
1008 | ||
1009 | def Preview(self): | |
1010 | self.table.Preview() | |
1011 | ||
1012 | def Print(self): | |
1013 | self.table.Print() | |
1014 | ||
1015 | ||
1016 | class SetPrintout(wx.Printout): | |
1017 | def __init__(self, canvas): | |
1018 | wx.Printout.__init__(self) | |
1019 | self.canvas = canvas | |
1020 | self.end_pg = 1000 | |
1021 | ||
1022 | def OnBeginDocument(self, start, end): | |
1023 | return self.base_OnBeginDocument(start, end) | |
1024 | ||
1025 | def OnEndDocument(self): | |
1026 | self.base_OnEndDocument() | |
1027 | ||
1028 | def HasPage(self, page): | |
1029 | try: | |
1030 | end = self.canvas.HasPage(page) | |
1031 | return end | |
1032 | except: | |
1033 | return True | |
1034 | ||
1035 | def GetPageInfo(self): | |
1036 | try: | |
1037 | self.end_pg = self.canvas.GetTotalPages() | |
1038 | except: | |
1039 | pass | |
1040 | ||
1041 | end_pg = self.end_pg | |
1042 | str_pg = 1 | |
1043 | return (str_pg, end_pg, str_pg, end_pg) | |
1044 | ||
1045 | def OnPreparePrinting(self): | |
1046 | self.base_OnPreparePrinting() | |
1047 | ||
1048 | def OnBeginPrinting(self): | |
1049 | dc = self.GetDC() | |
1050 | ||
1051 | self.preview = self.IsPreview() | |
1052 | if (self.preview): | |
1053 | self.pixelsPerInch = self.GetPPIScreen() | |
1054 | else: | |
1055 | self.pixelsPerInch = self.GetPPIPrinter() | |
1056 | ||
1057 | (w, h) = dc.GetSize() | |
1058 | scaleX = float(w) / 1000 | |
1059 | scaleY = float(h) / 1000 | |
1060 | self.printUserScale = min(scaleX, scaleY) | |
1061 | ||
1062 | self.base_OnBeginPrinting() | |
1063 | ||
1064 | def GetSize(self): | |
1065 | self.psizew, self.psizeh = self.GetPPIPrinter() | |
1066 | return self.psizew, self.psizeh | |
1067 | ||
1068 | def GetTotalSize(self): | |
1069 | self.ptsizew, self.ptsizeh = self.GetPageSizePixels() | |
1070 | return self.ptsizew, self.ptsizeh | |
1071 | ||
1072 | def OnPrintPage(self, page): | |
1073 | dc = self.GetDC() | |
1074 | (w, h) = dc.GetSize() | |
1075 | scaleX = float(w) / 1000 | |
1076 | scaleY = float(h) / 1000 | |
1077 | self.printUserScale = min(scaleX, scaleY) | |
1078 | dc.SetUserScale(self.printUserScale, self.printUserScale) | |
1079 | ||
1080 | self.preview = self.IsPreview() | |
1081 | ||
1082 | self.canvas.SetPreview(self.preview, self.printUserScale) | |
1083 | self.canvas.SetPage(page) | |
1084 | ||
1085 | self.ptsizew, self.ptsizeh = self.GetPageSizePixels() | |
1086 | self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh) | |
1087 | ||
1088 | self.psizew, self.psizeh = self.GetPPIPrinter() | |
1089 | self.canvas.SetPageSize(self.psizew, self.psizeh) | |
1090 | ||
1091 | self.canvas.DoDrawing(dc) | |
1092 | return True | |
1093 | ||
1094 | ||
1095 | ||
1096 | ||
1097 | ||
1098 |