/*
 * Xailer source code:
 *
 * Printer.prg
 * Clase TPrinter
 *
 * Copyright 2003, 2007 Ignacio Ortiz de Zuņiga
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"

STATIC aEmf := {}

//--------------------------------------------------------------------------

CLASS XPrinter FROM TComponent

PUBLISHED:
   PROPERTY oPrnDlg        AS TPrintDlg
   PROPERTY oPageSetupDlg  AS TPageSetupDlg
   PROPERTY oWndOwner      AS TForm
   PROPERTY oCanvas        AS TCanvas
   PROPERTY aPrinterNames  INIT {}  READONLY
   PROPERTY cJobTitle
   PROPERTY cPrinterName   INIT ""  READONLY
   PROPERTY nPaperSizeType INIT 0   READ METHOD PaperSizeType  WRITE INLINE ::PaperSizeType( Value ), ::Reset()
   PROPERTY nPaperLength   INIT 0   READ METHOD PaperLength    WRITE INLINE ::PaperLength( Value ), ::Reset()
   PROPERTY nPaperWidth    INIT 0   READ METHOD PaperWidth     WRITE INLINE ::PaperWidth( Value ), ::Reset()
   PROPERTY nCopies        INIT 0   READ METHOD Copies         WRITE INLINE ::Copies( Value ), ::Reset()
   PROPERTY nDefaultBin    INIT 0   READ METHOD DefaultBin     WRITE INLINE ::DefaultBin( Value ), ::Reset()
   PROPERTY nColor         INIT 0   READ METHOD Color          WRITE INLINE ::Color( Value ), ::Reset()
   PROPERTY nDuplex        INIT 0   READ METHOD Duplex         WRITE INLINE ::Duplex( Value ), ::Reset()
   PROPERTY nPrinterIndex  INIT 0   READ METHOD PrinterIndex   WRITE INLINE ::PrinterIndex( Value ), ::Reset()
   PROPERTY nStatus        INIT 0   READ METHOD Status
   PROPERTY nPDFPrinter    INIT 0
   PROPERTY nPDFDirect     INIT 0

   PROPERTY nOrientation   INIT 0 ;
                           VALUES poPORTRAIT, poLANDSCAPE ;
                           READ METHOD Orientation ;
                           WRITE INLINE ( ::Orientation( Value ), ::Reset() )

   PROPERTY nPrintQuality  INIT 0 ;
                           VALUES pqHIGH, pqMEDIUM, pqLOW, pqDRAFT ;
                           READ METHOD PrintQuality  ;
                           WRITE INLINE ( ::PrintQuality( Value ), ::Reset() )

   PROPERTY nPreviewShowMode INIT smNORMAL ;
                             VALUES smNORMAL, smMAXIMIZE, smMINIMIZE
   PROPERTY nPageNumber    INIT 0

   PROPERTY lCollate       INIT .F. READ METHOD Collate  WRITE INLINE ::Collate( Value ), ::Reset()
   PROPERTY lPreview       INIT .F.
   PROPERTY lPreviewModal  INIT .T.
   PROPERTY lKeepWithNext  INIT .F.

RESERVED:
   DATA lOnPage INIT .F.

PUBLIC:
   PROPERTY oPreviewDC  AS TPreviewDC
   CLASSDATA oExportInfo //AS TExportInfo

   DATA hDC             INIT 0   READONLY
   DATA cPort           INIT ""  READONLY
   DATA lAborted        INIT .F. READONLY
   DATA cPdfFilename    INIT ""

   METHOD Initialize() CONSTRUCTOR
   METHOD Create()     CONSTRUCTOR
   METHOD Destroy() // --> Nil

   METHOD GetPrinterFonts() // --> aFonts
   METHOD Setup( oForm ) // --> lResult
   METHOD PageSetup( oForm ) // --> Nil
   METHOD DocumentSetup( oForm ) // --> Nil
   METHOD Run( oForm ) // --> lSuccess
   METHOD Preview( nShowMode, lModal, oParent )  // --> Nil
   METHOD Port() // --> cPort
   METHOD ServerName() // --> cServer
   METHOD ShareName() // --> cName
   METHOD DriverName() // --> cDriver
   METHOD Location() // --> cLocation
   METHOD Comment() // --> cComment
   METHOD SepFile() // --> cSepFile
   METHOD PrintProcessor() // --> cPrintProcessor
   METHOD Attributes() // --> nAttributes
   METHOD Resolution() // --> aResolution
   METHOD PaperRes() // --> aResolution
   METHOD PaperSize() // --> aSize
   METHOD PaperPhysicalSize() // --> aSize
   METHOD PhysicalOffset() // --> aOffset
   METHOD IsPrinting() INLINE !Empty( ::oCanvas ) // --> lResult

   METHOD CanPrintToPdf()  INLINE !Empty( ::nPDFDirect )  // --> lCanPrintToPdf
   METHOD StartDocPdf( cOutput, cJobTitle, oWndOwner ) // --> lSuccess

   METHOD StartDoc( cJobTitle, oWndOwner, hDC, cOutput ) // --> lSuccess
   METHOD EndDoc() // --> Nil
   METHOD AbortDoc() // --> lSuccess
   METHOD StartPage() // --> lSuccess
   METHOD EndPage() // --> lSuccess

   METHOD GetPaperNames() // --> aNames
   METHOD GetPaperTypes() // --> aTypes
   METHOD GetPaperSizes() // --> aSizes
   METHOD CountPapers() // --> nCount

   METHOD GetBinSourceNames() // --> aNames
   METHOD GetBinSourceTypes() // --> aTypes
   METHOD CountBinSources() // --> nCount

   METHOD GetResolutions() // --> aResolutions
   METHOD IsDuplex() // --> lResult

   METHOD WriteData( cData, cDocument ) // --> lSuccess
   METHOD EmfToPrinter( nPrinter, nFirst, nLast )

   EVENT OnPreview( oSender, nShowMode, lModal, oParent ) // --> lResult

   METHOD PreviewForm( oParent )
   METHOD PreviewControl( oForm, oDC )
   METHOD PrintingForm( oParent, oReport, lExcel )

RESERVED:
   METHOD CreateDC()              INLINE ::hDC := PrinterCreateDC()
   METHOD DeleteDC()              INLINE ( PrinterDeleteDC( ::hDC ), ::hDC := 0 )

   METHOD Reset()
   METHOD GetPrinterNames()
   METHOD GetPrinterDefault()
   METHOD Orientation( Value )
   METHOD PaperSizeType( Value )
   METHOD PaperLength( Value )
   METHOD PaperWidth( Value )
   METHOD PrinterIndex( nIndex )
   METHOD Copies( Value )
   METHOD DefaultBin( Value )
   METHOD Color( Value )
   METHOD Duplex( Value )
   METHOD Collate( Value )
   METHOD PrintQuality( Value )
   METHOD Status()
   METHOD PreviewPages() INLINE aEmf

ENDCLASS

//--------------------------------------------------------------------------

METHOD Initialize() CLASS XPrinter

   IF ValType( Printer ) != "O"
      Printer := Self
      ::Create()
   ELSE
      Self := Printer
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Create() CLASS XPrinter

   IF PrinterInit()
      ::aPrinterNames := ::GetPrinterNames()
      ::cPrinterName  := ::GetPrinterDefault()
      ::cPort         := ::Port()
      IF ! Empty( ::cPrinterName )
         ::nPrinterIndex := Ascan( ::aPrinterNames, {|v| v == ::cPrinterName } )
      ENDIF
      ::nPDFDirect := ::nPDFPrinter := Ascan( ::aPrinterNames, {|v| v == "Microsoft Print to PDF" } )
      IF ::nPDFPrinter == 0
         ::nPDFPrinter := Ascan( ::aPrinterNames, {|v| "PDF" $ Upper( v ) } )
      ENDIF
      IF ::nPDFDirect == 0
         ::nPDFDirect := Ascan( ::aPrinterNames, {|v| "PDF ARCHITECT" $ Upper( v ) } )
      ENDIF

   ENDIF

   IF ::oExportInfo == NIL
      ::oExportInfo := TPrnExportInfo():New( Self )
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Destroy() CLASS XPrinter

   IF ::oPrnDlg != Nil
      ::oPrnDlg:Destroy()
   ENDIF

   IF ! Empty( ::hDC )
      ::EndDoc()
   ENDIF

   PrinterEnd()

RETURN Self

//--------------------------------------------------------------------------

METHOD PrinterIndex( nIndex ) CLASS XPrinter

   IF nIndex == Nil .OR. nIndex < 1 .OR. nIndex > Len( ::aPrinterNames )
      nIndex := 0
   ENDIF

   IF nIndex != 0
      ::FnPrinterIndex := PrinterIndex( nIndex )
   ELSE
      ::FnPrinterIndex := PrinterIndex()
   ENDIF

   IF ::FnPrinterIndex != 0 .AND. ::FnPrinterIndex <= Len( ::aPrinterNames )
      ::cPrinterName := ::aPrinterNames[ ::FnPrinterIndex ]
   ELSE
      ::cPrinterName := ""
   ENDIF

RETURN ::FnPrinterIndex

//--------------------------------------------------------------------------

METHOD Setup( oForm ) CLASS XPrinter

   LOCAL lOld, lRet

   IF ::oPrnDlg == Nil
      ::oPrnDlg := TPrintDlg():Create( oForm )
   ENDIF

   lOld := ::oPrnDlg:lPrintSetup
   lRet := .F.

   ::oPrnDlg:lPrintSetup := .T.

   IF ::oPrnDlg:Run()
      ::FnCopies  := ::oPrnDlg:nCopies
      ::FlCollate := ::oPrnDlg:lCollate
      ::PrinterIndex()
      IF ! Empty( ::oPrnDlg:hDC )
         ::StartDoc( , oForm, ::oPrnDlg:hDC )
      ENDIF
      lRet := .T.
   ENDIF

   ::oPrnDlg:lPrintSetup := lOld

RETURN lRet

//--------------------------------------------------------------------------

METHOD PageSetup( oForm ) CLASS XPrinter

   IF ::oPageSetupDlg == Nil
      ::oPageSetupDlg := TPageSetupDlg():Create( oForm )
   ENDIF

RETURN ::oPageSetupDlg:Run()

//--------------------------------------------------------------------------

METHOD Run( oForm ) CLASS XPrinter

   LOCAL lOld, lRet

   IF ::oPrnDlg == Nil
      ::oPrnDlg := TPrintDlg():Create( oForm )
   ELSE
      ::oPrnDlg:nCopies := ::nCopies
   ENDIF

   lOld := ::oPrnDlg:lPrintSetup
   lRet := .F.

   ::oPrnDlg:lPrintSetup := .F.

   IF ::oPrnDlg:Run()
      ::FnCopies  := ::oPrnDlg:nCopies
      ::FlCollate := ::oPrnDlg:lCollate
      ::PrinterIndex()
      IF ! Empty( ::oPrnDlg:hDC )
         ::StartDoc( , oForm, ::oPrnDlg:hDC )
      ENDIF
      lRet := .T.
   ENDIF

   ::oPrnDlg:lPrintSetup := lOld

RETURN lRet

//--------------------------------------------------------------------------

METHOD StartDocPdf( cOutput, cJobTitle, oWndOwner ) CLASS XPrinter

   IF !Empty( ::nPDFDirect )

      IF !Empty( cOutput )
         ::cPdfFilename := cOutput
      ELSEIF !Empty( ::cPdfFilename )
         cOutput := ::cPdfFilename
      ENDIF

      ::nPrinterIndex := ::nPDFDirect

      RETURN ::StartDoc( cJobTitle, oWndOwner,, cOutput )

   ENDIF

RETURN .F.

//--------------------------------------------------------------------------

METHOD StartDoc( cJobTitle, oWndOwner, hDC, cOutput ) CLASS XPrinter

   LOCAL lRet

   DEFAULT oWndOwner TO GetControlFromHandle( GetActiveWindow() )

   UPDATE ::cJobTitle TO cJobTitle
   UPDATE ::oWndOwner TO oWndOwner

   IF Empty( ::cJobTitle )
      ::cJobTitle := Application:cTitle
   ENDIF

   ::EndDoc()

   ::lAborted := .F.

   IF !::lKeepWithNext
      ::nPageNumber := 0
   ENDIF

   IF ::lPreview
      IF ::oPreviewDC != NIL .AND. !Empty( ::oPreviewDC:hPrinterDC )
         ::oPreviewDC:Destroy( .T. )
      ENDIF
      ::oPreviewDC  := TPreviewDC():Create( Self, hDC, ::nPrinterIndex )
      ::oCanvas     := TCanvas():New( Self )
      ::oCanvas:hDC := ::oPreviewDC:hPrinterDC
      lRet          := .T.
   ELSE
      IF Empty( hDC )
         ::hDC      := PrinterCreateDC()
      ELSE
         ::hDC      := hDC
      ENDIF
      ::oCanvas     := TCanvas():New( Self )
      lRet          := PrinterStartDoc( ::hDC, ::cJobTitle, cOutput )
      ::oCanvas:hDC := ::hDC
   ENDIF

RETURN lRet

//--------------------------------------------------------------------------

METHOD EndDoc() CLASS XPrinter

   LOCAL lRet

   IF ! ::IsPrinting()
      RETURN .F.
   ENDIF

   IF ::lPreview
      lRet := ( ::oPreviewDC != Nil .AND. Len( aEmf ) > 0 )
   ELSE
      lRet := PrinterEndDoc( ::hDC )
   ENDIF

   ::oCanvas:Destroy()
   ::oCanvas := Nil
   ::hDC     := 0

   IF ::nPrinterIndex == ::nPDFDirect
      ::cPdfFilename := ""
      ::cPrinterName := ::GetPrinterDefault()
      IF ! Empty( ::cPrinterName )
         ::nPrinterIndex := Ascan( ::aPrinterNames, {|v| v == ::cPrinterName } )
      ENDIF
   ENDIF

RETURN lRet

//--------------------------------------------------------------------------

METHOD AbortDoc() CLASS XPrinter

   IF ! ::IsPrinting()
      RETURN .F.
   ENDIF

   ::lAborted := .T.

RETURN PrinterAbortDoc( ::hDC )

//--------------------------------------------------------------------------

METHOD StartPage() CLASS XPrinter

   LOCAL lRet := .F.

   IF ::lOnPage
      ::EndPage()
   ENDIF

   ::nPageNumber++

   IF ::lPreview
      ::hDC := ::oPreviewDC:StartPage()
      lRet  := ( ::hDC != 0 )
      ::oCanvas:hDC := ::hDC
   ELSEIF ! Empty( ::hDC )
      lRet := PrinterStartPage( ::hDC )
   ENDIF

   ::lOnPage := lRet

RETURN lRet

//--------------------------------------------------------------------------

METHOD EndPage() CLASS XPrinter

   LOCAL lRet := .F.

   IF ! ::lOnPage
      RETURN .F.
   ENDIF

   IF ::lPreview
      lRet  := ::oPreviewDC:EndPage()
      ::hDC := 0
      ::oCanvas:hDC := ::oPreviewDC:hPrinterDC
   ELSEif ! Empty( ::hDC )
      lRet := PrinterEndPage( ::hDC )
   ENDIF

   ::lOnPage := !lRet

RETURN lRet

//--------------------------------------------------------------------------

METHOD Preview( nShowMode, lModal, oParent ) CLASS XPrinter

   LOCAL oForm, oPreview
   LOCAL lRet

   IF Empty( ::oPreviewDC ) .OR. Len( aEmf ) == 0
      RETURN .F.
   ENDIF

   IF ::lKeepWithNext
      RETURN .T.
   ENDIF

   IF Valtype( lRet := ::OnPreview( nShowMode, lModal, oParent ) ) == "L" .AND. ! lRet
      RETURN .T.
   ENDIF

   DEFAULT lModal    TO ::lPreviewModal
   DEFAULT nShowMode TO ::nPreviewShowMode
   DEFAULT oParent   TO Application:oMainForm

   oForm    := ::PreviewForm( oParent )
   oPreview := ::PreviewControl( oForm, ::oPreviewDC )

   oForm:OnClose  := {|| ::oPreviewDC:Destroy( .F. ) }

   IF lModal
      oForm:ShowModal( nShowMode, .T. )
   ELSE
      oForm:Show( nShowMode, .T.)
   ENDIF

RETURN .T.

//--------------------------------------------------------------------------

METHOD PreviewForm( oParent ) CLASS XPrinter

   LOCAL oForm

   WITH OBJECT oForm := TForm():New( oParent )
      :cText     := ::cJobTitle
      :nWidth    := 800
      :nHeight   := 600
      :lCentered := .T.
      :Create()
   END WITH

RETURN oForm

//--------------------------------------------------------------------------

METHOD PreviewControl( oForm, oDC ) CLASS XPrinter

   LOCAL oPreview

   WITH OBJECT oPreview := TPreviewControl():New( oForm )
      :oPreviewDC := oDC
      :nAlign := alCLIENT
      :Create()
   END

RETURN oPreview

//--------------------------------------------------------------------------

METHOD PrintingForm( oParent, oReport, lExcel ) CLASS XPrinter

   LOCAL oFrm, oGroupBox, oFont, oBevel1, oBevel2, oBevel3
   LOCAL lState

   REDECLARE oReport AS CLASS TReport

   lState := oParent:lEnabled
   oParent:lEnabled := .F.

   WITH OBJECT oFrm := TForm():New()
      :SetClientSize( 400, 200 )
      :lCentered := .T.
      :cText := Application:cTitle
      :nBorderStyle := bsDIALOG
      :OnClose := {|| oParent:lEnabled := lState, oFrm := NIL, NIL }
      :Create()
   END WITH

   WITH OBJECT oBevel1 := TBevel():New( oFrm )
      :SetBounds( 0, 147, 450, 75 )
      :nAlign := alBOTTOM
      :nAlignMarginTop := 10
      :nBorderStyle := bvNONE
      :Create()
   END

   WITH OBJECT TButton():New( oBevel1 )
      :SetBounds( 90, 20, 270, 45 )
      :cText := "Button1"
      :nAlign := alCLIENT
      :nAlignMarginLeft := 90
      :nAlignMarginTop := 20
      :nAlignMarginRight := 90
      :nAlignMarginBottom := 20
      :cText   := LT( XA_MSG_PRINT_STOP_PRINTING )
      :OnClick := {|| oReport:lCancel := .T. }
      :Create()
   END

   WITH OBJECT oGroupBox := TGroupBox():New( oFrm )
      :SetBounds( 10, 10, 430, 127 )
      :cText := LT( XA_MSG_PRINT_PRINTING )
      :nAlign := alCLIENT
      :nAlignMarginLeft := 10
      :nAlignMarginTop := 10
      :nAlignMarginRight := 10
      :Create()
   END

   WITH OBJECT oBevel2 := TBevel():New( oGroupBox )
      :SetBounds( 5, 30, 65, 47 )
      :nAlign := alLEFT
      :nAlignMarginLeft := 5
      :nAlignMarginTop := 30
      :nAlignMarginBottom := 50
      :nBorderStyle := bvNONE
      :Create()
   END

   WITH OBJECT TImage():New( oBevel2 )
      :SetBounds( 0, 0, 65, 47 )
      :nAlign := alCLIENT
      :lTransparent := .T.
      :nBorderStyle := bvNONE
      IF !lExcel
         :oPicture := "XA_BMP_PRINTER"
      ELSE
         :oPicture := "XA_BMP_EXCEL"
      ENDIF
      :lAutoFit := .T.
      :Create()
   END

   WITH OBJECT oBevel3 := TBevel():New( oGroupBox )
      :SetBounds( 75, 30, 350, 87 )
      :nAlign := alCLIENT
      :nAlignMarginLeft := 5
      :nAlignMarginTop := 30
      :nAlignMarginRight := 5
      :nAlignMarginBottom := 10
      :nBorderStyle := bvNONE
      :Create()
   END

   WITH OBJECT TLabelEx():New( oBevel3 )
      :SetBounds( 0, 0, 350, 34 )
      :cText := LT( XA_MSG_PRINT_JOB_NAME ) + ": <b>" + oReport:cJobName + "</b>"
      :lMultiLine := .F.
      IF !lExcel
         :nAlign := alTOP
      ELSE
         :nAlign := alCLIENT
         :nVAlignment := vaCENTER
      ENDIF
      :Create()
   END

   IF !lExcel
      WITH OBJECT oReport:oLblPage := TLabelEx():New( oBevel3 )
         :SetBounds( 0, 34, 350, 53 )
         :cText := LT( XA_MSG_PRINT_ACTUAL_PAGE ) + ;
                   ": <b>" + Transform( oReport:nGenPage, "@E 999,999" ) + "</b>"
         :nAlign := alCLIENT
         :nVAlignment := vaCENTER
         :Create()
      END
   ENDIF

RETURN oFrm

//--------------------------------------------------------------------------

METHOD Reset() CLASS XPrinter

   IF ::IsPrinting()
      IF ::lOnPage
         ::EndPage()
      ENDIF
      ::oCanvas:Reset()
      IF ::lPreview
         ::oCanvas:hDC := ::oPreviewDC:Reset()
      ELSE
         ::hDC := PrinterResetDC( ::hDC )
         ::oCanvas:hDC := ::hDC
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD EmfToPrinter( nPrinter, nFirst, nLast ) CLASS xPrinter

   LOCAL cPdfFile
   LOCAL nOldPrinter, nFor, nWidth, nHeight, x, y
   LOCAL lOldPreview

   IF !Empty( nPrinter ) .AND. ValType( nPrinter ) == "C"
      cPdfFile := nPrinter
      nPrinter := ::nPDFDirect
   ENDIF

   DEFAULT nPrinter TO ::nPrinterIndex
   DEFAULT nFirst   TO 1
   DEFAULT nLast    TO Len( ::oPreviewDC:aEmf )

   IF nFirst < 1 .OR. nLast > Len( ::oPreviewDC:aEmf ) .OR. nFirst > nLast ;
      .OR. nPrinter < 1 .OR. nPrinter > Len( ::aPrinterNames )
      LogDebug( "TPrinter:EmfToPrinter(): Invalid range or invalid printer" )
		MessageBeep()
		RETURN .F.
	ENDIF

   nOldPrinter := ::nPrinterIndex
   lOldPreview := ::lPreview

   ::lPreview      := .F.
   ::nPrinterIndex := nPrinter

   Application:lBusy := .T.

   IF !Empty( cPdfFile )
      ::StartDocPdf( cPdfFile )
   ELSE
      ::StartDoc()
   ENDIF

   FOR nFor := nFirst TO nLast
      WITH OBJECT ::oPreviewDC:aEmf[ nFor ]
         IF :nWidth > :nHeight
            ::nOrientation := poLANDSCAPE
         ELSE
            ::nOrientation := poPORTRAIT
         ENDIF
      END WITH
      nWidth := GetDeviceCaps( ::hDC, PHYSICALWIDTH )
      nHeight := GetDeviceCaps( ::hDC, PHYSICALHEIGHT )
      ::StartPage()
      IF nWidth / nHeight <= ::oPreviewDC:aEmf[ nFor ]:nWidth / ::oPreviewDC:aEmf[ nFor ]:nHeight
         nHeight := ::oPreviewDC:aEmf[ nFor ]:nHeight * nWidth / ::oPreviewDC:aEmf[ nFor ]:nWidth
         x := 0
         y := ( GetDeviceCaps( ::hDC, PHYSICALHEIGHT ) - nHeight ) / 2
      ELSE
         nWidth := ::oPreviewDC:aEmf[ nFor ]:nWidth * nHeight / ::oPreviewDC:aEmf[ nFor ]:nHeight
         x := ( GetDeviceCaps( ::hDC, PHYSICALWIDTH ) - nWidth ) / 2
         y := 0
      ENDIF
      ::oPreviewDC:aEmf[ nFor ]:Paint( ::hDC, x, y, x + nWidth, y + nHeight )
      ::EndPage()
   NEXT

   ::EndDoc()

   ::lPreview := lOldPreview
   ::nPrinterIndex := nOldPrinter

   Application:lBusy := .F.

RETURN .T.

//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

CLASS XPreviewDC

PUBLIC:
   DATA hDC        INIT 0  READONLY
   DATA hPrinterDC INIT 0  READONLY
//   DATA aEmf       INIT {} READONLY AS TEnhMetaFile
   DATA oPrinter   AS TPrinter
   DATA nPrinterIndex

   METHOD StartPage()
   METHOD EndPage()

   METHOD New( oPrinter )                        CONSTRUCTOR
   METHOD Create( oPrinter, hDC, nPrinterIndex ) CONSTRUCTOR
   METHOD Destroy( lKeepEmf )

   METHOD Reset()
   METHOD aEmf() INLINE aEmf

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oPrinter ) CLASS XPreviewDC
RETURN ::Create( oPrinter )

//--------------------------------------------------------------------------

METHOD Create( oPrinter, hDC, nPrinterIndex ) CLASS XPreviewDC

   UPDATE ::oPrinter TO oPrinter

   ::nPrinterIndex := nPrinterIndex

   IF ! Empty( ::oPrinter )
      IF Empty( hDC )
         ::hPrinterDC := PrinterCreateDC()
      ELSE
         ::hPrinterDC := hDC
      ENDIF
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Destroy( lKeepEmf ) CLASS XPreviewDC

   DEFAULT lKeepEmf TO .F.

   IF ! Empty( ::hDC )
      ::EndPage()
   ENDIF

   IF !lKeepEmf
      AEval( aEmf, {|o| o:Destroy() } )
      aEmf := {}
      ::oPrinter:lKeepWithNext := .F.
      ::oPrinter:nPageNumber := 0
   ENDIF

   IF ! Empty( ::hPrinterDC )
      PrinterDeleteDC( ::hPrinterDC )
      ::hPrinterDC := 0
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD StartPage() CLASS XPreviewDC

   LOCAL oEmf
   LOCAL nPage, nWidth, nHeight

   IF ! Empty( ::hDC )
      ::EndPage()
   ENDIF

   nPage := Len( aEmf ) + 1

   WITH OBJECT ::oPrinter
      nWidth  := :PaperWidth() * 10
      nHeight := :PaperLength() * 10
      oEmf    := TEnhMetaFile():Create( ::hPrinterDC, Nil, nWidth, nHeight, ;
                                        :cJobTitle + " # " + LTrim( Str( nPage ) ) )

   END WITH

   ::hDC := oEmf:hNewDC

   AAdd( aEmf, oEmf )

RETURN ::hDC

//--------------------------------------------------------------------------

METHOD EndPage() CLASS XPreviewDC

   ::hDC := 0

   IF ! Empty( aEmf )
      ATail( aEmf ):Close()
   ENDIF

RETURN .T.

//--------------------------------------------------------------------------

METHOD Reset() CLASS XPreviewDC

   LOCAL nPage := Len( aEmf )

   IF ! Empty( aEmf ) .AND. ! Empty( ::hDC )
      aEmf[ nPage ]:Close()
      aEmf[ nPage ]:Destroy()
      ::hPrinterDC := PrinterResetDC( ::hPrinterDC )
      aEmf[ nPage ] := TEnhMetaFile():Create( ::hPrinterDC, Nil, ;
                                              ::oPrinter:PaperWidth() * 10, ;
                                              ::oPrinter:PaperLength() * 10, ;
                                              ::oPrinter:cJobTitle + " # " + LTrim( Str( nPage ) ) )
      ::hDC := aEmf[ nPage ]:hNewDC
   ELSE
      RETURN ( ::hPrinterDC := PrinterResetDC( ::hPrinterDC ) )
   ENDIF

RETURN ::hDC

//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

CLASS XPrnExportInfo

PUBLIC:
   DATA cImgPDFLicense     INIT ""
   DATA cImgPDFPassword    INIT ""
   DATA lImgPDFButton      INIT .F.
   DATA lImgPdfCanEdit     INIT .F.
   DATA lImgPdfCanCopy     INIT .T.
   DATA lImgPdfCanPrint    INIT .T.
   DATA lMailButton        INIT .F.
   DATA oPrinter           AS TPrinter

   METHOD New( oPrinter )    CONSTRUCTOR
   METHOD Create( oPrinter ) CONSTRUCTOR

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oPrinter ) CLASS XPrnExportInfo

   ::Create( oPrinter )

RETURN Self

//--------------------------------------------------------------------------

METHOD Create( oPrinter ) CLASS XPrnExportInfo

   UPDATE ::oPrinter TO oPrinter

   ::cImgPDFLicense     := ""
   ::cImgPDFPassword    := ""
   ::lImgPDFButton      := .F.
   ::lImgPdfCanEdit     := .F.
   ::lImgPdfCanCopy     := .T.
   ::lImgPdfCanPrint    := .T.
   ::lMailButton        := .F.

RETURN Self


//--------------------------------------------------------------------------

#pragma BEGINDUMP

#include <windows.h>
#include <xailer.h>

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETPAPERNAMES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_PAPERNAMES, NULL, NULL );

   if( wCount )
   {
      char * pBuffer = hb_xgrab( wCount * 64 );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_PAPERNAMES, pBuffer, NULL );

      hb_reta( wCount );

      for( i = 0; i <= wCount; i++ )
         hb_storvc( pBuffer + ( 64 * i ), -1, i + 1 );

      hb_xfree( pBuffer );
   }
   else
      hb_reta( 0 );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETPAPERTYPES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_PAPERS, NULL, NULL );

   if( wCount )
   {
      WORD * pBuffer = hb_xgrab( wCount * sizeof( WORD ) );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_PAPERS, (LPVOID) pBuffer, NULL );

      hb_reta( wCount );

      for( i = 0; i <= wCount; i++ )
         hb_storvnl( pBuffer[ i ], -1, i + 1 );

      hb_xfree( pBuffer );
   }
   else
      hb_reta( 0 );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETPAPERSIZES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   PHB_ITEM pArray = hb_itemArrayNew( 0 );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_PAPERSIZE, NULL, NULL );

   if( wCount )
   {
      POINT * pBuffer = (POINT *) hb_xgrab( wCount * sizeof( POINT ) );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_PAPERSIZE, (LPVOID) pBuffer, NULL );

      for( i = 0; i < wCount; i++ )
      {
         PHB_ITEM pSub = hb_itemArrayNew( 0 );
         PHB_ITEM pWidth = hb_itemPutNL( NULL, pBuffer[ i ].x );
         PHB_ITEM pHeight = hb_itemPutNL( NULL, pBuffer[ i ].y );

         hb_arrayAdd( pSub, pWidth );
         hb_arrayAdd( pSub, pHeight );

         hb_arrayAdd( pArray, pSub );

         hb_itemRelease( pWidth );
         hb_itemRelease( pHeight );
         hb_itemRelease( pSub );
      }

      hb_xfree( pBuffer );
   }

   hb_itemReturnForward( pArray );
   hb_itemRelease( pArray );
   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_COUNTPAPERS )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );

   hb_retnl( DeviceCapabilities( szDevice, szPort, DC_PAPERNAMES, NULL, NULL ) );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETBINSOURCENAMES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_BINNAMES, NULL, NULL );

   if( wCount )
   {
      char * pBuffer = hb_xgrab( wCount * 24 );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_BINNAMES, (LPVOID) pBuffer, NULL );

      hb_reta( wCount );

      for( i = 0; i <= wCount; i++ )
         hb_storvc( pBuffer + ( 24 * i ), -1, i + 1 );

      hb_xfree( pBuffer );
   }
   else
      hb_reta( 0 );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETBINSOURCETYPES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_BINS, NULL, NULL );

   if( wCount )
   {
      WORD * pBuffer = hb_xgrab( wCount * sizeof( WORD ) );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_BINS, (LPVOID) pBuffer, NULL );

      hb_reta( wCount );

      for( i = 0; i <= wCount; i++ )
         hb_storvnl( pBuffer[ i ], -1, i + 1 );

      hb_xfree( pBuffer );
   }
   else
      hb_reta( 0 );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_COUNTBINSOURCES )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );

   hb_retnl( DeviceCapabilities( szDevice, szPort, DC_BINS, NULL, NULL ) );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_GETRESOLUTIONS )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );
   PHB_ITEM pArray = hb_itemArrayNew( 0 );
   WORD wCount;

   wCount = DeviceCapabilities( szDevice, szPort, DC_ENUMRESOLUTIONS, NULL, NULL );

   if( wCount )
   {
      POINT * pBuffer = (POINT *) hb_xgrab( wCount * sizeof( POINT ) );
      WORD i;

      DeviceCapabilities( szDevice, szPort, DC_ENUMRESOLUTIONS, (LPVOID) pBuffer, NULL );

      for( i = 0; i < wCount; i++ )
      {
         PHB_ITEM pSub = hb_itemArrayNew( 0 );
         PHB_ITEM pWidth = hb_itemPutNL( NULL, pBuffer[ i ].x );
         PHB_ITEM pHeight = hb_itemPutNL( NULL, pBuffer[ i ].y );

         hb_arrayAdd( pSub, pWidth );
         hb_arrayAdd( pSub, pHeight );

         hb_arrayAdd( pArray, pSub );

         hb_itemRelease( pWidth );
         hb_itemRelease( pHeight );
         hb_itemRelease( pSub );
      }

      hb_xfree( pBuffer );
   }

   hb_itemReturnForward( pArray );
   hb_itemRelease( pArray );
   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XPRINTER_ISDUPLEX )
{
   PHB_ITEM Self   = hb_stackSelfItem();
   char * szDevice = XA_ObjGetCBuf( Self, "cPrinterName" );
   char * szPort   = XA_ObjGetCBuf( Self, "cPort" );

   hb_retl( DeviceCapabilities( szDevice, szPort, DC_DUPLEX, NULL, NULL ) );

   XA_FreeCBuf( szDevice );
   XA_FreeCBuf( szPort );
}

#pragma ENDDUMP

//--------------------------------------------------------------------------
