#-----------------------------------------------------------------------------
# Name:        STCPrinting.py
# Purpose:
#
# Author:      Riaan Booysen
#
# Created:     2003/05/21
# RCS-ID:      $Id: STCPrinting.py,v 1.10 2007/07/02 15:01:16 riaan Exp $
# Copyright:   (c) 2003 - 2007
# Licence:     wxWidgets
#-----------------------------------------------------------------------------
#Boa:Dialog:STCPrintDlg

"""
"""

# XXX Currently forces stc rendering not to wrap lines, currently the page
# XXX total calculations depend on exact number of lines

# XXX

import os

import wx
import wx.stc

from Utils import _

def create(parent):
    return STCPrintDlg(parent)

[wxID_STCPRINTDLG, wxID_STCPRINTDLGBTNCANCEL, wxID_STCPRINTDLGBTNPRINT, 
 wxID_STCPRINTDLGBTNPRINTPREVIEW, wxID_STCPRINTDLGBTNPRINTSETUP, 
 wxID_STCPRINTDLGCKBFILENAME, wxID_STCPRINTDLGCKBPAGENUMBERS, 
 wxID_STCPRINTDLGRDBCOLOURMODE, 
] = [wx.NewId() for _init_ctrls in range(8)]

stcPrintColourModes = [0, wx.stc.STC_PRINT_BLACKONWHITE, 
                          wx.stc.STC_PRINT_COLOURONWHITE,
                          wx.stc.STC_PRINT_COLOURONWHITEDEFAULTBG]

class STCPrintDlg(wx.Dialog):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Dialog.__init__(self, id=wxID_STCPRINTDLG, name='STCPrintDlg',
              parent=prnt, pos=wx.Point(352, 204), size=wx.Size(402, 189),
              style=wx.DEFAULT_DIALOG_STYLE, title=_('Print Source'))
        self.SetClientSize(wx.Size(394, 162))

        self.rdbColourMode = wx.RadioBox(choices=[_('Normal'), _('Black on white'),
              _('Colour on white'), _('Colour on white default background')],
              id=wxID_STCPRINTDLGRDBCOLOURMODE, label=_('Colour Mode'),
              majorDimension=1, name='rdbColourMode', parent=self,
              point=wx.Point(8, 8), size=wx.Size(216, 112),
              style=wx.RA_SPECIFY_COLS)

        self.ckbFilename = wx.CheckBox(id=wxID_STCPRINTDLGCKBFILENAME,
              label=_('Filename at top'), name='ckbFilename', parent=self,
              pos=wx.Point(240, 16), size=wx.Size(144, 13), style=0)
        self.ckbFilename.SetValue(True)

        self.ckbPageNumbers = wx.CheckBox(id=wxID_STCPRINTDLGCKBPAGENUMBERS,
              label=_('Page numbers'), name='ckbPageNumbers', parent=self,
              pos=wx.Point(240, 40), size=wx.Size(136, 13), style=0)
        self.ckbPageNumbers.SetValue(True)

        self.btnPrintSetup = wx.Button(id=wxID_STCPRINTDLGBTNPRINTSETUP,
              label=_('Print Setup'), name='btnPrintSetup', parent=self,
              pos=wx.Point(8, 128), size=wx.Size(88, 23), style=0)
        self.btnPrintSetup.Bind(wx.EVT_BUTTON, self.OnPrintSetup,
              id=wxID_STCPRINTDLGBTNPRINTSETUP)

        self.btnPrintPreview = wx.Button(id=wxID_STCPRINTDLGBTNPRINTPREVIEW,
              label=_('Print Preview'), name='btnPrintPreview', parent=self,
              pos=wx.Point(104, 128), size=wx.Size(88, 23), style=0)
        self.btnPrintPreview.Bind(wx.EVT_BUTTON, self.OnPrintPreview,
              id=wxID_STCPRINTDLGBTNPRINTPREVIEW)

        self.btnPrint = wx.Button(id=wxID_STCPRINTDLGBTNPRINT, label=_('Print'),
              name='btnPrint', parent=self, pos=wx.Point(200, 128),
              size=wx.Size(88, 23), style=0)
        self.btnPrint.Bind(wx.EVT_BUTTON, self.OnDoPrint,
              id=wxID_STCPRINTDLGBTNPRINT)

        self.btnCancel = wx.Button(id=wx.ID_CANCEL, label=_('Cancel'),
              name='btnCancel', parent=self, pos=wx.Point(296, 128),
              size=wx.Size(88, 23), style=0)

    def __init__(self, parent, stc, filename=''):
        self._init_ctrls(parent)

        self.stc = stc
        self.filename = filename
        self.parentFrame = parent
        self.preview = None

        self.printData = wx.PrintData()
        self.printData.SetPaperId(wx.PAPER_LETTER)
        self.printData.SetOrientation(wx.PORTRAIT)
        self.margins = (wx.Point(15,15), wx.Point(15,15))

        #self.printData.SetPaperId(wx.PAPER_LETTER)


    def OnPrintSetup(self, event):
        data = wx.PageSetupDialogData()
        data.SetPrintData(self.printData)

        data.SetDefaultMinMargins(True)
        data.SetMarginTopLeft(self.margins[0])
        data.SetMarginBottomRight(self.margins[1])

        dlg = wx.PageSetupDialog(self, data)
        try:
            if dlg.ShowModal() == wx.ID_OK:
                data = dlg.GetPageSetupData()
                self.printData = wx.PrintData(data.GetPrintData()) 
                self.printData.SetPaperId(data.GetPaperId())
                self.margins = (data.GetMarginTopLeft(),
                                data.GetMarginBottomRight())
        finally:
            dlg.Destroy()

    def createSTCPrintout(self):
        colourMode = stcPrintColourModes[self.rdbColourMode.GetSelection()]
        doPageNums = self.ckbPageNumbers.GetValue()
        if self.ckbFilename.GetValue():
            filename = self.filename
        else:
            filename = ''

        return STCPrintout(self.stc, colourMode, filename, doPageNums)

    def OnPrintPreview(self, event):
        printout1 = self.createSTCPrintout()
        printout2 = self.createSTCPrintout()
        self.preview = wx.PrintPreview(printout1, printout2, self.printData)
        if not self.preview.Ok():
            wx.LogError(_('An error occured while preparing preview.'))
            return

        frame = wx.PreviewFrame(self.preview, self.parentFrame, _('Print Preview'))
        frame.Initialize()
        frame.Show(True)


    def OnDoPrint(self, event):
        pdd = wx.PrintDialogData()
        pdd.SetPrintData(self.printData)
        printer = wx.Printer(pdd)
        printout = self.createSTCPrintout()

        if not printer.Print(self.parentFrame, printout):
            wx.LogError(_('An error occured while printing.'))
        else:
            self.printData = wx.PrintData(printer.GetPrintDialogData().GetPrintData())
        printout.Destroy()

        self.EndModal(wx.OK)


#-------------------------------------------------------------------------------

class STCPrintout(wx.Printout):
    margin = 0.1
    linesPerPage = 69

    def __init__(self, stc, colourMode=0, filename='', doPageNums=1):
        wx.Printout.__init__(self)
        self.stc = stc
        self.colourMode = colourMode
        self.filename = filename
        self.doPageNums = doPageNums

        self.pageTotal, m = divmod(stc.GetLineCount(), self.linesPerPage)
        if m: self.pageTotal += 1

##    def OnBeginDocument(self, start, end):
##        return self.base_OnBeginDocument(start, end)
##
##    def OnEndDocument(self):
##        self.base_OnEndDocument()
##
##    def OnBeginPrinting(self):
##        self.base_OnBeginPrinting()
##
##    def OnEndPrinting(self):
##        self.base_OnEndPrinting()
##
##    def OnPreparePrinting(self):
##        self.base_OnPreparePrinting()

    def HasPage(self, page):
        if page <= self.pageTotal:
            return True
        else:
            return False

    def GetPageInfo(self):
        return (1, self.pageTotal, 1, 32000)

    def OnPrintPage(self, page):
        stc = self.stc
        self.stcLineHeight = stc.TextHeight(0)

        # calculate sizes including margin and scale
        dc = self.GetDC()
        dw, dh = dc.GetSizeTuple()

        mw = self.margin*dw
        mh = self.margin*dh
        textAreaHeight = dh - mh*2
        textAreaWidth = dw - mw*2

        scale = float(textAreaHeight)/(self.stcLineHeight*self.linesPerPage)
        dc.SetUserScale(scale, scale)

        # render page titles and numbers
        f = dc.GetFont()
        f.SetFamily(wx.ROMAN)
        f.SetFaceName('Times New Roman')
        f.SetPointSize(f.GetPointSize()+3)
        dc.SetFont(f)

        if self.filename:
            tlw, tlh = dc.GetTextExtent(self.filename)
            dc.DrawText(self.filename,
                  int(dw/scale/2-tlw/2), int(mh/scale-tlh*3))

        if self.doPageNums:
            pageLabel = _('Page: %d') % page
            plw, plh = dc.GetTextExtent(pageLabel)
            dc.DrawText(pageLabel,
                  int(dw/scale/2-plw/2), int((textAreaHeight+mh)/scale+plh*2))

        # render stc into dc
        stcStartPos = stc.PositionFromLine((page-1)*self.linesPerPage)
        stcEndPos = stc.GetLineEndPosition(page*self.linesPerPage-1)

        maxWidth = 32000
        stc.SetPrintColourMode(self.colourMode)
        ep = stc.FormatRange(1, stcStartPos, stcEndPos, dc, dc,
                        wx.Rect(int(mw/scale), int(mh/scale),
                               maxWidth, int(textAreaHeight/scale)),
                        wx.Rect(0, (page-1)*self.linesPerPage*self.stcLineHeight,
                            maxWidth, self.stcLineHeight*self.linesPerPage))

        # warn when less characters than expected is rendered by the stc when
        # printing
        if not self.IsPreview():
            if ep < stcEndPos:
                print _('warning: on page %s: not enough chars rendered, diff:')%(page, stcEndPos-ep)

        return True


#----------------------------------------------------------------------

if __name__ == '__main__':
    testFile = 'STCPrinting.py'
    app = wx.PySimpleApp()
    wx.InitAllImageHandlers()
    frame = wx.Frame(None, -1, '')
    # prepare an stc
    frame.stc = wx.stc.StyledTextCtrl(frame, -1)
    frame.stc.SetText(open(testFile).read())
    config = os.path.abspath('../Config/stc-styles.rc.cfg')
    from STCStyleEditor import initSTC
    initSTC(frame.stc, config, 'python')
    # print dlg for prepared stc
    dlg = STCPrintDlg(frame, frame.stc, testFile)
    try:
        dlg.ShowModal()
    finally:
        dlg.Destroy()
    wx.CallAfter(frame.Destroy)
    app.MainLoop()
