git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@40852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			1154 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1154 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #----------------------------------------------------------------------------
 | |
| # Name:         printout.py
 | |
| # Purpose:      preview and printing class -> table/grid printing
 | |
| #
 | |
| # Author:       Lorne White (email: lorne.white@telusplanet.net)
 | |
| #
 | |
| # Created:
 | |
| # Version       0.75
 | |
| # Date:         May 15, 2002
 | |
| # Licence:      wxWindows license
 | |
| #----------------------------------------------------------------------------
 | |
| # Release Notes
 | |
| 
 | |
| # fixed bug for string wider than print region
 | |
| # add index to data list after parsing total pages for paging
 | |
| #----------------------------------------------------------------------------
 | |
| # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net)
 | |
| # o 2.5 compatability update.
 | |
| #----------------------------------------------------------------------------
 | |
| # 11/23/2004 - Vernon Cole (wnvcole@peppermillcas.com)
 | |
| # o Generalize for non-2-dimensional sequences and non-text data
 | |
| #   (can use as a simple text printer by supplying a list of strings.)
 | |
| # o Add a small _main_ for self test
 | |
|  
 | |
| import  copy
 | |
| import  types
 | |
| import  wx
 | |
| 
 | |
| class PrintBase:
 | |
|     def SetPrintFont(self, font):      # set the DC font parameters
 | |
|         fattr = font["Attr"]
 | |
|         if fattr[0] == 1:
 | |
|             weight = wx.BOLD
 | |
|         else:
 | |
|             weight = wx.NORMAL
 | |
| 
 | |
|         if fattr[1] == 1:
 | |
|             set_style = wx.ITALIC
 | |
|         else:
 | |
|             set_style = wx.NORMAL
 | |
| 
 | |
|         underline = fattr[2]
 | |
|         fcolour = self.GetFontColour(font)
 | |
|         self.DC.SetTextForeground(fcolour)
 | |
| 
 | |
|         setfont = wx.Font(font["Size"], wx.SWISS, set_style, weight, underline)
 | |
|         setfont.SetFaceName(font["Name"])
 | |
|         self.DC.SetFont(setfont)
 | |
| 
 | |
|     def GetFontColour(self, font):
 | |
|         fcolour = font["Colour"]
 | |
|         return wx.Colour(fcolour[0], fcolour[1], fcolour[2])
 | |
| 
 | |
|     def OutTextRegion(self, textout, txtdraw = True):
 | |
|         textlines = textout.split('\n')
 | |
|         y = copy.copy(self.y) + self.pt_space_before
 | |
|         for text in textlines:
 | |
|             remain = 'X'
 | |
|             while remain != "":
 | |
|                 vout, remain = self.SetFlow(text, self.region)
 | |
|                 if self.draw == True and txtdraw == True:
 | |
|                     test_out = self.TestFull(vout)
 | |
|                     if self.align == wx.ALIGN_LEFT:
 | |
|                         self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y)
 | |
| 
 | |
|                     elif self.align == wx.ALIGN_CENTRE:
 | |
|                         diff = self.GetCellDiff(test_out, self.region)
 | |
|                         self.DC.DrawText(test_out, self.indent+diff/2, y)
 | |
| 
 | |
|                     elif self.align == wx.ALIGN_RIGHT:
 | |
|                         diff = self.GetCellDiff(test_out, self.region)
 | |
|                         self.DC.DrawText(test_out, self.indent+diff, y)
 | |
| 
 | |
|                     else:
 | |
|                         self.DC.DrawText(test_out, self.indent+self.pcell_left_margin, y)
 | |
|                 text = remain
 | |
|                 y = y + self.space
 | |
|         return y - self.space + self.pt_space_after
 | |
| 
 | |
|     def GetCellDiff(self, text, width):      # get the remaining cell size for adjustment
 | |
|         w, h = self.DC.GetTextExtent(text)
 | |
|         diff = width - w
 | |
|         if diff < 0:
 | |
|             diff = 0
 | |
|         return diff
 | |
| 
 | |
|     def TestFull(self, text_test):
 | |
|         w, h = self.DC.GetTextExtent(text_test)
 | |
|         if w > self.region:     # trouble fitting into cell
 | |
|             return self.SetChar(text_test, self.region)     # fit the text to the cell size
 | |
|         else:
 | |
|             return text_test
 | |
| 
 | |
|     def SetFlow(self, ln_text, width):
 | |
|         width = width - self.pcell_right_margin
 | |
|         text = ""
 | |
|         split = ln_text.split()
 | |
|         if len(split) == 1:
 | |
|             return ln_text, ""
 | |
| 
 | |
|         try:
 | |
|             w, h = self.DC.GetTextExtent(" " + split[0])
 | |
|             if w >= width:
 | |
|                 return ln_text, ""
 | |
|         except:
 | |
|             pass
 | |
| 
 | |
|         cnt = 0
 | |
|         for word in split:
 | |
|             bword = " " + word  # blank + word
 | |
|             length = len(bword)
 | |
| 
 | |
|             w, h = self.DC.GetTextExtent(text + bword)
 | |
|             if w < width:
 | |
|                 text = text + bword
 | |
|                 cnt = cnt + 1
 | |
|             else:
 | |
|                 remain = ' '.join(split[cnt:])
 | |
|                 text = text.strip()
 | |
|                 return text, remain
 | |
| 
 | |
|         remain = ' '.join(split[cnt:])
 | |
|         vout = text.strip()
 | |
|         return vout, remain
 | |
| 
 | |
|     def SetChar(self, ln_text, width):  # truncate string to fit into width
 | |
|         width = width - self.pcell_right_margin - self.pcell_left_margin
 | |
|         text = ""
 | |
|         for val in ln_text:
 | |
|             w, h = self.DC.GetTextExtent(text + val)
 | |
|             if w > width:
 | |
|                 text = text + ".."
 | |
|                 return text     # fitted text value
 | |
|             text = text + val
 | |
|         return text
 | |
| 
 | |
|     def OutTextPageWidth(self, textout, y_out, align, indent, txtdraw = True):
 | |
|         textlines = textout.split('\n')
 | |
|         y = copy.copy(y_out)
 | |
| 
 | |
|         pagew = self.parent.page_width * self.pwidth        # full page width
 | |
|         w, h = self.DC.GetTextExtent(textout)
 | |
|         y_line = h
 | |
| 
 | |
|         for text in textlines:
 | |
|             remain = 'X'
 | |
|             while remain != "":
 | |
|                 vout, remain = self.SetFlow(text, pagew)
 | |
|                 if self.draw == True and txtdraw == True:
 | |
|                     test_out = vout
 | |
|                     if align == wx.ALIGN_LEFT:
 | |
|                         self.DC.DrawText(test_out, indent, y)
 | |
| 
 | |
|                     elif align == wx.ALIGN_CENTRE:
 | |
|                         diff = self.GetCellDiff(test_out, pagew)
 | |
|                         self.DC.DrawText(test_out, indent+diff/2, y)
 | |
| 
 | |
|                     elif align == wx.ALIGN_RIGHT:
 | |
|                         diff = self.GetCellDiff(test_out, pagew)
 | |
|                         self.DC.DrawText(test_out, indent+diff, y)
 | |
| 
 | |
|                     else:
 | |
|                         self.DC.DrawText(test_out, indent, y_out)
 | |
|                 text = remain
 | |
|                 y = y + y_line
 | |
|         return y - y_line
 | |
| 
 | |
|     def GetDate(self):
 | |
|         date, time = self.GetNow()
 | |
|         return date
 | |
| 
 | |
|     def GetDateTime(self):
 | |
|         date, time = self.GetNow()
 | |
|         return date + ' ' + time
 | |
| 
 | |
|     def GetNow(self):
 | |
|         now = wx.DateTime.Now()
 | |
|         date = now.FormatDate()
 | |
|         time = now.FormatTime()
 | |
|         return date, time
 | |
| 
 | |
|     def SetPreview(self, preview):
 | |
|         self.preview = preview
 | |
| 
 | |
|     def SetPSize(self, width, height):
 | |
|         self.pwidth = width/self.scale
 | |
|         self.pheight = height/self.scale
 | |
| 
 | |
|     def SetScale(self, scale):
 | |
|         self.scale = scale
 | |
| 
 | |
|     def SetPTSize(self, width, height):
 | |
|         self.ptwidth = width
 | |
|         self.ptheight = height
 | |
| 
 | |
|     def getWidth(self):
 | |
|         return self.sizew
 | |
| 
 | |
|     def getHeight(self):
 | |
|         return self.sizeh
 | |
| 
 | |
| 
 | |
| class PrintTableDraw(wx.ScrolledWindow, PrintBase):
 | |
|     def __init__(self, parent, DC, size):
 | |
|         self.parent = parent
 | |
|         self.DC = DC
 | |
|         self.scale = parent.scale
 | |
|         self.width = size[0]
 | |
|         self.height = size[1]
 | |
|         self.SetDefaults()
 | |
| 
 | |
|     def SetDefaults(self):
 | |
|         self.page = 1
 | |
|         self.total_pages = None
 | |
| 
 | |
|         self.page_width = self.parent.page_width
 | |
|         self.page_height = self.parent.page_height
 | |
| 
 | |
|         self.left_margin = self.parent.left_margin
 | |
|         self.right_margin = self.parent.right_margin
 | |
| 
 | |
|         self.top_margin  = self.parent.top_margin
 | |
|         self.bottom_margin = self.parent.bottom_margin
 | |
|         self.cell_left_margin = self.parent.cell_left_margin
 | |
|         self.cell_right_margin = self.parent.cell_right_margin
 | |
| 
 | |
|         self.label_colour = self.parent.label_colour
 | |
| 
 | |
|         self.row_line_colour = self.parent.row_line_colour
 | |
|         self.row_line_size = self.parent.row_line_size
 | |
| 
 | |
|         self.row_def_line_colour = self.parent.row_def_line_colour
 | |
|         self.row_def_line_size = self.parent.row_def_line_size
 | |
| 
 | |
|         self.column_line_colour = self.parent.column_line_colour
 | |
|         self.column_line_size = self.parent.column_line_size
 | |
| 
 | |
|         self.column_def_line_size = self.parent.column_def_line_size
 | |
|         self.column_def_line_colour = self.parent.column_def_line_colour
 | |
| 
 | |
|         self.text_font = self.parent.text_font
 | |
| 
 | |
|         self.label_font = self.parent.label_font
 | |
| 
 | |
|     def AdjustValues(self):
 | |
|         self.vertical_offset = self.pheight * self.parent.vertical_offset
 | |
|         self.horizontal_offset = self.pheight * self.parent.horizontal_offset
 | |
| 
 | |
|         self.pcell_left_margin = self.pwidth * self.cell_left_margin
 | |
|         self.pcell_right_margin = self.pwidth * self.cell_right_margin
 | |
|         self.ptop_margin = self.pheight * self.top_margin
 | |
|         self.pbottom_margin = self.pheight * self.bottom_margin
 | |
| 
 | |
|         self.pheader_margin = self.pheight * self.parent.header_margin
 | |
|         self.pfooter_margin = self.pheight * self.parent.footer_margin
 | |
| 
 | |
|         self.cell_colour = self.parent.set_cell_colour
 | |
|         self.cell_text = self.parent.set_cell_text
 | |
| 
 | |
|         self.column = []
 | |
|         self.column_align = []
 | |
|         self.column_bgcolour = []
 | |
|         self.column_txtcolour = []
 | |
| 
 | |
|         set_column_align = self.parent.set_column_align
 | |
|         set_column_bgcolour = self.parent.set_column_bgcolour
 | |
|         set_column_txtcolour = self.parent.set_column_txtcolour
 | |
| 
 | |
|         pos_x = self.left_margin * self.pwidth + self.horizontal_offset     # left margin
 | |
|         self.column.append(pos_x)
 | |
| 
 | |
|         #module logic expects two dimensional data -- fix input if needed
 | |
|         if isinstance(self.data,types.StringTypes):
 | |
|             self.data = [[copy.copy(self.data)]] # a string becomes a single cell
 | |
|         try:
 | |
|             rows = len(self.data)
 | |
|         except TypeError:
 | |
|             self.data = [[str(self.data)]] # a non-iterable becomes a single cell
 | |
|             rows = 1
 | |
|         first_value = self.data[0]
 | |
| 
 | |
|         if isinstance(first_value, types.StringTypes): # a sequence of strings
 | |
|             if self.label == [] and self.set_column == []:
 | |
|                 data = []
 | |
|                 for x in self.data:     #becomes one column
 | |
|                     data.append([x])
 | |
|             else:
 | |
|                 data = [self.data]      #becames one row
 | |
|             self.data = data
 | |
|             first_value = data[0]
 | |
|         try:
 | |
|             column_total = len(first_value)
 | |
|         except TypeError:    # a sequence of non-iterables
 | |
|             if self.label == [] and self.set_column == []:
 | |
|                 data = []       #becomes one column
 | |
|                 for x in self.data:
 | |
|                     data.append([str(x)])
 | |
|                 column_total = 1
 | |
|             else:
 | |
|                 data = [self.data] #becomes one row
 | |
|                 column_total = len(self.data)
 | |
|             self.data = data
 | |
|             first_value = data[0]
 | |
| 
 | |
|         if self.set_column == []:
 | |
|             table_width = self.page_width - self.left_margin - self.right_margin
 | |
|             if self.label == []:
 | |
|                 temp = first_value
 | |
|             else:
 | |
|                 temp = self.label
 | |
|             width = table_width/(len(temp))
 | |
|             for val in temp:
 | |
|                 column_width = width * self.pwidth
 | |
|                 pos_x = pos_x + column_width
 | |
|                 self.column.append(pos_x)   # position of each column
 | |
|         else:
 | |
|             for val in self.set_column:
 | |
|                 column_width = val * self.pwidth
 | |
|                 pos_x = pos_x + column_width
 | |
|                 self.column.append(pos_x)   # position of each column
 | |
| 
 | |
|         if pos_x > self.page_width * self.pwidth:    # check if it fits in page
 | |
|             print "Warning, Too Wide for Page"
 | |
|             return
 | |
| 
 | |
|         if self.label != []:
 | |
|             if len(self.column) -1 != len(self.label):
 | |
|                 print "Column Settings Incorrect", "\nColumn Value: " + str(self.column), "\nLabel Value: " + str(self.label)
 | |
|                 return
 | |
| 
 | |
|         if column_total != len(self.column) -1:
 | |
|             print "Cannot fit", first_value, 'in', len(self.column)-1, 'columns.'
 | |
|             return
 | |
| 
 | |
|         for col in range(column_total):
 | |
|             try:
 | |
|                 align = set_column_align[col]       # check if custom column alignment
 | |
|             except:
 | |
|                 align = wx.ALIGN_LEFT
 | |
|             self.column_align.append(align)
 | |
| 
 | |
|             try:
 | |
|                 colour = set_column_bgcolour[col]     # check if custom column background colour
 | |
|             except:
 | |
|                 colour = self.parent.column_colour
 | |
|             self.column_bgcolour.append(colour)
 | |
| 
 | |
|             try:
 | |
|                 colour = set_column_txtcolour[col]     # check if custom column text colour
 | |
|             except:
 | |
|                 colour = self.GetFontColour(self.parent.text_font)
 | |
|             self.column_txtcolour.append(colour)
 | |
| 
 | |
| 
 | |
|     def SetPointAdjust(self):
 | |
|         f = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)     # setup using 10 point
 | |
|         self.DC.SetFont(f)
 | |
|         f.SetFaceName(self.text_font["Name"])
 | |
|         x, y = self.DC.GetTextExtent("W")
 | |
| 
 | |
|         self.label_pt_space_before = self.parent.label_pt_adj_before * y/10        # extra spacing for label per point value
 | |
|         self.label_pt_space_after = self.parent.label_pt_adj_after * y/10
 | |
| 
 | |
|         self.text_pt_space_before = self.parent.text_pt_adj_before * y/10        # extra spacing for row text per point value
 | |
|         self.text_pt_space_after = self.parent.text_pt_adj_after * y/10
 | |
| 
 | |
|     def SetPage(self, page):
 | |
|         self.page = page
 | |
| 
 | |
|     def SetColumns(self, col):
 | |
|         self.column = col
 | |
| 
 | |
|     def OutCanvas(self):
 | |
|         self.AdjustValues()
 | |
|         self.SetPointAdjust()
 | |
| 
 | |
|         self.y_start = self.ptop_margin + self.vertical_offset
 | |
|         self.y_end = self.parent.page_height * self.pheight - self.pbottom_margin + self.vertical_offset
 | |
| 
 | |
|         self.SetPrintFont(self.label_font)
 | |
| 
 | |
|         x, y = self.DC.GetTextExtent("W")
 | |
|         self.label_space = y
 | |
| 
 | |
|         self.SetPrintFont(self.text_font)
 | |
| 
 | |
|         x, y = self.DC.GetTextExtent("W")
 | |
|         self.space = y
 | |
| 
 | |
|         if self.total_pages is None:
 | |
|             self.GetTotalPages()    # total pages for display/printing
 | |
| 
 | |
|         self.data_cnt = self.page_index[self.page-1]
 | |
| 
 | |
|         self.draw = True
 | |
|         self.PrintHeader()
 | |
|         self.PrintFooter()
 | |
|         self.OutPage()
 | |
| 
 | |
|     def GetTotalPages(self):
 | |
|         self.data_cnt = 0
 | |
|         self.draw = False
 | |
|         self.page_index = [0]
 | |
| 
 | |
|         cnt = 0
 | |
|         while 1:
 | |
|             test = self.OutPage()
 | |
|             self.page_index.append(self.data_cnt)
 | |
|             if  test == False:
 | |
|                 break
 | |
|             cnt = cnt + 1
 | |
| 
 | |
|         self.total_pages = cnt + 1
 | |
| 
 | |
|     def OutPage(self):
 | |
|         self.y = self.y_start
 | |
|         self.end_x = self.column[-1]
 | |
| 
 | |
|         if self.data_cnt < len(self.data):  # if there data for display on the page
 | |
|             if self.label != []:        # check if header defined
 | |
|                 self.PrintLabel()
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
|         for val in self.data:
 | |
|             try:
 | |
|                 row_val = self.data[self.data_cnt]
 | |
|             except:
 | |
|                 self.FinishDraw()
 | |
|                 return False
 | |
| 
 | |
|             max_y = self.PrintRow(row_val, False)       # test to see if row will fit in remaining space
 | |
|             test = max_y + self.space
 | |
| 
 | |
|             if test > self.y_end:
 | |
|                 break
 | |
| 
 | |
|             self.ColourRowCells(max_y-self.y+self.space)       # colour the row/column
 | |
|             max_y = self.PrintRow(row_val, True)      # row fits - print text
 | |
|             self.DrawGridLine()     # top line of cell
 | |
|             self.y = max_y + self.space
 | |
| 
 | |
|             if self.y > self.y_end:
 | |
|                 break
 | |
| 
 | |
|             self.data_cnt = self.data_cnt + 1
 | |
| 
 | |
|         self.FinishDraw()
 | |
| 
 | |
|         if self.data_cnt == len(self.data):    # last value in list
 | |
|             return False
 | |
| 
 | |
|         return True
 | |
| 
 | |
| 
 | |
|     def PrintLabel(self):
 | |
|         self.pt_space_before = self.label_pt_space_before   # set the point spacing
 | |
|         self.pt_space_after = self.label_pt_space_after
 | |
| 
 | |
|         self.LabelColorRow(self.label_colour)
 | |
|         self.SetPrintFont(self.label_font)
 | |
| 
 | |
|         self.col = 0
 | |
|         max_y = 0
 | |
|         for vtxt in self.label:
 | |
|             self.region = self.column[self.col+1] - self.column[self.col]
 | |
|             self.indent = self.column[self.col]
 | |
| 
 | |
|             self.align = wx.ALIGN_LEFT
 | |
| 
 | |
|             max_out = self.OutTextRegion(vtxt, True)
 | |
|             if max_out > max_y:
 | |
|                 max_y = max_out
 | |
|             self.col = self.col + 1
 | |
| 
 | |
|         self.DrawGridLine()     # top line of label
 | |
|         self.y = max_y + self.label_space
 | |
| 
 | |
|     def PrintHeader(self):      # print the header array
 | |
|         if self.draw == False:
 | |
|             return
 | |
| 
 | |
|         for val in self.parent.header:
 | |
|             self.SetPrintFont(val["Font"])
 | |
| 
 | |
|             header_indent = val["Indent"] * self.pwidth
 | |
|             text = val["Text"]
 | |
| 
 | |
|             htype = val["Type"]
 | |
|             if htype == "Date":
 | |
|                 addtext = self.GetDate()
 | |
|             elif htype == "Date & Time":
 | |
|                 addtext = self.GetDateTime()
 | |
|             else:
 | |
|                 addtext = ""
 | |
| 
 | |
|             self.OutTextPageWidth(text+addtext, self.pheader_margin, val["Align"], header_indent, True)
 | |
| 
 | |
|     def PrintFooter(self):      # print the header array
 | |
|         if self.draw == False:
 | |
|             return
 | |
| 
 | |
|         footer_pos = self.parent.page_height * self.pheight - self.pfooter_margin + self.vertical_offset
 | |
|         for val in self.parent.footer:
 | |
|             self.SetPrintFont(val["Font"])
 | |
| 
 | |
|             footer_indent = val["Indent"] * self.pwidth
 | |
|             text = val["Text"]
 | |
| 
 | |
|             ftype = val["Type"]
 | |
|             if ftype == "Pageof":
 | |
|                 addtext = "Page " + str(self.page) + " of " + str(self.total_pages)
 | |
|             elif ftype == "Page":
 | |
|                 addtext = "Page " + str(self.page)
 | |
|             elif ftype == "Num":
 | |
|                 addtext = str(self.page)
 | |
|             elif ftype == "Date":
 | |
|                 addtext = self.GetDate()
 | |
|             elif ftype == "Date & Time":
 | |
|                 addtext = self.GetDateTime()
 | |
|             else:
 | |
|                 addtext = ""
 | |
| 
 | |
|             self.OutTextPageWidth(text+addtext, footer_pos, val["Align"], footer_indent, True)
 | |
| 
 | |
| 
 | |
|     def LabelColorRow(self, colour):
 | |
|         brush = wx.Brush(colour, wx.SOLID)
 | |
|         self.DC.SetBrush(brush)
 | |
|         height = self.label_space + self.label_pt_space_before + self.label_pt_space_after
 | |
|         self.DC.DrawRectangle(self.column[0], self.y,
 | |
|                               self.end_x-self.column[0]+1, height)
 | |
| 
 | |
|     def ColourRowCells(self, height):
 | |
|         if self.draw == False:
 | |
|             return
 | |
| 
 | |
|         col = 0
 | |
|         for colour in self.column_bgcolour:
 | |
|             cellcolour = self.GetCellColour(self.data_cnt, col)
 | |
|             if cellcolour is not None:
 | |
|                 colour = cellcolour
 | |
| 
 | |
|             brush = wx.Brush(colour, wx.SOLID)
 | |
|             self.DC.SetBrush(brush)
 | |
|             self.DC.SetPen(wx.Pen(wx.NamedColour('WHITE'), 0))
 | |
| 
 | |
|             start_x = self.column[col]
 | |
|             width = self.column[col+1] - start_x + 2
 | |
|             self.DC.DrawRectangle(start_x, self.y, width, height)
 | |
|             col = col + 1
 | |
| 
 | |
|     def PrintRow(self, row_val, draw = True, align = wx.ALIGN_LEFT):
 | |
|         self.SetPrintFont(self.text_font)
 | |
| 
 | |
|         self.pt_space_before = self.text_pt_space_before   # set the point spacing
 | |
|         self.pt_space_after = self.text_pt_space_after
 | |
| 
 | |
|         self.col = 0
 | |
|         max_y = 0
 | |
|         for vtxt in row_val:
 | |
|             if not isinstance(vtxt,types.StringTypes):
 | |
|                 vtxt = str(vtxt)
 | |
|             self.region = self.column[self.col+1] - self.column[self.col]
 | |
|             self.indent = self.column[self.col]
 | |
|             self.align = self.column_align[self.col]
 | |
| 
 | |
|             fcolour = self.column_txtcolour[self.col]       # set font colour
 | |
|             celltext = self.GetCellTextColour(self.data_cnt, self.col)
 | |
|             if celltext is not None:
 | |
|                 fcolour = celltext      # override the column colour
 | |
| 
 | |
|             self.DC.SetTextForeground(fcolour)
 | |
| 
 | |
|             max_out = self.OutTextRegion(vtxt, draw)
 | |
|             if max_out > max_y:
 | |
|                 max_y = max_out
 | |
|             self.col = self.col + 1
 | |
|         return max_y
 | |
| 
 | |
|     def GetCellColour(self, row, col):      # check if custom colour defined for the cell background
 | |
|         try:
 | |
|             set = self.cell_colour[row]
 | |
|         except:
 | |
|             return None
 | |
|         try:
 | |
|             colour = set[col]
 | |
|             return colour
 | |
|         except:
 | |
|             return None
 | |
| 
 | |
|     def GetCellTextColour(self, row, col):      # check if custom colour defined for the cell text
 | |
|         try:
 | |
|             set = self.cell_text[row]
 | |
|         except:
 | |
|             return None
 | |
|         try:
 | |
|             colour = set[col]
 | |
|             return colour
 | |
|         except:
 | |
|             return None
 | |
| 
 | |
|     def FinishDraw(self):
 | |
|         self.DrawGridLine()     # draw last row line
 | |
|         self.DrawColumns()      # draw all vertical lines
 | |
| 
 | |
|     def DrawGridLine(self):
 | |
|         if self.draw == True \
 | |
|         and len(self.column) > 2:    #supress grid lines if only one column
 | |
|             try:
 | |
|                 size = self.row_line_size[self.data_cnt]
 | |
|             except:
 | |
|                 size = self.row_def_line_size
 | |
| 
 | |
|             if size < 1: return
 | |
| 
 | |
|             try:
 | |
|                 colour = self.row_line_colour[self.data_cnt]
 | |
|             except:
 | |
|                 colour = self.row_def_line_colour
 | |
| 
 | |
|             self.DC.SetPen(wx.Pen(colour, size))
 | |
| 
 | |
|             y_out = self.y
 | |
| #            y_out = self.y + self.pt_space_before + self.pt_space_after     # adjust for extra spacing
 | |
|             self.DC.DrawLine(self.column[0], y_out, self.end_x, y_out)
 | |
| 
 | |
|     def DrawColumns(self):
 | |
|         if self.draw == True \
 | |
|         and len(self.column) > 2:   #surpress grid line if only one column
 | |
|             col = 0
 | |
|             for val in self.column:
 | |
|                 try:
 | |
|                     size = self.column_line_size[col]
 | |
|                 except:
 | |
|                     size = self.column_def_line_size
 | |
| 
 | |
|                 if size < 1: continue
 | |
| 
 | |
|                 try:
 | |
|                     colour = self.column_line_colour[col]
 | |
|                 except:
 | |
|                     colour = self.column_def_line_colour
 | |
| 
 | |
|                 indent = val
 | |
| 
 | |
|                 self.DC.SetPen(wx.Pen(colour, size))
 | |
|                 self.DC.DrawLine(indent, self.y_start, indent, self.y)
 | |
|                 col = col + 1
 | |
| 
 | |
|     def DrawText(self):
 | |
|         self.DoRefresh()
 | |
| 
 | |
|     def DoDrawing(self, DC):
 | |
|         size = DC.GetSize()
 | |
|         self.DC = DC
 | |
| 
 | |
|         DC.BeginDrawing()
 | |
|         self.DrawText()
 | |
|         DC.EndDrawing()
 | |
| 
 | |
|         self.sizew = DC.MaxY()
 | |
|         self.sizeh = DC.MaxX()
 | |
| 
 | |
| 
 | |
| class PrintTable:
 | |
|     def __init__(self, parentFrame=None):
 | |
|         self.data = []
 | |
|         self.set_column = []
 | |
|         self.label = []
 | |
|         self.header = []
 | |
|         self.footer = []
 | |
| 
 | |
|         self.set_column_align = {}
 | |
|         self.set_column_bgcolour = {}
 | |
|         self.set_column_txtcolour = {}
 | |
|         self.set_cell_colour = {}
 | |
|         self.set_cell_text = {}
 | |
|         self.column_line_size = {}
 | |
|         self.column_line_colour = {}
 | |
|         self.row_line_size = {}
 | |
|         self.row_line_colour = {}
 | |
| 
 | |
|         self.parentFrame = parentFrame
 | |
|         self.SetPreviewSize()
 | |
| 
 | |
|         self.printData = wx.PrintData()
 | |
|         self.scale = 1.0
 | |
| 
 | |
|         self.SetParms()
 | |
|         self.SetColors()
 | |
|         self.SetFonts()
 | |
|         self.TextSpacing()
 | |
| 
 | |
|         self.SetPrinterOffset()
 | |
|         self.SetHeaderValue()
 | |
|         self.SetFooterValue()
 | |
|         self.SetMargins()
 | |
|         self.SetPortrait()
 | |
| 
 | |
|     def SetPreviewSize(self, position = wx.Point(0, 0), size="Full"):
 | |
|         if size == "Full":
 | |
|             r = wx.GetClientDisplayRect()
 | |
|             self.preview_frame_size = r.GetSize()
 | |
|             self.preview_frame_pos = r.GetPosition()
 | |
|         else:
 | |
|             self.preview_frame_size = size
 | |
|             self.preview_frame_pos = position
 | |
| 
 | |
|     def SetPaperId(self, paper):
 | |
|         self.printData.SetPaperId(paper)
 | |
| 
 | |
|     def SetOrientation(self, orient):
 | |
|         self.printData.SetOrientation(orient)
 | |
| 
 | |
|     def SetColors(self):
 | |
|         self.row_def_line_colour = wx.NamedColour('BLACK')
 | |
|         self.row_def_line_size = 1
 | |
| 
 | |
|         self.column_def_line_colour = wx.NamedColour('BLACK')
 | |
|         self.column_def_line_size = 1
 | |
|         self.column_colour = wx.NamedColour('WHITE')
 | |
| 
 | |
|         self.label_colour = wx.NamedColour('LIGHT GREY')
 | |
| 
 | |
|     def SetFonts(self):
 | |
|         self.label_font = { "Name": self.default_font_name, "Size": 12, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 | |
|         self.text_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 | |
| 
 | |
|     def TextSpacing(self):
 | |
|         self.label_pt_adj_before = 0     # point adjustment before and after the label text
 | |
|         self.label_pt_adj_after = 0
 | |
| 
 | |
|         self.text_pt_adj_before = 0     # point adjustment before and after the row text
 | |
|         self.text_pt_adj_after = 0
 | |
| 
 | |
|     def SetLabelSpacing(self, before, after):        # method to set the label space adjustment
 | |
|         self.label_pt_adj_before = before
 | |
|         self.label_pt_adj_after = after
 | |
| 
 | |
|     def SetRowSpacing(self, before, after):         # method to set the row space adjustment
 | |
|         self.text_pt_adj_before = before
 | |
|         self.text_pt_adj_after = after
 | |
| 
 | |
|     def SetPrinterOffset(self):        # offset to adjust for printer
 | |
|         self.vertical_offset = -0.1
 | |
|         self.horizontal_offset = -0.1
 | |
| 
 | |
|     def SetHeaderValue(self):
 | |
|         self.header_margin = 0.25
 | |
|         self.header_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 | |
|         self.header_align = wx.ALIGN_CENTRE
 | |
|         self.header_indent = 0
 | |
|         self.header_type = "Text"
 | |
| 
 | |
|     def SetFooterValue(self):
 | |
|         self.footer_margin = 0.7
 | |
|         self.footer_font = { "Name": self.default_font_name, "Size": 11, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 | |
|         self.footer_align = wx.ALIGN_CENTRE
 | |
|         self.footer_indent = 0
 | |
|         self.footer_type = "Pageof"
 | |
| 
 | |
|     def SetMargins(self):
 | |
|         self.left_margin = 0.5
 | |
|         self.right_margin = 0.5    # only used if no column sizes
 | |
| 
 | |
|         self.top_margin  = 0.8
 | |
|         self.bottom_margin = 1.0
 | |
|         self.cell_left_margin = 0.1
 | |
|         self.cell_right_margin = 0.1
 | |
| 
 | |
|     def SetPortrait(self):
 | |
|         self.printData.SetPaperId(wx.PAPER_LETTER)
 | |
|         self.printData.SetOrientation(wx.PORTRAIT)
 | |
|         self.page_width = 8.5
 | |
|         self.page_height = 11.0
 | |
| 
 | |
|     def SetLandscape(self):
 | |
|         self.printData.SetOrientation(wx.LANDSCAPE)
 | |
|         self.page_width = 11.0
 | |
|         self.page_height = 8.5
 | |
| 
 | |
|     def SetParms(self):
 | |
|         self.ymax = 1
 | |
|         self.xmax = 1
 | |
|         self.page = 1
 | |
|         self.total_pg = 100
 | |
| 
 | |
|         self.preview = None
 | |
|         self.page = 0
 | |
| 
 | |
|         self.default_font_name = "Arial"
 | |
|         self.default_font = { "Name": self.default_font_name, "Size": 10, "Colour": [0, 0, 0], "Attr": [0, 0, 0] }
 | |
| 
 | |
|     def SetColAlignment(self, col, align=wx.ALIGN_LEFT):
 | |
|         self.set_column_align[col] = align
 | |
| 
 | |
|     def SetColBackgroundColour(self, col, colour):
 | |
|         self.set_column_bgcolour[col] = colour
 | |
| 
 | |
|     def SetColTextColour(self, col, colour):
 | |
|         self.set_column_txtcolour[col] = colour
 | |
| 
 | |
|     def SetCellColour(self, row, col, colour):      # cell background colour
 | |
|         try:
 | |
|             set = self.set_cell_colour[row]     # test if row already exists
 | |
|             try:
 | |
|                 set[col] = colour       # test if column already exists
 | |
|             except:
 | |
|                 set = { col: colour }       # create the column value
 | |
|         except:
 | |
|             set = { col: colour }           # create the column value
 | |
| 
 | |
|         self.set_cell_colour[row] = set    # create dictionary item for colour settings
 | |
| 
 | |
|     def SetCellText(self, row, col, colour):        # font colour for custom cells
 | |
|         try:
 | |
|             set = self.set_cell_text[row]     # test if row already exists
 | |
|             try:
 | |
|                 set[col] = colour       # test if column already exists
 | |
|             except:
 | |
|                 set = { col: colour }       # create the column value
 | |
|         except:
 | |
|             set = { col: colour }           # create the column value
 | |
| 
 | |
|         self.set_cell_text[row] = set    # create dictionary item for colour settings
 | |
| 
 | |
|     def SetColumnLineSize(self, col, size):      # column line size
 | |
|         self.column_line_size[col] = size    # create dictionary item for column line settings
 | |
| 
 | |
|     def SetColumnLineColour(self, col, colour):
 | |
|         self.column_line_colour[col] = colour
 | |
| 
 | |
|     def SetRowLineSize(self, row, size):
 | |
|         self.row_line_size[row] = size
 | |
| 
 | |
|     def SetRowLineColour(self, row, colour):
 | |
|         self.row_line_colour[row] = colour
 | |
| 
 | |
|     def GetColour(self, colour):        # returns colours based from wxColour value
 | |
|         red = colour.Red()
 | |
|         blue = colour.Blue()
 | |
|         green = colour.Green()
 | |
|         return [red, green, blue ]
 | |
| 
 | |
|     def SetHeader(self, text = "", type = "Text", font=None, align = None, indent = None, colour = None, size = None):
 | |
|         set = { "Text": text }
 | |
| 
 | |
|         if font is None:
 | |
|             set["Font"] = copy.copy(self.default_font)
 | |
|         else:
 | |
|             set["Font"] = font
 | |
| 
 | |
|         if colour is not None:
 | |
|             setfont = set["Font"]
 | |
|             setfont["Colour"] = self.GetColour(colour)
 | |
| 
 | |
|         if size is not None:
 | |
|             setfont = set["Font"]
 | |
|             setfont["Size"] = size
 | |
| 
 | |
|         if align is None:
 | |
|             set["Align"] = self.header_align
 | |
|         else:
 | |
|             set["Align"] = align
 | |
| 
 | |
|         if indent is None:
 | |
|             set["Indent"] = self.header_indent
 | |
|         else:
 | |
|             set["Indent"] = indent
 | |
| 
 | |
|         if type is None:
 | |
|             set["Type"] = self.header_type
 | |
|         else:
 | |
|             set["Type"] = type
 | |
| 
 | |
|         self.header.append(set)
 | |
| 
 | |
|     def SetFooter(self, text = "", type = None, font=None, align = None, indent = None, colour = None, size = None):
 | |
|         set = { "Text": text }
 | |
| 
 | |
|         if font is None:
 | |
|             set["Font"] = copy.copy(self.default_font)
 | |
|         else:
 | |
|             set["Font"] = font
 | |
| 
 | |
|         if colour is not None:
 | |
|             setfont = set["Font"]
 | |
|             setfont["Colour"] = self.GetColour(colour)
 | |
| 
 | |
|         if size is not None:
 | |
|             setfont = set["Font"]
 | |
|             setfont["Size"] = size
 | |
| 
 | |
|         if align is None:
 | |
|             set["Align"] = self.footer_align
 | |
|         else:
 | |
|             set["Align"] = align
 | |
| 
 | |
|         if indent is None:
 | |
|             set["Indent"] = self.footer_indent
 | |
|         else:
 | |
|             set["Indent"] = indent
 | |
| 
 | |
|         if type is None:
 | |
|             set["Type"] = self.footer_type
 | |
|         else:
 | |
|             set["Type"] = type
 | |
| 
 | |
|         self.footer.append(set)
 | |
| 
 | |
|     def Preview(self):
 | |
|         data = wx.PrintDialogData(self.printData)
 | |
|         printout = SetPrintout(self)
 | |
|         printout2 = SetPrintout(self)
 | |
|         self.preview = wx.PrintPreview(printout, printout2, data)
 | |
|         if not self.preview.Ok():
 | |
|             wx.MessageBox("There was a problem printing!", "Printing", wx.OK)
 | |
|             return
 | |
| 
 | |
|         self.preview.SetZoom(60)        # initial zoom value
 | |
|         frame = wx.PreviewFrame(self.preview, self.parentFrame, "Print preview")
 | |
| 
 | |
|         frame.Initialize()
 | |
|         if self.parentFrame:
 | |
|             frame.SetPosition(self.preview_frame_pos)
 | |
|             frame.SetSize(self.preview_frame_size)
 | |
|         frame.Show(True)
 | |
| 
 | |
|     def Print(self):
 | |
|         pdd = wx.PrintDialogData(self.printData)
 | |
|         printer = wx.Printer(pdd)
 | |
|         printout = SetPrintout(self)
 | |
|         if not printer.Print(self.parentFrame, printout):
 | |
|             wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
 | |
|         else:
 | |
|             self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
 | |
|         printout.Destroy()
 | |
| 
 | |
|     def DoDrawing(self, DC):
 | |
|         size = DC.GetSize()
 | |
|         DC.BeginDrawing()
 | |
| 
 | |
|         table = PrintTableDraw(self, DC, size)
 | |
|         table.data = self.data
 | |
|         table.set_column = self.set_column
 | |
|         table.label = self.label
 | |
|         table.SetPage(self.page)
 | |
| 
 | |
|         if self.preview is None:
 | |
|             table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
 | |
|             table.SetPTSize(size[0], size[1])
 | |
|             table.SetPreview(False)
 | |
|         else:
 | |
|             if self.preview == 1:
 | |
|                 table.scale = self.scale
 | |
|                 table.SetPSize(size[0]/self.page_width, size[1]/self.page_height)
 | |
|             else:
 | |
|                 table.SetPSize(self.pwidth, self.pheight)
 | |
| 
 | |
|             table.SetPTSize(self.ptwidth, self.ptheight)
 | |
|             table.SetPreview(self.preview)
 | |
| 
 | |
|         table.OutCanvas()
 | |
|         self.page_total = table.total_pages     # total display pages
 | |
| 
 | |
|         DC.EndDrawing()
 | |
| 
 | |
|         self.ymax = DC.MaxY()
 | |
|         self.xmax = DC.MaxX()
 | |
| 
 | |
|         self.sizeh = size[0]
 | |
|         self.sizew = size[1]
 | |
| 
 | |
|     def GetTotalPages(self):
 | |
|         self.page_total = 100
 | |
|         return self.page_total
 | |
| 
 | |
|     def HasPage(self, page):
 | |
|         if page <= self.page_total:
 | |
|             return True
 | |
|         else:
 | |
|             return False
 | |
| 
 | |
|     def SetPage(self, page):
 | |
|         self.page = page
 | |
| 
 | |
|     def SetPageSize(self, width, height):
 | |
|         self.pwidth, self.pheight = width, height
 | |
| 
 | |
|     def SetTotalSize(self, width, height):
 | |
|         self.ptwidth, self.ptheight = width, height
 | |
| 
 | |
|     def SetPreview(self, preview, scale):
 | |
|         self.preview = preview
 | |
|         self.scale = scale
 | |
| 
 | |
|     def SetTotalSize(self, width, height):
 | |
|         self.ptwidth = width
 | |
|         self.ptheight = height
 | |
| 
 | |
| class PrintGrid:
 | |
|     def __init__(self, parent, grid, format = [], total_col = None, total_row = None):
 | |
|         if total_row is None:
 | |
|             total_row = grid.GetNumberRows()
 | |
|         if total_col is None:
 | |
|             total_col = grid.GetNumberCols()
 | |
| 
 | |
|         self.total_row = total_row
 | |
|         self.total_col = total_col
 | |
|         self.grid = grid
 | |
| 
 | |
|         data = []
 | |
|         for row in range(total_row):
 | |
|             row_val = []
 | |
|             value = grid.GetRowLabelValue(row)
 | |
|             row_val.append(value)
 | |
| 
 | |
|             for col in range(total_col):
 | |
|                 value = grid.GetCellValue(row, col)
 | |
|                 row_val.append(value)
 | |
|             data.append(row_val)
 | |
| 
 | |
|         label = [""]
 | |
|         for col in range(total_col):
 | |
|             value = grid.GetColLabelValue(col)
 | |
|             label.append(value)
 | |
| 
 | |
|         self.table = PrintTable(parent)
 | |
|         self.table.cell_left_margin = 0.0
 | |
|         self.table.cell_right_margin = 0.0
 | |
| 
 | |
|         self.table.label = label
 | |
|         self.table.set_column = format
 | |
|         self.table.data = data
 | |
| 
 | |
|     def GetTable(self):
 | |
|         return self.table
 | |
| 
 | |
|     def SetAttributes(self):
 | |
|         for row in range(self.total_row):
 | |
|             for col in range(self.total_col):
 | |
|                 colour = self.grid.GetCellTextColour(row, col-1)
 | |
|                 self.table.SetCellText(row, col, colour)
 | |
| 
 | |
|                 colour = self.grid.GetCellBackgroundColour(row, col-1)
 | |
|                 self.table.SetCellColour(row, col, colour)
 | |
| 
 | |
|     def Preview(self):
 | |
|         self.table.Preview()
 | |
| 
 | |
|     def Print(self):
 | |
|         self.table.Print()
 | |
| 
 | |
| 
 | |
| class SetPrintout(wx.Printout):
 | |
|     def __init__(self, canvas):
 | |
|         wx.Printout.__init__(self)
 | |
|         self.canvas = canvas
 | |
|         self.end_pg = 1000
 | |
| 
 | |
|     def OnBeginDocument(self, start, end):
 | |
|         return super(SetPrintout, self).OnBeginDocument(start, end)
 | |
| 
 | |
|     def OnEndDocument(self):
 | |
|         super(SetPrintout, self).OnEndDocument()
 | |
| 
 | |
|     def HasPage(self, page):
 | |
|         try:
 | |
|             end = self.canvas.HasPage(page)
 | |
|             return end
 | |
|         except:
 | |
|             return True
 | |
| 
 | |
|     def GetPageInfo(self):
 | |
|         try:
 | |
|             self.end_pg = self.canvas.GetTotalPages()
 | |
|         except:
 | |
|             pass
 | |
| 
 | |
|         end_pg = self.end_pg
 | |
|         str_pg = 1
 | |
|         return (str_pg, end_pg, str_pg, end_pg)
 | |
| 
 | |
|     def OnPreparePrinting(self):
 | |
|         super(SetPrintout, self).OnPreparePrinting()
 | |
| 
 | |
|     def OnBeginPrinting(self):
 | |
|         dc = self.GetDC()
 | |
| 
 | |
|         self.preview = self.IsPreview()
 | |
|         if (self.preview):
 | |
|             self.pixelsPerInch = self.GetPPIScreen()
 | |
|         else:
 | |
|             self.pixelsPerInch = self.GetPPIPrinter()
 | |
| 
 | |
|         (w, h) = dc.GetSize()
 | |
|         scaleX = float(w) / 1000
 | |
|         scaleY = float(h) / 1000
 | |
|         self.printUserScale = min(scaleX, scaleY)
 | |
| 
 | |
|         super(SetPrintout, self).OnBeginPrinting()
 | |
| 
 | |
|     def GetSize(self):
 | |
|         self.psizew, self.psizeh = self.GetPPIPrinter()
 | |
|         return self.psizew, self.psizeh
 | |
| 
 | |
|     def GetTotalSize(self):
 | |
|         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
 | |
|         return self.ptsizew, self.ptsizeh
 | |
| 
 | |
|     def OnPrintPage(self, page):
 | |
|         dc = self.GetDC()
 | |
|         (w, h) = dc.GetSize()
 | |
|         scaleX = float(w) / 1000
 | |
|         scaleY = float(h) / 1000
 | |
|         self.printUserScale = min(scaleX, scaleY)
 | |
|         dc.SetUserScale(self.printUserScale, self.printUserScale)
 | |
| 
 | |
|         self.preview = self.IsPreview()
 | |
| 
 | |
|         self.canvas.SetPreview(self.preview, self.printUserScale)
 | |
|         self.canvas.SetPage(page)
 | |
| 
 | |
|         self.ptsizew, self.ptsizeh = self.GetPageSizePixels()
 | |
|         self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh)
 | |
| 
 | |
|         self.psizew, self.psizeh = self.GetPPIPrinter()
 | |
|         self.canvas.SetPageSize(self.psizew, self.psizeh)
 | |
| 
 | |
|         self.canvas.DoDrawing(dc)
 | |
|         return True
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     app = wx.PySimpleApp()
 | |
|     frame = wx.Frame(None, -1, "Dummy wx frame for testing printout.py")
 | |
|     frame.Show(True)
 | |
|     ptbl = PrintTable(frame)
 | |
|     ptbl.SetHeader('This is the test HEADER')
 | |
|     # a single sequence will print out as a single column with no borders ...
 | |
|     ptbl.data = (
 | |
|         'This is the first line of text.',
 | |
|         'This is the second line\nand the third. The fourth will be the number "4.0".',
 | |
|         04.00,
 | |
|         'This is the fifth line, but by design it is too long to fit in the width of a standard'\
 | |
|          ' page, so it will be forced to wrap around in order to fit without having '\
 | |
|          'some of its verbose verbage truncated.',
 | |
|         'Here we have the final line.'
 | |
|         )
 | |
|     #... but, if labels or columns are defined, a single sequence will print out as a single row
 | |
|     ##ptbl.label = ('One','Two','Three','Four','5')
 | |
|     ptbl.Preview()
 | |
|     app.MainLoop()
 |