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