~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/wx/lib/printout.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

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