1 {
2  /***************************************************************************
3                                 Printers.pas
4                                 ------------
5                             Basic Printer object
6 
7  ****************************************************************************/
8 
9  *****************************************************************************
10   This file is part of the Lazarus Component Library (LCL)
11 
12   See the file COPYING.modifiedLGPL.txt, included in this distribution,
13   for details about the license.
14  *****************************************************************************
15 
16   Author: Olivier Guilbaud
17 }
18 unit Printers;
19 
20 {$mode objfpc}{$H+}
21 
22 interface
23 
24 uses
25   Classes, SysUtils, LCLProc, Graphics;
26 type
27   TPrinter = Class;
28   EPrinter = class(Exception);
29 
30   TPrinterOrientation = (poPortrait,poLandscape,poReverseLandscape,poReversePortrait);
31   TPrinterCapability  = (pcCopies, pcOrientation, pcCollation);
32   TPrinterCapabilities= Set of TPrinterCapability;
33   TPrinterState       = (psNoDefine,psReady,psPrinting,psStopped);
34   TPrinterType        = (ptLocal,ptNetWork);
35 
36   {
37    This object it's a base class for TCanvas for TPrinter Object.
38    Few properties it's replicate for can create an TPrinterCavas not
39    associated with TPrinter or override few values.
40 
41    BeginDoc,NewPage and EndDoc it's called in Printer.BeginDoc ...
42 
43    PaperWidth:  physical width of paper
44    PaperHeight: Physical height of paper
45    PageWidth:   Printable width on page
46    PageHeight:  Printable height of paper
47   }
48 
49   { TPrinterCanvas }
50 
51   TPrinterCanvas = class(TCanvas)
52   private
53     fPrinter      : TPrinter;
54     fTitle        : String;
55     fPageNum      : Integer;
56     fTopMargin    : Integer;
57     fLeftMargin   : Integer;
58     fBottomMargin : Integer;
59     fRightMargin  : Integer;
60     fPaperWidth   : Integer;
61     fPaperHeight  : Integer;
62     fOrientation  : TPrinterOrientation;
63     fXDPI,fYDPI    : Integer;
64 
GetOrientationnull65     function GetOrientation: TPrinterOrientation;
GetPageHeightnull66     function GetPageHeight: Integer;
GetPageWidthnull67     function GetPageWidth: Integer;
GetPaperHeightnull68     function GetPaperHeight: Integer;
GetPaperWidthnull69     function GetPaperWidth: Integer;
GetTitlenull70     function GetTitle: string;
GetXDPInull71     function GetXDPI: Integer;
GetYDPInull72     function GetYDPI: Integer;
73     procedure SetOrientation(const AValue: TPrinterOrientation);
74     procedure SetPaperHeight(const AValue: Integer);
75     procedure SetPaperWidth(const AValue: Integer);
76     procedure SetTitle(const AValue: string);
HasDefaultMarginsnull77     function HasDefaultMargins: boolean;
78     procedure SetXDPI(const AValue: Integer);
79     procedure SetYDPI(const AValue: Integer);
80   protected
GetLeftMarginnull81     function GetLeftMargin: Integer;
GetTopMarginnull82     function GetTopMargin: Integer;
GetBottomMarginnull83     function GetBottomMargin: Integer;
GetRightMarginnull84     function GetRightMargin: Integer;
85   public
86     constructor Create(APrinter: TPrinter); virtual;
87     procedure BeginDoc; virtual;
88     procedure NewPage;  virtual;
89     procedure BeginPage; virtual;
90     procedure EndPage; virtual;
91     procedure EndDoc; virtual;
92     procedure Changing; override;
93 
94     property Printer : TPrinter read fPrinter;
95 
96     property Title : string read GetTitle write SetTitle;
97     property PageHeight : Integer read GetPageHeight;
98     property PageWidth  : Integer read GetPageWidth;
99     property PaperWidth : Integer read GetPaperWidth write SetPaperWidth;
100     property PaperHeight: Integer read GetPaperHeight write SetPaperHeight;
101     property PageNumber : Integer read fPageNum;
102     property TopMargin : Integer read GetTopMargin write FTopMargin;
103     property LeftMargin: Integer read GetLeftMargin write FLeftMargin;
104     property BottomMargin: Integer read GetBottomMargin write FBottomMargin;
105     property RightMargin: Integer read GetRightMargin write FRightMargin;
106     property Orientation: TPrinterOrientation read GetOrientation Write SetOrientation;
107     property XDPI: Integer read GetXDPI write SetXDPI;
108     property YDPI: Integer read GetYDPI write SetYDPI;
109 
110   end;
111 
112   TPrinterCanvasRef = Class of TPrinterCanvas;
113 
114   { TFilePrinterCanvas }
115 
116   TFilePrinterCanvas = class(TPrinterCanvas)
117   protected
118     FOutputFileName: string;
119   public
120     property OutputFileName : string read FOutputFileName write FOutputFileName;
121   end;
122 
123   TFilePrinterCanvasClass = class of TFilePrinterCanvas;
124 
125   TPaperRect = Record
126     PhysicalRect : TRect;
127     WorkRect     : TRect;
128   end;
129 
130   TPaperItem = record
131     PaperName: string[40];
132     PaperRect: TPaperRect;
133   end;
134 
135   { TPaperSize }
136 
137   TPaperSize = Class(TObject)
138   private
139     //The width and length are in points;
140     //there are 72 points per inch.
141 
142     fOwnedPrinter      : TPrinter;
143     fSupportedPapers   : TStringList;  //List of Paper supported by the current printer
144     fLastPrinterIndex  : Integer;      //Last index of printer used
145 
GetDefaultPaperNamenull146     function GetDefaultPaperName: string;
GetPhysPaperHeightnull147     function GetPhysPaperHeight: Integer;
GetPaperNamenull148     function GetPaperName: string;
GetPaperRectnull149     function GetPaperRect: TPaperRect;
GetPhysPaperWidthnull150     function GetPhysPaperWidth: Integer;
GetSupportedPapersnull151     function GetSupportedPapers: TStrings;
152     procedure SetPaperName(const AName: string);
PaperRectOfNamenull153     function PaperRectOfName(const AName: string) : TPaperRect;
154     procedure CheckSupportedPapers;
155   private
156     fInternalPapers    : array of TPaperItem;
157     fDefaultPapers     : boolean;
158     fDefaultPaperIndex : Integer;
159     procedure CreateInternalPapers;
160     procedure FillDefaultPapers;
GetDefaultPaperRectnull161     function GetDefaultPaperRect(const AName: string; var APaperRect:TPaperRect): Integer;
IndexOfDefaultPapernull162     function IndexOfDefaultPaper(const AName: string): Integer;
163   public
164     constructor Create(aOwner : TPrinter); overload;
165     destructor Destroy; override;
166 
167     property DefaultPapers   : boolean read fDefaultPapers;
168     property Width           : Integer read GetPhysPaperWidth;
169     property Height          : Integer read GetPhysPaperHeight;
170     property PaperName       : string read GetPaperName write SetPaperName;
171     property DefaultPaperName: string read GetDefaultPaperName;
172 
173     property PaperRect       : TPaperRect read GetPaperRect;
174     property SupportedPapers : TStrings read GetSupportedPapers;
175 
176     property PaperRectOf[aName : string] : TPaperRect read PaperRectOfName;
177   end;
178 
179   TPrinterFlags = set of
180     (
181       pfPrinting,                //Printing
182       pfAborted,                 //Abort  process
183       pfDestroying,              //Printer object is being destroyed
184       pfPrintersValid,           //fPrinters list is valid
185       pfRawMode                  //Printer is in raw mode
186     );
187 
188   { TPrinter }
189 
190   TPrinter = class(TObject)
191   private
192     fCanvas      : TCanvas;      //Active canvas object
193     FFileName    : string;       //Filename for output file
194     fFonts       : TStrings;     //Accepted font by printer
195     fPageNumber  : Integer;      //Current page number
196     fPrinters    : TStrings;     //Printers names list
197     fPrinterIndex: Integer;      //selected printer index
198     fTitle       : string;       //Title of current document
199     //fCapabilities: TPrinterCapabilities;
200     fPaperSize   : TPaperSize;
201     fCanvasClass : TPrinterCanvasRef;
202     fBins        : TStrings;
203     fFlags       : TPrinterFlags;
204 
GetAbortednull205     function GetAborted: Boolean;
GetCanvasnull206     function GetCanvas: TCanvas;
207     procedure CheckPrinting(Value: Boolean);
GetCanvasClassnull208     function GetCanvasClass: TPrinterCanvasRef;
GetCopiesnull209     function GetCopies: Integer;
GetFontsnull210     function GetFonts: TStrings;
GetOrientationnull211     function GetOrientation: TPrinterOrientation;
GetPageHeightnull212     function GetPageHeight: Integer;
GetPageWidthnull213     function GetPageWidth: Integer;
GetPaperSizenull214     function GetPaperSize: TPaperSize;
GetBinNamenull215     Function GetBinName: string;
GetDefaultBinNamenull216     function GetDefaultBinName: string;
GetPrinterIndexnull217     function GetPrinterIndex: integer;
GetPrinterNamenull218     function GetPrinterName: string;
GetPrintersnull219     function GetPrinters: TStrings;
GetPrintingnull220     function GetPrinting: Boolean;
GetRawModenull221     function GetRawMode: boolean;
222     procedure SetCanvasClass(const AValue: TPrinterCanvasRef);
223     procedure SetCopies(AValue: Integer);
224     procedure SetOrientation(const AValue: TPrinterOrientation);
225     procedure SetPrinterIndex(AValue: integer);
226     procedure SetRawMode(const AValue: boolean);
227     procedure SetBinName(const aName: string);
228   protected
229      procedure SelectCurrentPrinterOrDefault;
230 
231      procedure DoBeginDoc; virtual;
232      procedure DoNewPage; virtual;
233      procedure DoBeginPage; virtual;
234      procedure DoEndPage; virtual;
235      procedure DoEndDoc(aAborded : Boolean); virtual;
236      procedure DoAbort; virtual;
237      procedure DoResetPrintersList; virtual;
238      procedure DoResetFontsList; virtual;
239 
240      procedure DoEnumPrinters(Lst : TStrings); virtual;
241      procedure DoEnumFonts(Lst : TStrings); virtual;
242      procedure DoEnumPapers(Lst : TStrings); virtual;
243      procedure DoEnumBins(Lst : TStrings); virtual;
244      procedure DoInitialization; virtual;
DoSetPrinternull245      function DoSetPrinter(aName : string): Integer; virtual;
DoGetCopiesnull246      function DoGetCopies : Integer; virtual;
247      procedure DoSetCopies(aValue : Integer); virtual;
DoGetOrientationnull248      function DoGetOrientation: TPrinterOrientation; virtual;
249      procedure DoSetOrientation(aValue : TPrinterOrientation); virtual;
DoGetDefaultPaperNamenull250      function DoGetDefaultPaperName: string; virtual;
DoGetPaperNamenull251      function DoGetPaperName: string; virtual;
252      procedure DoSetPaperName(aName : string); virtual;
DoGetDefaultBinNamenull253      function DoGetDefaultBinName: string; virtual;
DoGetBinNamenull254      function DoGetBinName: string; virtual;
255      procedure DoSetBinName(aName: string); virtual;
DoGetPaperRectnull256      function DoGetPaperRect(aName : string; Var aPaperRc : TPaperRect) : Integer; virtual;
DoGetPrinterStatenull257      function DoGetPrinterState: TPrinterState; virtual;
258      procedure DoDestroy; virtual;
259 
GetPrinterTypenull260      function GetPrinterType : TPrinterType; virtual;
GetCanPrintnull261      function GetCanPrint : Boolean; virtual;
GetCanRenderCopiesnull262      function GetCanRenderCopies : Boolean; virtual;
GetXDPInull263      function GetXDPI: Integer; virtual;
GetYDPInull264      function GetYDPI: Integer; virtual;
GetBinsnull265      function GetBins: TStrings; virtual;
266      procedure CheckRawMode(const Value: boolean; Msg:string='');
267      procedure RawModeChanging; virtual;
268      procedure PrinterSelected; virtual;
DoGetDefaultCanvasClassnull269      function  DoGetDefaultCanvasClass: TPrinterCanvasRef; virtual;
270 
271      property PrinterFlags: TPrinterFlags read fFlags write fFlags;
272   public
273      constructor Create; virtual;
274      destructor Destroy; override;
275 
276      procedure Abort;
277      procedure BeginDoc;
278      procedure EndDoc;
279      procedure NewPage;
280      procedure BeginPage;
281      procedure EndPage;
282      procedure Refresh;
283      procedure SetPrinter(aName : String);
284      Procedure RestoreDefaultBin; virtual;
Writenull285      function  Write(const Buffer; Count:Integer; out Written: Integer): Boolean; virtual;
Writenull286      function  Write(const s: ansistring): boolean; overload;
287 
288      property PrinterIndex : integer read GetPrinterIndex write SetPrinterIndex;
289      property PrinterName: string read GetPrinterName;
290      property PaperSize : TPaperSize read GetPaperSize;
291      property Orientation: TPrinterOrientation read GetOrientation write SetOrientation;
292      property PrinterState : TPrinterState read DoGetPrinterState;
293      property Copies : Integer read GetCopies write SetCopies;
294      property Printers: TStrings read GetPrinters;
295      property FileName: string read FFileName write FFileName;
296      property Fonts: TStrings read GetFonts;
297      property Canvas: TCanvas read GetCanvas;
298      property CanvasClass: TPrinterCanvasRef read GetCanvasClass write SetCanvasClass;
299      property PageHeight: Integer read GetPageHeight;
300      property PageWidth: Integer read GetPageWidth;
301      property PageNumber : Integer read fPageNumber;
302      property Aborted: Boolean read GetAborted;
303      property Printing: Boolean read GetPrinting;
304      property Title: string read fTitle write fTitle;
305      property PrinterType : TPrinterType read GetPrinterType;
306      property CanPrint : Boolean read GetCanPrint;
307      property CanRenderCopies : Boolean read GetCanRenderCopies;
308      property XDPI : Integer read GetXDPI;
309      property YDPI : Integer read GetYDPI;
310      property RawMode: boolean read GetRawMode write SetRawMode;
311      property DefaultBinName: string read GetDefaultBinName;
312      property BinName: string read GetBinName write SetBinName;
313      property SupportedBins: TStrings read GetBins;
314   end;
315 
316 // TPrinter it's an basic object. If you override this object,
317 // you must create an instance.
318 var
319   Printer: TPrinter = nil;
320 
321 implementation
322 
323 { TPrinter }
324 
325 constructor TPrinter.Create;
326 begin
327   if ClassType=TPrinter then
328     raise Exception.Create('TPrinter is an abstract base class.'
329     +' Please use a printer implementation like the package printers4lazarus.');
330   Inherited Create;
331   fPrinterIndex:=-1;  //By default, use the default printer
332   fCanvas:=nil;
333   fPaperSize:=nil;
334   fBins:=nil;
335   fTitle:='';
336 end;
337 
338 destructor TPrinter.Destroy;
339 begin
340   Include(fFlags, pfDestroying);
341   DoDestroy;
342   inherited Destroy;
343 end;
344 
345 //Abort the current document
346 procedure TPrinter.Abort;
347 begin
348   //Check if Printer print otherwise, exception
349   CheckPrinting(True);
350 
351   DoAbort;
352 
353   Include(fFlags, pfAborted);
354   EndDoc;
355 end;
356 
357 //Begin a new document
358 procedure TPrinter.BeginDoc;
359 begin
360   //Check if Printer not printing otherwise, exception
361   CheckPrinting(False);
362 
363   //If not selected printer, set default printer
364   SelectCurrentPrinterOrDefault;
365 
366   Include(fFlags, pfPrinting);
367   Exclude(fFlags, pfAborted);
368   fPageNumber := 1;
369 
370   if not RawMode then begin
371     Canvas.Refresh;
372     TPrinterCanvas(Canvas).BeginDoc;
373   end;
374   //Call the specifique Begindoc
375   DoBeginDoc;
376 
377   BeginPage;
378 
379   // Set font resolution
380   if not RawMode then
381     Canvas.Font.PixelsPerInch := YDPI;
382 end;
383 
384 //End the current document
385 procedure TPrinter.EndDoc;
386 begin
387 
388   EndPage;
389 
390   //Check if Printer print otherwise, exception
391   CheckPrinting(True);
392 
393   if not RawMode then
394     TPrinterCanvas(Canvas).EndDoc;
395 
396   DoEndDoc(pfAborted in fFlags);
397 
398   Exclude(fFlags, pfPrinting);
399   Exclude(fFlags, pfAborted);
400   fPageNumber := 0;
401 end;
402 
403 //Create an new page
404 procedure TPrinter.NewPage;
405 begin
406   if TMethod(@Self.DoNewPage).Code = Pointer(@TPrinter.DoNewPage) then
407   begin
408     // DoNewPage has not been overriden, use the new method
409     EndPage;
410     BeginPage;
411   end else
412   begin
413     // Use the old method as DoNewPage has been overriden in descendat TPrinter
414     CheckPrinting(True);
415     Inc(fPageNumber);
416     if not RawMode then
417       TPrinterCanvas(Canvas).NewPage;
418     DoNewPage;
419   end;
420 end;
421 
422 procedure TPrinter.BeginPage;
423 begin
424   CheckPrinting(True);
425   inc(fPageNumber);
426   if not RawMode then
427     TPrinterCanvas(Canvas).BeginPage;
428   DoBeginPage;
429 end;
430 
431 procedure TPrinter.EndPage;
432 begin
433   if not RawMode then
434     TPrinterCanvas(Canvas).EndPage;
435   DoEndPage;
436 end;
437 
438 //Clear Printers & Fonts list
439 procedure TPrinter.Refresh;
440 var
441   OldPrinter: string;
442 begin
443   //Check if Printer not printing otherwise, exception
444   CheckPrinting(False);
445 
446   if FPrinterIndex>=0 then
447     OldPrinter := fPrinters[FPrinterIndex]
448   else
449     OldPrinter := '';
450 
451   if Assigned(fPrinters) then
452   begin
453     DoResetPrintersList;
454     FreeAndNil(fPrinters);
455   end;
456 
457   if Assigned(fFonts) then
458   begin
459     DoResetFontsList;
460     FreeAndNil(fFonts);
461   end;
462 
463   // need to refill printers here otherwise
464   // it wont be filled on getting printers
465   // due to only one initialization
466   GetPrinters;
467 
468   fPrinterIndex:=-1;
469 
470   // try to locate old selected printer
471   if OldPrinter<>'' then
472     SetPrinter(OldPrinter);
473 end;
474 
475 //Set the current printer
476 procedure TPrinter.SetPrinter(aName: String);
477 var
478   i,oldIndex : Integer;
479 begin
480   if aName='*' then begin
481     // select default printer
482     OldIndex := FPrinterIndex;
483     fPrinterIndex := -1; // avoid to remember last printer
484     Refresh;
485     if Printers.count>0 then begin
486       i:= doSetprinter(FPrinters[0]); // now first printer is default
487       if i<>0 then begin
488         // something went wrong, try to restore old printer
489         if OldIndex>=0 then
490           FPrinterIndex := doSetPrinter(FPrinters[OldIndex]);
491         raise EPrinter.Create('Unable to set default printer!');
492       end else
493         FPrinterIndex := i;
494     end;
495   end else
496   if (Printers.Count>0) then
497   begin
498     if (aName<>'') then
499     begin
500       //Printer changed ?
501       if fPrinters.IndexOf(aName)<>fPrinterIndex then
502       begin
503         i:=DoSetPrinter(aName);
504         if i<0 then
505           raise EPrinter.Create(Format('Printer "%s" doesn''t exist.',[aName]));
506         fPrinterIndex:=i;
507       end;
508     end;
509   end;
510   PrinterSelected;
511 end;
512 
513 procedure TPrinter.RestoreDefaultBin;
514 begin
515   DoSetBinName(DoGetDefaultBinName);
516 end;
517 
Writenull518 function TPrinter.Write(const Buffer; Count: Integer; out Written: Integer): Boolean;
519 begin
520   result := False;
521   Written := 0;
522 end;
523 
Writenull524 function TPrinter.Write(const s: ansistring): boolean;
525 var
526   Written: integer;
527 begin
528   Result := Write(S[1], Length(S), Written);
529 end;
530 
531 //Return an Canvas object
GetCanvasnull532 function TPrinter.GetCanvas: TCanvas;
533 begin
534   Result := nil;
535 
536   CheckRawMode(False, 'Canvas not allowed in Raw Mode');
537 
538   if not Assigned(fCanvas) then
539   begin
540     if not Assigned(CanvasClass) then
541       raise Exception.Create('Canvas Class not defined.');
542 
543     fCanvas:=CanvasClass.Create(Self);
544   end;
545 
546   Result:=fCanvas;
547 end;
548 
GetAbortednull549 function TPrinter.GetAborted: Boolean;
550 begin
551   Result := (pfAborted in fFlags);
552 end;
553 
554 //Raise error if Printer.Printing is not Value
555 procedure TPrinter.CheckPrinting(Value: Boolean);
556 begin
557   if Printing<>Value then
558   begin
559     if Value then
560       raise EPrinter.Create('Printer is not printing')
561     else
562       raise Eprinter.Create('Printer is printing');
563   end;
564 end;
565 
GetCanvasClassnull566 function TPrinter.GetCanvasClass: TPrinterCanvasRef;
567 begin
568   if RawMode then
569     result := nil
570   else
571   if FCanvasClass=nil then
572     Result := DoGetDefaultCanvasClass
573   else
574     Result := FCanvasClass;
575 end;
576 
577 procedure TPrinter.CheckRawMode(const Value: boolean; Msg: string);
578 begin
579   if RawMode<>Value then
580   begin
581     if msg='' then
582       if Value then
583         Msg:='Printer is in Raw Mode'
584       else
585         Msg:='Printer is not in Raw Mode';
586     raise EPrinter.Create(msg);
587   end;
588 end;
589 
590 procedure TPrinter.RawModeChanging;
591 begin
592   //
593 end;
594 
595 procedure TPrinter.PrinterSelected;
596 begin
597 end;
598 
DoGetDefaultCanvasClassnull599 function TPrinter.DoGetDefaultCanvasClass: TPrinterCanvasRef;
600 begin
601   result := TPrinterCanvas;
602 end;
603 
604 //Get current copies number
GetCopiesnull605 function TPrinter.GetCopies: Integer;
606 Var i : Integer;
607 begin
608   Result:=1;
609   i:=DoGetCopies;
610   if i>0 then
611     Result:=i;
612 end;
613 
614 //Return & initialize the Fonts list
GetFontsnull615 function TPrinter.GetFonts: TStrings;
616 begin
617   if not Assigned(fFonts) then
618     fFonts:=TStringList.Create;
619   Result:=fFonts;
620 
621   //Only 1 initialization
622   if fFonts.Count=0 then
623     DoEnumFonts(fFonts);
624 end;
625 
GetOrientationnull626 function TPrinter.GetOrientation: TPrinterOrientation;
627 begin
628   Result:=DoGetOrientation;
629 end;
630 
631 // Returns the height in points (pixels) of printable area
GetPageHeightnull632 function TPrinter.GetPageHeight: Integer;
633 begin
634   Result:=0;
635   if (Printers.Count>0) then
636     with PaperSize.PaperRect.WorkRect do
637       Result:=Bottom-Top;
638 end;
639 
640 // Returns the width in points (pixels) of the printable area
GetPageWidthnull641 function TPrinter.GetPageWidth: Integer;
642 begin
643   Result:=0;
644   if (Printers.Count>0) then
645     with PaperSize.PaperRect.WorkRect do
646       // PageWidth is the size in "pixels" of the printable area
647       Result:=Right-Left;
648 end;
649 
GetPaperSizenull650 function TPrinter.GetPaperSize: TPaperSize;
651 begin
652   if not Assigned(fPaperSize)  then
653     fPaperSize:=TPaperSize.Create(self);
654   Result:=fPaperSize;
655 end;
656 
GetBinNamenull657 function TPrinter.GetBinName: string;
658 begin
659   result := doGetBinName;
660 end;
661 
GetDefaultBinNamenull662 function TPrinter.GetDefaultBinName: string;
663 begin
664   result := doGetDefaultBinName;
665 end;
666 
667 //Return the current selected printer
GetPrinterIndexnull668 function TPrinter.GetPrinterIndex: integer;
669 begin
670   Result:=fPrinterIndex;
671   if (Result<0) and (Printers.Count>0) then
672      Result:=0; //printer by default
673 end;
674 
GetPrinterNamenull675 function TPrinter.GetPrinterName: string;
676 begin
677   if PrinterIndex<0 then
678     result := ''
679   else
680     result := Printers[PrinterIndex];
681 end;
682 
683 //Return & initialize the printers list
GetPrintersnull684 function TPrinter.GetPrinters: TStrings;
685 begin
686   if not Assigned(fPrinters) then
687     fPrinters:=TStringList.Create;
688   Result:=fPrinters;
689 
690   //Only 1 initialization
691   if [pfPrintersValid, pfDestroying]*fFlags = [] then begin
692     Include(fFlags, pfPrintersValid);
693     DoEnumPrinters(fPrinters);
694     if FPrinters.Count>0 then
695       SelectCurrentPrinterOrDefault;
696     DoInitialization;
697   end;
698 end;
699 
GetPrintingnull700 function TPrinter.GetPrinting: Boolean;
701 begin
702   result := (pfPrinting in fFlags);
703 end;
704 
GetRawModenull705 function TPrinter.GetRawMode: boolean;
706 begin
707   result := (pfRawMode in fFlags);
708 end;
709 
710 procedure TPrinter.SetCanvasClass(const AValue: TPrinterCanvasRef);
711 begin
712   FCanvasClass := AValue;
713 end;
714 
715 //Return XDPI
GetXDPInull716 function TPrinter.GetXDPI: Integer;
717 begin
718   Result:=1;
719 end;
720 
721 //Return YDPI
GetYDPInull722 function TPrinter.GetYDPI: Integer;
723 begin
724   Result:=1;
725 end;
726 
GetBinsnull727 function TPrinter.GetBins: TStrings;
728 begin
729   if fBins=nil then
730     fBins := TStringList.Create;
731 
732   doEnumBins(fBins);
733 
734   result := fBins;
735 end;
736 
737 //Set copies number
738 procedure TPrinter.SetCopies(AValue: Integer);
739 begin
740   CheckPrinting(False);
741   if aValue<1 then aValue:=1;
742   if Printers.Count>0 then
743     DoSetCopies(aValue)
744   else
745     raise EPrinter.Create('No printers found.');
746 end;
747 
748 procedure TPrinter.SetOrientation(const AValue: TPrinterOrientation);
749 begin
750   DoSetOrientation(aValue);
751 end;
752 
753 //Set selected printer
754 procedure TPrinter.SetPrinterIndex(AValue: integer);
755 Var aName : String;
756 begin
757   if fPrinterIndex=AValue then exit;
758   CheckPrinting(False);
759   if Printers.Count>0 then
760   begin
761     if AValue=-1 then
762       aName:='*'
763     else
764       if (AValue>=0) and (AValue<Printers.Count) then
765         aName:=Printers.Strings[AValue]
766       else
767         raise EPrinter.Create('Printer index out of range!');
768     SetPrinter(aName);
769     DoResetFontsList;
770   end
771   else
772     raise EPrinter.Create('No printers defined!');
773 end;
774 
775 procedure TPrinter.SetRawMode(const AValue: boolean);
776 begin
777   if AValue<>RawMode then begin
778     CheckPrinting(False);
779     RawModeChanging;
780     if AValue then
781       Include(fFlags, pfRawMode)
782     else
783       Exclude(fFlags, pfRawMode);
784   end;
785 end;
786 
787 procedure TPrinter.SetBinName(const aName: string);
788 begin
789   CheckPrinting(False);
790   DoSetBinName(aName);
791 end;
792 
793 //If not Printer selected, Select the default printer
794 procedure TPrinter.SelectCurrentPrinterOrDefault;
795 begin
796   if (fPrinterIndex<0) and (Printers.Count>0) then
797     PrinterIndex:=0;
798 end;
799 
800 procedure TPrinter.DoBeginDoc;
801 begin
802   //Override this method
803 end;
804 
805 procedure TPrinter.DoNewPage;
806 begin
807   //Override this method
808 end;
809 
810 procedure TPrinter.DoBeginPage;
811 begin
812   //Override this method
813 end;
814 
815 procedure TPrinter.DoEndPage;
816 begin
817   //Override this method
818 end;
819 
820 procedure TPrinter.DoEndDoc(aAborded : Boolean);
821 begin
822   //Override this method
823 end;
824 
825 procedure TPrinter.DoAbort;
826 begin
827  //Override this method
828 end;
829 
830 procedure TPrinter.DoResetPrintersList;
831 begin
832  //Override this method
833   Exclude(fFlags, pfPrintersValid);
834 end;
835 
836 procedure TPrinter.DoResetFontsList;
837 begin
838   if fFonts<>nil then
839     fFonts.Clear;
840 end;
841 
842 //Initialize the Lst with all definied printers
843 procedure TPrinter.DoEnumPrinters(Lst: TStrings);
844 begin
845  //Override this method
846  //Warning: The default printer must be the first printer
847  //          (fPrinters[0])
848 end;
849 
850 //Initialize the Lst with all supported fonts
851 procedure TPrinter.DoEnumFonts(Lst: TStrings);
852 begin
853  //Override this method
854 end;
855 
856 //Initialize the Lst with all supported papers names
857 procedure TPrinter.DoEnumPapers(Lst: TStrings);
858 begin
859   //DebugLn(['TPrinter.DoEnumPapers ',dbgsName(Self)]);
860 
861  //Override this method
862 end;
863 
864 procedure TPrinter.DoEnumBins(Lst : TStrings);
865 begin
866   // Override this method
867 end;
868 
869 // This method is called once after the printer list
870 // is obtained for the first time.
871 procedure TPrinter.DoInitialization;
872 begin
873   //Override this method
874 end;
875 
876 
877 //Set the current printer
DoSetPrinternull878 function TPrinter.DoSetPrinter(aName : string): Integer;
879 begin
880   //Override this method. The result must be
881   //the index of aName printer in Printers list
882   //if the aName doesn't exist, return -1
883   Result:=-1;
884 end;
885 
886 //Get the current copies nulbers
TPrinter.DoGetCopiesnull887 function TPrinter.DoGetCopies: Integer;
888 begin
889  //Override this method
890  Result:=1;
891 end;
892 
893 //Set copies number
894 procedure TPrinter.DoSetCopies(aValue: Integer);
895 begin
896  //Override this method
897 end;
898 
899 //Return current paper orientation
TPrinter.DoGetOrientationnull900 function TPrinter.DoGetOrientation: TPrinterOrientation;
901 begin
902   Result:=poPortrait;
903   //Override this method
904 end;
905 
906 //Set paper Orientation
907 procedure TPrinter.DoSetOrientation(aValue: TPrinterOrientation);
908 begin
909  //Override this method
910 end;
911 
912 //Return the default paper name for the selected printer
TPrinter.DoGetDefaultPaperNamenull913 function TPrinter.DoGetDefaultPaperName: string;
914 begin
915   Result:='';
916   //Override this methode
917 end;
918 
919 //Return selected paper name for the current printer
TPrinter.DoGetPaperNamenull920 function TPrinter.DoGetPaperName: string;
921 begin
922   Result:='';
923   //Override this method
924 end;
925 
926 procedure TPrinter.DoSetPaperName(aName: string);
927 begin
928   //Override this method
929 end;
930 
TPrinter.DoGetDefaultBinNamenull931 function TPrinter.DoGetDefaultBinName: string;
932 begin
933   Result:='';
934 end;
935 
TPrinter.DoGetBinNamenull936 function TPrinter.DoGetBinName: string;
937 begin
938   result := '';
939 end;
940 
941 procedure TPrinter.DoSetBinName(aName: string);
942 begin
943   if SupportedBins.Count>0 then
944     DebugLn('Warning: bin %s is not allowed',[aName]);
945 end;
946 
947 //Initialise aPaperRc with the aName paper rect
948 //Result : -1 no result
949 //          0 aPaperRc.WorkRect is a margins
950 //          1 aPaperRc.WorkRect is really the work rect
DoGetPaperRectnull951 function TPrinter.DoGetPaperRect(aName : string; var aPaperRc: TPaperRect): Integer;
952 begin
953   Result:=-1;
954   //Override this method
955 end;
956 
957 //Get a state of current printer
TPrinter.DoGetPrinterStatenull958 function TPrinter.DoGetPrinterState: TPrinterState;
959 begin
960   //Override this method
961   Result:=psNoDefine;
962 end;
963 
964 procedure TPrinter.DoDestroy;
965 begin
966   if Printing then
967     Abort;
968 
969   fBins.free;
970 
971   if Assigned(fCanvas) then
972     fCanvas.Free;
973 
974   if Assigned(fPaperSize) then
975      fPaperSize.Free;
976 
977 
978   if Assigned(fPrinters) then
979   begin
980     DoResetPrintersList;
981     FreeAndNil(fPrinters);
982   end;
983 
984   if Assigned(fFonts) then
985   begin
986     DoResetFontsList;
987     FreeAndNil(fFonts);
988   end;
989 end;
990 
991 //Return the type of selected printer
GetPrinterTypenull992 function TPrinter.GetPrinterType: TPrinterType;
993 begin
994   Result:=ptLocal;
995 end;
996 
997 //Return True if selected printer is able to print
GetCanPrintnull998 function TPrinter.GetCanPrint: Boolean;
999 begin
1000   Result:=True;
1001 end;
1002 
GetCanRenderCopiesnull1003 function TPrinter.GetCanRenderCopies: Boolean;
1004 begin
1005   Result:=True;
1006 end;
1007 
1008 { TPaperSize }
1009 
1010 procedure TPaperSize.CreateInternalPapers;
1011   procedure add(AnIndex:Integer; aname:string; aPhysRect,aWrkRect:TRect);
1012   begin
1013     with fInternalPapers[AnIndex] do begin
1014       PaperName := aName;
1015       PaperRect.PhysicalRect := aPhysRect;
1016       PaperRect.WorkRect := aWrkRect;
1017     end;
1018   end;
PRRectnull1019   function PRRect(const ALeft,ATop,ARight,ABottom: Integer): TRect;
1020   begin
1021     Result.Left := ALeft;
1022     Result.Top := ATop;
1023     Result.Right  := round(ARight * FOwnedPrinter.XDPI / 72);
1024     Result.Bottom := round(ABottom * FOwnedPrinter.XDPI / 72);
1025   end;
1026 begin
1027   if Length(fInternalPapers)=0 then
1028   begin
1029     SetLength(fInternalPapers, 3);
1030     add(0, 'Letter',    PRRect(0, 0, 612,  792 ), PRRect(0,   0,   612, 792 ));
1031     add(1, 'A4',        PRRect(0, 0, 595,  892 ), PRRect(0,   0,   595, 892 ));
1032     add(2, 'Legal',     PRRect(0, 0, 612,  1008), PRRect(0,   0,   612, 1008));
1033   end;
1034 end;
1035 
1036 procedure TPaperSize.FillDefaultPapers;
1037 var
1038   i: Integer;
1039 begin
1040   FSupportedPapers.Clear;
1041   CreateInternalPapers;
1042   for i:=0 to Length(FInternalPapers)-1 do
1043     FSupportedPapers.Add(FInternalPapers[i].PaperName);
1044   FDefaultPaperIndex := 0;
1045   FDefaultPapers := true;
1046 end;
1047 
TPaperSize.GetDefaultPaperNamenull1048 function TPaperSize.GetDefaultPaperName: string;
1049 begin
1050   CheckSupportedPapers;
1051 
1052   if fDefaultPapers then
1053     Result := FSupportedPapers[0]
1054   else
1055     Result := fOwnedPrinter.DoGetDefaultPaperName;
1056 end;
1057 
TPaperSize.GetDefaultPaperRectnull1058 function TPaperSize.GetDefaultPaperRect(const AName: string;
1059   var APaperRect:TPaperRect): Integer;
1060 var
1061   PR: TPaperRect;
1062 begin
1063   Result := IndexOfDefaultPaper(AName);
1064   if Result>=0 then
1065   PR:=FInternalPapers[Result].PaperRect;
1066   if FOwnedPrinter.Orientation in [poPortrait, poReversePortrait] then
1067   begin
1068     APaperRect.PhysicalRect := PR.PhysicalRect;
1069     APaperRect.WorkRect     := PR.WorkRect;
1070   end else
1071   begin
1072     APaperRect.PhysicalRect.Left   := 0;
1073     APaperRect.PhysicalRect.Top    := 0;
1074     APaperRect.PhysicalRect.Right  := PR.PhysicalRect.Bottom;
1075     APaperRect.Physicalrect.Bottom := PR.PhysicalRect.Right;
1076 
1077     APaperRect.WorkRect.Left   := PR.WorkRect.Top;
1078     APaperRect.WorkRect.Top    := PR.PhysicalRect.Right-PR.WorkRect.Right;
1079     APaperRect.WorkRect.Right  := PR.WorkRect.Bottom;
1080     APaperRect.WorkRect.Bottom := PR.PhysicalRect.Right-PR.Workrect.Left;
1081   end;
1082 end;
1083 
GetPhysPaperHeightnull1084 function TPaperSize.GetPhysPaperHeight: Integer;
1085 begin
1086   result := PaperRect.PhysicalRect.Bottom - PaperRect.PhysicalRect.Top;
1087 end;
1088 
TPaperSize.GetPaperNamenull1089 function TPaperSize.GetPaperName: string;
1090 begin
1091   CheckSupportedPapers;
1092 
1093   if fDefaultPapers then
1094     Result := SupportedPapers[FDefaultPaperIndex]
1095   else
1096     Result := fOwnedPrinter.DoGetPaperName;
1097 
1098   if Result='' then
1099     Result:=DefaultPaperName;
1100 end;
1101 
GetPaperRectnull1102 function TPaperSize.GetPaperRect: TPaperRect;
1103 begin
1104   Result:=PaperRectOfName(PaperName);
1105 end;
1106 
GetPhysPaperWidthnull1107 function TPaperSize.GetPhysPaperWidth: Integer;
1108 begin
1109   result := PaperRect.PhysicalRect.Right - PaperRect.PhysicalRect.Left;
1110 end;
1111 
TPaperSize.GetSupportedPapersnull1112 function TPaperSize.GetSupportedPapers: TStrings;
1113 begin
1114   CheckSupportedPapers;
1115 
1116   Result:=fSupportedPapers;
1117 end;
1118 
TPaperSize.IndexOfDefaultPapernull1119 function TPaperSize.IndexOfDefaultPaper(const AName: string): Integer;
1120 var
1121   i: Integer;
1122 begin
1123   Result := -1;
1124   for i:=0 to Length(fInternalPapers)-1 do
1125     if CompareText(fInternalPapers[i].PaperName, AName)=0 then
1126     begin
1127       Result := i;
1128       break;
1129     end;
1130 end;
1131 
1132 procedure TPaperSize.SetPaperName(const AName: string);
1133 begin
1134   if SupportedPapers.IndexOf(aName)<>-1 then
1135   begin
1136     if aName<>PaperName then
1137     begin
1138       if fDefaultPapers then
1139         FDefaultPaperIndex := IndexOfDefaultPaper(AName)
1140       else
1141         FOwnedPrinter.DoSetPaperName(aName)
1142     end;
1143   end
1144   else
1145     raise EPrinter.Create(Format('Paper "%s" not supported!',[aName]));
1146 end;
1147 
1148 //Return an TPaperRect corresponding at an paper name
TPaperSize.PaperRectOfNamenull1149 function TPaperSize.PaperRectOfName(const AName: string): TPaperRect;
1150 var TmpPaperRect : TPaperRect;
1151     Margins      : Integer;
1152 begin
1153   FillChar(Result,SizeOf(Result),0);
1154 
1155   if SupportedPapers.IndexOf(AName)<>-1 then
1156   begin
1157 
1158     if fDefaultPapers then
1159       Margins := GetDefaultPaperRect(AName, TmpPaperRect)
1160     else
1161       Margins := fOwnedPrinter.DoGetPaperRect(aName,TmpPaperRect);
1162 
1163     if Margins>=0 then
1164       Result := TmpPaperRect
1165     else
1166       raise EPrinter.Create(Format('The paper "%s" has no defined rectangle!',[aName]));
1167 
1168   end
1169   else raise EPrinter.Create(Format('Paper "%s" not supported!',[aName]));
1170 end;
1171 
1172 procedure TPaperSize.CheckSupportedPapers;
1173 begin
1174   if (fSupportedPapers.Count=0) or
1175      (fLastPrinterIndex<>fOwnedPrinter.PrinterIndex) then
1176   begin
1177     fOwnedPrinter.SelectCurrentPrinterOrDefault;
1178 
1179     fSupportedPapers.Clear;
1180     fDefaultPapers := false;
1181     //DebugLn(['TPaperSize.GetSupportedPapers ',dbgsName(fOwnedPrinter),' ',dbgsName(Printer),' ',fOwnedPrinter=Printer]);
1182     fOwnedPrinter.DoEnumPapers(fSupportedPapers);
1183 
1184     if fSupportedPapers.Count=0 then
1185       FillDefaultPapers;
1186 
1187     fLastPrinterIndex:=fOwnedPrinter.PrinterIndex;
1188   end;
1189 end;
1190 
1191 constructor TPaperSize.Create(aOwner: TPrinter);
1192 begin
1193   if not assigned(aOwner) then
1194     raise Exception.Create('TMediaSize.Create, aOwner must be defined!');
1195   Inherited Create;
1196 
1197   fLastPrinterIndex:=-2;
1198   fOwnedPrinter:=aOwner;
1199   fSupportedPapers:=TStringList.Create;
1200 end;
1201 
1202 destructor TPaperSize.Destroy;
1203 begin
1204   fSupportedPapers.Free;
1205 
1206   inherited Destroy;
1207 end;
1208 
1209 { TPrinterCanvas }
1210 
TPrinterCanvas.GetTitlenull1211 function TPrinterCanvas.GetTitle: string;
1212 begin
1213   if Assigned(fPrinter) then
1214     Result:=fPrinter.Title
1215   else
1216     Result:=fTitle;
1217 end;
1218 
GetXDPInull1219 function TPrinterCanvas.GetXDPI: Integer;
1220 begin
1221   if Printer<>nil then
1222     result := Printer.XDPI
1223   else
1224   if fXDPI <= 0 then
1225     result := 300
1226   else
1227     result := fXDPI;
1228 end;
1229 
TPrinterCanvas.GetYDPInull1230 function TPrinterCanvas.GetYDPI: Integer;
1231 begin
1232   if Printer<>nil then
1233     result := Printer.YDPI
1234   else
1235   if fYDPI <= 0 then
1236     result := 300
1237   else
1238     result := fYDPI;
1239 end;
1240 
1241 procedure TPrinterCanvas.SetOrientation(const AValue: TPrinterOrientation);
1242 begin
1243   if Assigned(fPrinter) then
1244     fPrinter.Orientation := AValue
1245   else
1246     fOrientation := AValue;
1247 end;
1248 
TPrinterCanvas.GetOrientationnull1249 function TPrinterCanvas.GetOrientation: TPrinterOrientation;
1250 begin
1251   if fPrinter<>nil then
1252     result := fPrinter.Orientation
1253   else
1254     result := fOrientation;
1255 end;
1256 
TPrinterCanvas.GetPageHeightnull1257 function TPrinterCanvas.GetPageHeight: Integer;
1258 begin
1259   if Assigned(fPrinter) and HasDefaultMargins then
1260     Result:=fPrinter.PageHeight
1261   else
1262     Result:= PaperHeight - TopMargin - BottomMargin;
1263 end;
1264 
GetPageWidthnull1265 function TPrinterCanvas.GetPageWidth: Integer;
1266 begin
1267   if Assigned(fPrinter) and HasDefaultMargins then
1268     Result:=fPrinter.PageWidth
1269   else
1270     Result:= PaperWidth - LeftMargin - RightMargin;
1271 end;
1272 
GetPaperHeightnull1273 function TPrinterCanvas.GetPaperHeight: Integer;
1274 begin
1275   if Assigned(fPrinter) then
1276     result := fPrinter.PaperSize.Height
1277   else
1278   if fPaperHeight<=0 then
1279     result :=  round(YDPI * 842 / 72)   // default to A4 paper
1280   else
1281     result := fPaperHeight;
1282 end;
1283 
TPrinterCanvas.GetPaperWidthnull1284 function TPrinterCanvas.GetPaperWidth: Integer;
1285 begin
1286   if Assigned(fPrinter) then
1287     result := fPrinter.PaperSize.Width
1288   else
1289   if fPaperWidth<=0 then
1290     result := round(XDPI * 595 / 72)    // default to A4 paper
1291   else
1292     result := fPaperWidth;
1293 end;
1294 
1295 procedure TPrinterCanvas.SetPaperHeight(const AValue: Integer);
1296 begin
1297   fPaperHeight := AValue;
1298 end;
1299 
1300 procedure TPrinterCanvas.SetPaperWidth(const AValue: Integer);
1301 begin
1302   fPaperWidth := AValue;
1303 end;
1304 
1305 procedure TPrinterCanvas.SetTitle(const AValue: string);
1306 begin
1307   if Assigned(fPrinter) then
1308     fPrinter.Title:=aValue
1309   else
1310     fTitle:=aValue;
1311 end;
1312 
HasDefaultMarginsnull1313 function TPrinterCanvas.HasDefaultMargins: boolean;
1314 begin
1315   result := (FLeftMargin=0) and (FRightMargin=0) and
1316             (FTopMargin=0) and (FBottomMargin=0);
1317 end;
1318 
1319 procedure TPrinterCanvas.SetXDPI(const AValue: Integer);
1320 begin
1321   fXDPI := AValue;
1322 end;
1323 
1324 procedure TPrinterCanvas.SetYDPI(const AValue: Integer);
1325 begin
1326   fYDPI := AValue;
1327 end;
1328 
1329 constructor TPrinterCanvas.Create(APrinter: TPrinter);
1330 begin
1331   inherited Create;
1332   fPrinter:=aPrinter;
1333 end;
1334 
1335 procedure TPrinterCanvas.Changing;
1336 begin
1337   if Assigned(fPrinter)  then
1338     fPrinter.CheckPrinting(True);
1339   inherited Changing;
1340 end;
1341 
1342 procedure TPrinterCanvas.BeginDoc;
1343 begin
1344   fPageNum:=1;
1345 end;
1346 
1347 procedure TPrinterCanvas.NewPage;
1348 begin
1349   BeginPage;
1350 end;
1351 
1352 procedure TPrinterCanvas.BeginPage;
1353 begin
1354   Inc(fPageNum);
1355 end;
1356 
1357 procedure TPrinterCanvas.EndPage;
1358 begin
1359 
1360 end;
1361 
1362 procedure TPrinterCanvas.EndDoc;
1363 begin
1364   //No special action
1365 end;
1366 
GetLeftMarginnull1367 function TPrinterCanvas.GetLeftMargin: Integer;
1368 begin
1369   if (fLeftMargin=0) and (fPrinter<>nil) then
1370     Result:=fPrinter.PaperSize.PaperRect.WorkRect.Left
1371   else
1372     Result:=fLeftMargin;
1373 end;
1374 
TPrinterCanvas.GetTopMarginnull1375 function TPrinterCanvas.GetTopMargin: Integer;
1376 begin
1377   if (fTopMargin=0) and (fPrinter<>nil) then
1378     Result:=fPrinter.PaperSize.PaperRect.WorkRect.Top
1379   else
1380     Result:=fTopMargin;
1381 end;
1382 
TPrinterCanvas.GetBottomMarginnull1383 function TPrinterCanvas.GetBottomMargin: Integer;
1384 begin
1385   if (fBottomMargin=0) and (fPrinter<>nil) then
1386   begin
1387     with fPrinter.Papersize.PaperRect do
1388       Result := PhysicalRect.Bottom-WorkRect.Bottom;
1389   end else
1390     Result := fBottomMargin;
1391 end;
1392 
TPrinterCanvas.GetRightMarginnull1393 function TPrinterCanvas.GetRightMargin: Integer;
1394 var
1395   PR: TPaperRect;
1396 begin
1397   if (fRightMargin=0) and (fPrinter<>nil) then
1398   begin
1399     PR:=fPrinter.Papersize.PaperRect;
1400     Result := PR.PhysicalRect.Right-PR.WorkRect.Right;
1401   end else
1402     Result := fRightMargin;
1403 end;
1404 
1405 
1406 procedure doFreePrinter;
1407 begin
1408   if Assigned(Printer) then
1409     Printer.Free;
1410   Printer := nil;
1411 end;
1412 
1413 initialization
1414   RegisterInterfaceFinalizationHandler(@doFreePrinter);
1415 
1416 end.
1417