#----------------------------------------------------------------------------
# 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.
#

import  copy
import  os
import  sys

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)

        if self.set_column == []:
            table_width = self.page_width - self.left_margin - self.right_margin
            width = table_width/(len(self.label))
            for val in self.label:
                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

        first_value = self.data[0]
        column_total = len(first_value)
        if column_total != len(self.column) -1:
            print "Column Settings Incorrect", first_value, self.column
            return

        col = 0
        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)

            col = col + 1

    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:
            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.GetCellText(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 GetCellText(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:
            try:
                size = self.row_line_size[self.data_cnt]
            except:
                size = self.row_def_line_size

            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:
            col = 0
            for val in self.column:
                try:
                    size = self.column_line_size[col]
                except:
                    size = self.column_def_line_size

                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 = 1.0
        self.right_margin = 1.0     # 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):
        printout = SetPrintout(self)
        printout2 = SetPrintout(self)
        self.preview = wx.PrintPreview(printout, printout2, self.printData)
        if not self.preview.Ok():
            wxMessageBox("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()
        pdd.SetPrintData(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 = 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 self.base_OnBeginDocument(start, end)

    def OnEndDocument(self):
        self.base_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):
        self.base_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)

        self.base_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






