1055 lines
29 KiB
ObjectPascal
1055 lines
29 KiB
ObjectPascal
{ RxDBGridExportPdf unit
|
|
|
|
Copyright (C) 2005-2017 Lagunov Aleksey alexs75@yandex.ru and Lazarus team
|
|
original conception from rx library for Delphi (c)
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version with the following modification:
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent modules,and
|
|
to copy and distribute the resulting executable under terms of your choice,
|
|
provided that you also meet, for each linked independent module, the terms
|
|
and conditions of the license of that module. An independent module is a
|
|
module which is not derived from or based on this library. If you modify
|
|
this library, you may extend this exception to your version of the library,
|
|
but you are not obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
|
|
unit RxDBGridExportPdf;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
{$IF (FPC_FULLVERSION >= 30004)}
|
|
uses
|
|
Classes, SysUtils, DB, rxdbgrid, rxlclutils, Graphics, fpPDF, contnrs, fpparsettf,
|
|
fpTTF;
|
|
|
|
type
|
|
|
|
TRxDBGridExportPdfOption = (repExportTitle,
|
|
repExportColors,
|
|
repExportFooter,
|
|
repOverwriteExisting,
|
|
repExportImages
|
|
);
|
|
TRxDBGridExportPdfOptions = set of TRxDBGridExportPdfOption;
|
|
|
|
{ TPdfExportOptions }
|
|
|
|
TPdfExportOptions = class(TPersistent)
|
|
private
|
|
FOwner: TPersistent;
|
|
FOptions: TPDFOptions;
|
|
FPaperOrientation: TPDFPaperOrientation;
|
|
FPaperType: TPDFPaperType;
|
|
protected
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
public
|
|
constructor Create(AOwner: TPersistent);
|
|
published
|
|
property PaperType:TPDFPaperType read FPaperType write FPaperType default ptA4;
|
|
property PaperOrientation:TPDFPaperOrientation read FPaperOrientation write FPaperOrientation default ppoPortrait;
|
|
property Options:TPDFOptions read FOptions write FOptions;
|
|
end;
|
|
|
|
type
|
|
TRxDBGridExportPDF = class;
|
|
TExportFonts = class;
|
|
|
|
{ TExportFontItem }
|
|
|
|
TExportFontItem = class
|
|
private
|
|
FFontColor: TColor;
|
|
FFontName: string;
|
|
FFontSize: Integer;
|
|
FFontStyle: TFontStyles;
|
|
FOwner:TExportFonts;
|
|
FDefaultFont: boolean;
|
|
//
|
|
FPdfFont:integer;
|
|
FTTFFontInfo: TFPFontCacheItem;
|
|
function GetBold: boolean;
|
|
function GetItalic: boolean;
|
|
procedure SetFontSize(AValue: Integer);
|
|
public
|
|
constructor Create(AOwner:TExportFonts; AFontName:string; AFontStyle: TFontStyles);
|
|
destructor Destroy; override;
|
|
procedure Activate;
|
|
property FontStyle: TFontStyles read FFontStyle;
|
|
property FontSize:Integer read FFontSize write SetFontSize;
|
|
property FontColor:TColor read FFontColor write FFontColor;
|
|
property Bold:boolean read GetBold;
|
|
property Italic:boolean read GetItalic;
|
|
property DefaultFont:boolean read FDefaultFont;
|
|
property FontName:string read FFontName;
|
|
end;
|
|
|
|
{ TExportFonts }
|
|
|
|
TExportFonts = class
|
|
private
|
|
FDefaultFontBold: TExportFontItem;
|
|
FDefaultFontNormal: TExportFontItem;
|
|
FOwner:TRxDBGridExportPDF;
|
|
FList:TFPList;
|
|
function GetCount: integer;
|
|
function GetItem(Index: integer): TExportFontItem;
|
|
public
|
|
constructor Create(AOwner:TRxDBGridExportPDF);
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
function AddItem(AFontName: string; AFontStyle:TFontStyles = []): TExportFontItem;
|
|
function FindItem(AFontName: string; AFontStyle:TFontStyles = []):TExportFontItem;
|
|
property DefaultFontNormal:TExportFontItem read FDefaultFontNormal;
|
|
property DefaultFontBold:TExportFontItem read FDefaultFontBold;
|
|
property Count:integer read GetCount;
|
|
property Item[Index:integer]:TExportFontItem read GetItem;
|
|
end;
|
|
|
|
|
|
{ TRxDBGridExportPDF }
|
|
|
|
TRxDBGridExportPDF = class(TRxDBGridAbstractTools)
|
|
private
|
|
FPageMargin: TRxPageMargin;
|
|
FPageHeight:integer;
|
|
FPageWidth:integer;
|
|
|
|
FAuthorPDF: string;
|
|
FFileName: string;
|
|
FOpenAfterExport: boolean;
|
|
FOptions: TRxDBGridExportPdfOptions;
|
|
FProducerPDF: string;
|
|
FPdfOptions:TPdfExportOptions;
|
|
FCurPage: TPDFPage;
|
|
FTitleColor: TColor;
|
|
FWorkPages:TFPList;
|
|
FWorkPagesNeedCount:integer;
|
|
|
|
FFontItems:TExportFonts;
|
|
|
|
function GetPdfOptions: TPdfExportOptions;
|
|
procedure SetPageMargin(AValue: TRxPageMargin);
|
|
procedure SetPdfOptions(AValue: TPdfExportOptions);
|
|
function ActivateFont(AFont:TFont; AOwnerFont:TFont):TExportFontItem;
|
|
protected
|
|
FPDFDocument:TPDFDocument;
|
|
FCurSection: TPDFSection;
|
|
FDataSet:TDataSet;
|
|
FPosY : integer;
|
|
|
|
procedure InitFonts;
|
|
procedure DoSetupDocHeader;
|
|
procedure DoSetupFonts;
|
|
//
|
|
procedure WriteTextRect(AExportFont:TExportFontItem; X, Y, W, H:integer; AText:string; ATextAlign:TAlignment);
|
|
procedure DrawRect(X, Y, W, H: integer; ABorderColor, AFillColor: TColor);
|
|
procedure DrawImage(X, Y, W, H: integer; ABmp:TBitmap; ATextAlign:TAlignment);
|
|
|
|
procedure StartNewPage;
|
|
|
|
procedure DoExportPage;
|
|
procedure DoExportTitle;
|
|
procedure DoExportBody;
|
|
procedure DoExportFooter;
|
|
procedure DoSaveDocument;
|
|
|
|
function DoExecTools:boolean;override;
|
|
function DoSetupTools:boolean; override;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
published
|
|
property FileName:string read FFileName write FFileName;
|
|
property Options:TRxDBGridExportPdfOptions read FOptions write FOptions;
|
|
property PdfOptions:TPdfExportOptions read GetPdfOptions write SetPdfOptions;
|
|
property OpenAfterExport:boolean read FOpenAfterExport write FOpenAfterExport default false;
|
|
property AuthorPdf:string read FAuthorPDF write FAuthorPDF;
|
|
property ProducerPdf:string read FProducerPDF write FProducerPDF;
|
|
property PageMargin:TRxPageMargin read FPageMargin write SetPageMargin;
|
|
property TitleColor:TColor read FTitleColor write FTitleColor default clSilver;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
implementation
|
|
|
|
{$IF (FPC_FULLVERSION >= 30004)}
|
|
uses Grids, rxdconst, FileUtil, Forms, Controls, LCLIntf, LazFileUtils, FPReadBMP,
|
|
RxDBGridExportPdfSetupUnit, LazUTF8;
|
|
|
|
const
|
|
cInchToMM = 25.4;
|
|
function ConvetUnits(AUnits:TPDFFloat):TPDFFloat; inline;
|
|
begin
|
|
Result := (AUnits * cInchToMM) / gTTFontCache.DPI;
|
|
end;
|
|
|
|
function ColorToDdfColor(C:TColor):TARGBColor;
|
|
var
|
|
A:array [1..4] of byte absolute C;
|
|
begin
|
|
if C = clWindow then
|
|
Result:=clWhite
|
|
else
|
|
Result:={A[1] shl 24 +} A[1] shl 16 + A[2] shl 8 + A[3];
|
|
end;
|
|
|
|
type
|
|
THackExDBGrid = class(TRxDBGrid);
|
|
|
|
{ TExportFonts }
|
|
|
|
function TExportFonts.GetCount: integer;
|
|
begin
|
|
Result:=FList.Count;
|
|
end;
|
|
|
|
function TExportFonts.GetItem(Index: integer): TExportFontItem;
|
|
begin
|
|
Result:=TExportFontItem(FList[Index]);
|
|
end;
|
|
|
|
constructor TExportFonts.Create(AOwner: TRxDBGridExportPDF);
|
|
begin
|
|
inherited Create;
|
|
FOwner:=AOwner;
|
|
FList:=TFPList.Create;
|
|
end;
|
|
|
|
destructor TExportFonts.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(FList);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TExportFonts.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I:=0 to FList.Count-1 do
|
|
TExportFontItem(FList[i]).Free;
|
|
FList.Clear;
|
|
end;
|
|
|
|
function TExportFonts.AddItem(AFontName: string; AFontStyle: TFontStyles
|
|
): TExportFontItem;
|
|
var
|
|
S1, S2, S3: String;
|
|
begin
|
|
Result:=FindItem(AFontName, AFontStyle);
|
|
if Assigned(Result) then exit;
|
|
|
|
Result:=TExportFontItem.Create(Self, AFontName, AFontStyle);
|
|
|
|
S1:=ExtractFileDir(Result.FTTFFontInfo.FileName);
|
|
S2:=ExtractFileName(Result.FTTFFontInfo.FileName);
|
|
S3:=AFontName;
|
|
|
|
FOwner.FPDFDocument.FontDirectory:=S1;
|
|
|
|
Result.FPdfFont:=FOwner.FPDFDocument.AddFont(S2, S3);
|
|
end;
|
|
|
|
function TExportFonts.FindItem(AFontName: string; AFontStyle: TFontStyles
|
|
): TExportFontItem;
|
|
var
|
|
K: TExportFontItem;
|
|
i: Integer;
|
|
begin
|
|
Result:=nil;
|
|
|
|
if AFontName = 'default' then
|
|
begin
|
|
if Graphics.fsBold in AFontStyle then
|
|
Result:=FDefaultFontBold
|
|
else
|
|
Result:=FDefaultFontNormal;
|
|
end
|
|
else
|
|
begin
|
|
for i:=0 to FList.Count-1 do
|
|
begin
|
|
K:=TExportFontItem(FList[i]);
|
|
if (K.FontName = AFontName) and (K.FontStyle = AFontStyle) then
|
|
begin
|
|
Result:=K;
|
|
exit;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TExportFontItem }
|
|
|
|
function TExportFontItem.GetBold: boolean;
|
|
begin
|
|
Result:=Graphics.fsBold in FFontStyle;
|
|
end;
|
|
|
|
function TExportFontItem.GetItalic: boolean;
|
|
begin
|
|
Result:=Graphics.fsItalic in FFontStyle;
|
|
end;
|
|
|
|
procedure TExportFontItem.SetFontSize(AValue: Integer);
|
|
begin
|
|
if AValue = 0 then
|
|
FFontSize:=10
|
|
else
|
|
FFontSize:=AValue;
|
|
end;
|
|
|
|
constructor TExportFontItem.Create(AOwner: TExportFonts; AFontName: string;
|
|
AFontStyle: TFontStyles);
|
|
begin
|
|
inherited Create;
|
|
FOwner:=AOwner;
|
|
FOwner.FList.Add(Self);
|
|
FFontStyle:=AFontStyle;
|
|
FFontName:=AFontName;
|
|
FTTFFontInfo:=gTTFontCache.Find(AFontName, Graphics.fsBold in AFontStyle, Graphics.fsItalic in AFontStyle);
|
|
if not Assigned(FTTFFontInfo) then
|
|
raise Exception.CreateFmt('fpTTF:in gTTFontCache not found font "%s" info.', [AFontName]);
|
|
end;
|
|
|
|
destructor TExportFontItem.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TExportFontItem.Activate;
|
|
begin
|
|
FOwner.FOwner.FCurPage.SetFont(FPdfFont, FontSize);
|
|
FOwner.FOwner.FCurPage.SetColor(ColorToDdfColor(FontColor), false);
|
|
end;
|
|
|
|
{ TPdfExportOptions }
|
|
|
|
procedure TPdfExportOptions.AssignTo(Dest: TPersistent);
|
|
begin
|
|
if Dest is TPdfExportOptions then
|
|
begin
|
|
TPdfExportOptions(Dest).FOptions := FOptions;
|
|
TPdfExportOptions(Dest).FPaperOrientation:=FPaperOrientation;
|
|
TPdfExportOptions(Dest).FPaperType:=FPaperType;
|
|
end
|
|
else
|
|
inherited AssignTo(Dest);
|
|
end;
|
|
|
|
constructor TPdfExportOptions.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create;
|
|
FOwner:=AOwner;
|
|
FPaperType:=ptA4;
|
|
FPaperOrientation:=ppoPortrait;
|
|
end;
|
|
|
|
{ TRxDBGridExportSpreadSheet }
|
|
|
|
function TRxDBGridExportPDF.GetPdfOptions: TPdfExportOptions;
|
|
begin
|
|
Result:=FPdfOptions;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.SetPageMargin(AValue: TRxPageMargin);
|
|
begin
|
|
FPageMargin.Assign(AValue);
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.SetPdfOptions(AValue: TPdfExportOptions);
|
|
begin
|
|
FPdfOptions.Assign(AValue);
|
|
end;
|
|
|
|
function TRxDBGridExportPDF.ActivateFont(AFont: TFont; AOwnerFont: TFont
|
|
): TExportFontItem;
|
|
begin
|
|
Result:=FFontItems.FindItem(AFont.Name, AFont.Style);
|
|
{ if not Assigned(Result) then
|
|
Result:=SelectFont(AOwnerFont);
|
|
if not Assigned(Result) then
|
|
Result:=FFontItems.FDefaultFontNormal;
|
|
}
|
|
if Assigned(Result) then
|
|
begin
|
|
Result.FontSize:=AFont.Size;
|
|
Result.FontColor:=AFont.Color;
|
|
Result.Activate
|
|
end
|
|
else
|
|
raise Exception.CreateFmt('Font "%s" not found', [AFont.Name]);
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.WriteTextRect(AExportFont: TExportFontItem; X, Y,
|
|
W, H: integer; AText: string; ATextAlign: TAlignment);
|
|
var
|
|
FTW, FTH, FTH1, FTH2: Single;
|
|
X1: TPDFFloat;
|
|
Y1, fX, fY: TPDFFloat;
|
|
fW, fH: Extended;
|
|
begin
|
|
|
|
fX := ConvetUnits(X);
|
|
fY := ConvetUnits(Y+2);
|
|
fW := ConvetUnits(W);
|
|
fH := ConvetUnits(H);
|
|
|
|
//Calc text width
|
|
FTW:=ConvetUnits(AExportFont.FTTFFontInfo.TextWidth(AText, AExportFont.FontSize));
|
|
//Calc text height
|
|
FTH1 := AExportFont.FTTFFontInfo.FontData.CapHeight * AExportFont.FontSize * gTTFontCache.DPI / (72 * AExportFont.FTTFFontInfo.FontData.Head.UnitsPerEm);
|
|
FTH2 := Abs(AExportFont.FTTFFontInfo.FontData.Descender) * AExportFont.FontSize * gTTFontCache.DPI / (72 * AExportFont.FTTFFontInfo.FontData.Head.UnitsPerEm);
|
|
FTH := (FTH1 * 25.4) / gTTFontCache.DPI + (FTH2 * 25.4) / gTTFontCache.DPI;
|
|
|
|
|
|
case ATextAlign of
|
|
taLeftJustify:
|
|
begin
|
|
// Y1:=fY - FTH2;
|
|
X1:=fX + ConvetUnits(constCellPadding);
|
|
|
|
while (FTW > fW) and (UTF8Length(AText) > 0) do
|
|
begin
|
|
AText:=UTF8Copy(AText, 1, UTF8Length(AText)-1);
|
|
FTW:=ConvetUnits(AExportFont.FTTFFontInfo.TextWidth(AText, AExportFont.FontSize));
|
|
end
|
|
end;
|
|
taRightJustify:
|
|
begin
|
|
// Y1:=fY - FTH2;
|
|
X1:=fX + fW - FTW - ConvetUnits(constCellPadding);
|
|
if X1 < fX then
|
|
X1:=fX;
|
|
end;
|
|
taCenter:
|
|
begin
|
|
// Y1:=fY - FTH2;
|
|
X1:=fX + fW / 2 - FTW / 2 - ConvetUnits(constCellPadding);
|
|
if X1 < fX then
|
|
X1:=fX;
|
|
end;
|
|
end;
|
|
|
|
Y1:=fY + FTH2;
|
|
FCurPage.WriteText(X1, Y1 {- fH}, AText);
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DrawRect(X, Y, W, H: integer; ABorderColor,
|
|
AFillColor: TColor);
|
|
var
|
|
fX, fY, fW, fH: Extended;
|
|
begin
|
|
if (AFillColor = clNone) and (ABorderColor = clNone) then exit;
|
|
|
|
if ABorderColor <> clNone then
|
|
FCurPage.SetColor(ColorToDdfColor(ABorderColor), true);
|
|
|
|
if (AFillColor <> clNone) and (repExportColors in FOptions) then
|
|
FCurPage.SetColor(ColorToDdfColor(AFillColor), false);
|
|
|
|
fW:= ConvetUnits(W);
|
|
fH:= ConvetUnits(H);
|
|
fX:= ConvetUnits(X);
|
|
fY:= ConvetUnits(Y) + fH;
|
|
|
|
FCurPage.DrawRect(fX, fY, fW, fH, 1, (AFillColor <> clNone) and (repExportColors in FOptions), (ABorderColor <> clNone));
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DrawImage(X, Y, W, H: integer; ABmp: TBitmap;
|
|
ATextAlign: TAlignment);
|
|
var
|
|
S:TMemoryStream;
|
|
IDX: Integer;
|
|
fW, fH, fX, fY, X1, Y1, fW1, fH1: TPDFFloat;
|
|
begin
|
|
S:=TMemoryStream.Create;
|
|
try
|
|
ABmp.SaveToStream(S);
|
|
S.Position:=0;
|
|
IDX := FPDFDocument.Images.AddFromStream(S, TFPReaderBMP, False);
|
|
fW1 := ConvetUnits(FPDFDocument.Images[IDX].Width);
|
|
fH1 := ConvetUnits(FPDFDocument.Images[IDX].Height);
|
|
fX:=ConvetUnits(X);
|
|
fY:=ConvetUnits(Y + constCellPadding);
|
|
fW:=ConvetUnits(W);
|
|
fH:=ConvetUnits(H);
|
|
|
|
case ATextAlign of
|
|
taLeftJustify:
|
|
begin
|
|
Y1:=fY;
|
|
X1:=fX + ConvetUnits(constCellPadding);
|
|
end;
|
|
taRightJustify:
|
|
begin
|
|
Y1:=fY;
|
|
X1:=fX + fW - fW1 - ConvetUnits(constCellPadding);
|
|
if X1 < fX then
|
|
X1:=fX;
|
|
end;
|
|
taCenter:
|
|
begin
|
|
Y1:=fY;
|
|
X1:=fX + fW / 2 - fW1 / 2 - ConvetUnits(constCellPadding);
|
|
if X1 < fX then
|
|
X1:=fX;
|
|
end;
|
|
end;
|
|
|
|
Y1:=Y1 + fW1;
|
|
FCurPage.DrawImage(X1, Y1, fW1, fH1, IDX);
|
|
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.StartNewPage;
|
|
var
|
|
P: TPDFPage;
|
|
i: Integer;
|
|
begin
|
|
FWorkPages.Clear;
|
|
for i:=0 to FWorkPagesNeedCount - 1 do
|
|
begin
|
|
P := FPDFDocument.Pages.AddPage;
|
|
P.PaperType := FPdfOptions.PaperType;
|
|
//P.UnitOfMeasure := uomPixels;
|
|
P.UnitOfMeasure := uomMillimeters; //normal work only whis mm ??
|
|
FCurSection.AddPage(P);
|
|
FWorkPages.Add(P);
|
|
end;
|
|
|
|
FPosY:=FPageMargin.Top;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoExportTitle;
|
|
var
|
|
i, X, CP, K, KY, TH1, X1, W1, WNext: Integer;
|
|
C, FStartCol: TRxColumn;
|
|
CT: TRxColumnTitle;
|
|
H: LongInt;
|
|
KL: TMLCaptionItem;
|
|
begin
|
|
X:=FPageWidth + FPageMargin.Right;
|
|
H:=THackExDBGrid(FRxDBGrid).RowHeights[0];
|
|
CP:=-1;
|
|
FCurPage:=nil;
|
|
for i:=0 to FRxDBGrid.Columns.Count - 1 do
|
|
begin
|
|
C:=FRxDBGrid.Columns[i];
|
|
if C.Visible then
|
|
begin
|
|
if X + C.Width > FPageWidth - FPageMargin.Right then
|
|
begin
|
|
Inc(CP);
|
|
FCurPage:=TPDFPage(FWorkPages[CP]);
|
|
X:=FPageMargin.Left;
|
|
FStartCol:=C;
|
|
end;
|
|
|
|
CT:=C.Title as TRxColumnTitle;
|
|
if CT.CaptionLinesCount > 0 then
|
|
begin
|
|
KY:=FPosY;
|
|
for K:=0 to CT.CaptionLinesCount - 1 do
|
|
begin
|
|
TH1:=CT.CaptionLine(K).Height * RxDBGrid.DefaultRowHeight;
|
|
if K < CT.CaptionLinesCount-1 then
|
|
begin
|
|
|
|
if i < FRxDBGrid.Columns.Count-1 then
|
|
WNext:=FRxDBGrid.Columns[i+1].Width
|
|
else
|
|
WNext:=0;
|
|
|
|
if (not Assigned(CT.CaptionLine(K).Next)) or (X + C.Width + WNext > FPageWidth - FPageMargin.Right) then
|
|
begin
|
|
KL:=CT.CaptionLine(K);
|
|
X1:=X;
|
|
W1:=C.Width;
|
|
while Assigned(KL.Prior) and (KL.Col <> FStartCol) do
|
|
begin
|
|
KL:=KL.Prior;
|
|
X1:=X1 - KL.Col.Width;
|
|
W1:=W1 + KL.Col.Width;
|
|
end;
|
|
|
|
DrawRect(X1, KY, W1, TH1, FRxDBGrid.BorderColor, FTitleColor);
|
|
WriteTextRect(ActivateFont(C.Title.Font, FRxDBGrid.TitleFont), X1, KY, W1, TH1, CT.CaptionLine(K).Caption, C.Title.Alignment);
|
|
end;
|
|
KY:=KY + TH1;
|
|
end
|
|
else
|
|
begin
|
|
DrawRect(X, KY, C.Width, FPosY + H - KY, FRxDBGrid.BorderColor, FTitleColor);
|
|
WriteTextRect(ActivateFont(C.Title.Font, FRxDBGrid.TitleFont), X, KY, C.Width, FPosY + H - KY, CT.CaptionLine(K).Caption, C.Title.Alignment);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
DrawRect(X, FPosY, C.Width, H, FRxDBGrid.BorderColor, FTitleColor);
|
|
WriteTextRect(ActivateFont(C.Title.Font, FRxDBGrid.TitleFont), X, FPosY, C.Width, H, C.Title.Caption, C.Title.Alignment);
|
|
end;
|
|
X:=X + C.Width;
|
|
end;
|
|
end;
|
|
|
|
Inc(FPosY, H); // DefaultRowHeight);
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoExportBody;
|
|
procedure DoWriteRow;
|
|
var
|
|
i, X, CP: Integer;
|
|
C: TRxColumn;
|
|
B: TBitmap;
|
|
AImageIndex: LongInt;
|
|
begin
|
|
X:=FPageWidth + FPageMargin.Right;
|
|
CP:=-1;
|
|
FCurPage:=nil;
|
|
|
|
|
|
for i:=0 to FRxDBGrid.Columns.Count - 1 do
|
|
begin
|
|
C:=FRxDBGrid.Columns[i];
|
|
if C.Visible then
|
|
begin
|
|
if X + C.Width > FPageWidth - FPageMargin.Right then
|
|
begin
|
|
Inc(CP);
|
|
FCurPage:=TPDFPage(FWorkPages[CP]);
|
|
X:=FPageMargin.Left;
|
|
end;
|
|
|
|
DrawRect(X, FPosY, C.Width, FRxDBGrid.DefaultRowHeight, FRxDBGrid.BorderColor, C.Color);
|
|
|
|
if Assigned(C.Field) then
|
|
begin
|
|
if (repExportImages in FOptions) and Assigned(C.ImageList) then
|
|
begin
|
|
AImageIndex := StrToIntDef(C.KeyList.Values[C.Field.AsString], C.NotInKeyListIndex);
|
|
if (AImageIndex > -1) and (AImageIndex < C.ImageList.Count) then
|
|
begin
|
|
B:=TBitmap.Create;
|
|
try
|
|
B.Width:=C.ImageList.Width;
|
|
B.Height:=C.ImageList.Height;
|
|
B.Canvas.Brush.Color:=clWhite;
|
|
B.Canvas.FillRect(0, 0, B.Width, B.Height);
|
|
|
|
C.ImageList.StretchDraw(B.Canvas, AImageIndex, Rect(0, 0, B.Width, B.Height));
|
|
DrawImage(X, FPosY, C.Width, FRxDBGrid.DefaultRowHeight, B, C.Alignment);
|
|
finally
|
|
B.Free
|
|
end;
|
|
end
|
|
end
|
|
else
|
|
WriteTextRect(ActivateFont(C.Font, FRxDBGrid.Font), X, FPosY, C.Width, FRxDBGrid.DefaultRowHeight, C.Field.DisplayText, C.Alignment);
|
|
end;
|
|
|
|
X:=X + C.Width;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
while not FDataSet.EOF do
|
|
begin
|
|
DoWriteRow;
|
|
FDataSet.Next;
|
|
Inc(FPosY, FRxDBGrid.DefaultRowHeight);
|
|
if FPosY > FPageHeight - FPageMargin.Bottom then
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoSetupFonts;
|
|
//Find default font name
|
|
function DefFontName:string;
|
|
const
|
|
DefFontNames : array [1..3] of string =
|
|
('Liberation Sans', 'Arial', 'FreeSans');
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=1 to 3 do
|
|
if Assigned(gTTFontCache.Find(DefFontNames[i], false, false)) then
|
|
begin
|
|
Result:=DefFontNames[i];
|
|
exit;
|
|
end;
|
|
raise Exception.Create('Not found Sans font');
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
sDefFontName:string;
|
|
begin
|
|
InitFonts;
|
|
sDefFontName:=DefFontName;
|
|
FFontItems.FDefaultFontNormal:=FFontItems.AddItem(sDefFontName, []);
|
|
FFontItems.FDefaultFontBold:=FFontItems.AddItem(sDefFontName, [Graphics.fsBold]);
|
|
|
|
for i:=0 to FRxDBGrid.Columns.Count-1 do
|
|
begin
|
|
if FRxDBGrid.Columns[i].Font.Name <> 'default' then
|
|
FFontItems.AddItem(FRxDBGrid.Columns[i].Font.Name, FRxDBGrid.Columns[i].Font.Style);
|
|
|
|
if FRxDBGrid.Columns[i].Footer.Font.Name <> 'default' then
|
|
FFontItems.AddItem(FRxDBGrid.Columns[i].Footer.Font.Name, FRxDBGrid.Columns[i].Footer.Font.Style);
|
|
|
|
if FRxDBGrid.Columns[i].Title.Font.Name <> 'default' then
|
|
FFontItems.AddItem(FRxDBGrid.Columns[i].Title.Font.Name, FRxDBGrid.Columns[i].Title.Font.Style);
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoExportFooter;
|
|
|
|
procedure WriteFooterRow(AFooterRow:Integer);
|
|
var
|
|
i, X, CP: Integer;
|
|
S: String;
|
|
C: TRxColumn;
|
|
begin
|
|
X:=FPageWidth + FPageMargin.Right;
|
|
CP:=-1;
|
|
FCurPage:=nil;
|
|
|
|
for i:=0 to FRxDBGrid.Columns.Count - 1 do
|
|
begin
|
|
C:=FRxDBGrid.Columns[i];
|
|
if C.Visible then
|
|
begin
|
|
if X + C.Width > FPageWidth - FPageMargin.Right then
|
|
begin
|
|
Inc(CP);
|
|
FCurPage:=TPDFPage(FWorkPages[CP]);
|
|
X:=FPageMargin.Left;
|
|
end;
|
|
|
|
DrawRect(X, FPosY, C.Width, FRxDBGrid.DefaultRowHeight, FRxDBGrid.BorderColor, FRxDBGrid.FooterOptions.Color);
|
|
|
|
if FRxDBGrid.FooterOptions.RowCount = 1 then
|
|
S:=C.Footer.DisplayText
|
|
else
|
|
begin
|
|
if C.Footers.Count > AFooterRow then
|
|
S:=C.Footers[AFooterRow].DisplayText
|
|
else
|
|
S:='';
|
|
end;
|
|
|
|
if (S<>'') then
|
|
WriteTextRect(ActivateFont(C.Footer.Font, FRxDBGrid.Font), X, FPosY, C.Width, FRxDBGrid.DefaultRowHeight, S, C.Footer.Alignment);
|
|
|
|
X:=X + C.Width;
|
|
end;
|
|
end;
|
|
Inc(FPosY, FRxDBGrid.DefaultRowHeight);
|
|
end;
|
|
|
|
var
|
|
j: Integer;
|
|
begin
|
|
if FRxDBGrid.FooterOptions.RowCount = 1 then
|
|
WriteFooterRow(1)
|
|
else
|
|
begin
|
|
for j:=0 to FRxDBGrid.FooterOptions.RowCount-1 do
|
|
begin
|
|
if FPosY > FPageHeight - FPageMargin.Bottom then
|
|
StartNewPage;
|
|
WriteFooterRow(j);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoSetupDocHeader;
|
|
var
|
|
W, i: Integer;
|
|
C: TRxColumn;
|
|
begin
|
|
FPDFDocument.Infos.Title := Application.Title;
|
|
FPDFDocument.Infos.Author := FAuthorPDF;
|
|
FPDFDocument.Infos.Producer := FProducerPDF;
|
|
FPDFDocument.Infos.ApplicationName := ApplicationName;
|
|
FPDFDocument.Infos.CreationDate := Now;
|
|
|
|
FPDFDocument.Options:=FPdfOptions.FOptions + [poPageOriginAtTop];
|
|
FPDFDocument.DefaultOrientation:=FPdfOptions.PaperOrientation;
|
|
|
|
//calc need count pages for all columns
|
|
FWorkPagesNeedCount:=1;
|
|
if FPdfOptions.FPaperType <> ptCustom then
|
|
begin
|
|
if FPdfOptions.PaperOrientation = ppoPortrait then
|
|
begin
|
|
FPageWidth := PDFPaperSizes[FPdfOptions.FPaperType, 1];
|
|
FPageHeight := PDFPaperSizes[FPdfOptions.FPaperType, 0];
|
|
end
|
|
else
|
|
begin
|
|
FPageWidth := PDFPaperSizes[FPdfOptions.FPaperType, 0];
|
|
FPageHeight := PDFPaperSizes[FPdfOptions.FPaperType, 1];
|
|
end;
|
|
|
|
W:=FPageWidth + FPageMargin.Right;
|
|
FWorkPagesNeedCount:=0;
|
|
for i:=0 to FRxDBGrid.Columns.Count - 1 do
|
|
begin
|
|
C:=FRxDBGrid.Columns[i];
|
|
if C.Visible then
|
|
begin
|
|
if W + C.Width > FPageWidth - FPageMargin.Right then
|
|
begin
|
|
Inc(FWorkPagesNeedCount);
|
|
W:=FPageMargin.Left;
|
|
end;
|
|
W:=W + C.Width;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoExportPage;
|
|
begin
|
|
StartNewPage;
|
|
|
|
if repExportTitle in FOptions then
|
|
DoExportTitle;
|
|
DoExportBody;
|
|
end;
|
|
|
|
function TRxDBGridExportPDF.DoExecTools: boolean;
|
|
var
|
|
P: TBookMark;
|
|
begin
|
|
Result:=false;
|
|
FDataSet:=FRxDBGrid.DataSource.DataSet;
|
|
FDataSet.DisableControls;
|
|
{$IFDEF NoAutomatedBookmark}
|
|
P:=FDataSet.GetBookmark;
|
|
{$ELSE}
|
|
P:=FDataSet.Bookmark;
|
|
{$ENDIF}
|
|
|
|
FPDFDocument:=TPDFDocument.Create(nil);
|
|
FFontItems:=TExportFonts.Create(Self);
|
|
FWorkPages:=TFPList.Create;
|
|
try
|
|
FPDFDocument.StartDocument;
|
|
DoSetupFonts;
|
|
DoSetupDocHeader;
|
|
FCurSection := FPDFDocument.Sections.AddSection; // we always need at least one section
|
|
FDataSet.First;
|
|
repeat
|
|
DoExportPage;
|
|
until FDataSet.EOF;
|
|
|
|
if repExportFooter in FOptions then
|
|
begin
|
|
if FPosY > FPageHeight - FPageMargin.Bottom then
|
|
StartNewPage;
|
|
|
|
DoExportFooter;
|
|
end;
|
|
DoSaveDocument;
|
|
Result:=true;
|
|
finally
|
|
{$IFDEF NoAutomatedBookmark}
|
|
FDataSet.GotoBookmark(P);
|
|
FDataSet.FreeBookmark(P);
|
|
{$ELSE}
|
|
FDataSet.Bookmark:=P;
|
|
{$ENDIF}
|
|
FDataSet.EnableControls;
|
|
|
|
FreeAndNil(FWorkPages);
|
|
FreeAndNil(FPDFDocument);
|
|
FreeAndNil(FFontItems);
|
|
end;
|
|
|
|
if Result and FOpenAfterExport then
|
|
OpenDocument(FileName);
|
|
end;
|
|
|
|
function TRxDBGridExportPDF.DoSetupTools: boolean;
|
|
begin
|
|
RxDBGridExportPdfSetupForm:=TRxDBGridExportPdfSetupForm.Create(Application);
|
|
|
|
RxDBGridExportPdfSetupForm.FileNameEdit1.FileName:=FileName;
|
|
RxDBGridExportPdfSetupForm.cbOpenAfterExport.Checked:=FOpenAfterExport;
|
|
RxDBGridExportPdfSetupForm.cbExportColumnHeader.Checked:=repExportTitle in FOptions;
|
|
RxDBGridExportPdfSetupForm.cbExportColumnFooter.Checked:=repExportFooter in FOptions;
|
|
RxDBGridExportPdfSetupForm.cbExportCellColors.Checked:=repExportColors in FOptions;
|
|
RxDBGridExportPdfSetupForm.CheckBox6.Checked:=repExportImages in FOptions;
|
|
RxDBGridExportPdfSetupForm.ColorBox1.Selected:=FTitleColor;
|
|
|
|
RxDBGridExportPdfSetupForm.RadioGroup1.ItemIndex:=Ord(FPdfOptions.PaperOrientation = ppoLandscape);
|
|
RxDBGridExportPdfSetupForm.ComboBox1.ItemIndex:=Ord(FPdfOptions.PaperType)-1;
|
|
|
|
RxDBGridExportPdfSetupForm.CheckBox1.Checked:=poOutLine in FPdfOptions.Options;
|
|
RxDBGridExportPdfSetupForm.CheckBox2.Checked:=poCompressText in FPdfOptions.Options;
|
|
RxDBGridExportPdfSetupForm.CheckBox3.Checked:=poCompressFonts in FPdfOptions.Options;
|
|
RxDBGridExportPdfSetupForm.CheckBox4.Checked:=poCompressImages in FPdfOptions.Options;
|
|
RxDBGridExportPdfSetupForm.CheckBox5.Checked:=poUseRawJPEG in FPdfOptions.Options;
|
|
|
|
Result:=RxDBGridExportPdfSetupForm.ShowModal = mrOk;
|
|
if Result then
|
|
begin
|
|
FileName:=RxDBGridExportPdfSetupForm.FileNameEdit1.FileName;
|
|
FOpenAfterExport:=RxDBGridExportPdfSetupForm.cbOpenAfterExport.Checked;
|
|
FTitleColor:=RxDBGridExportPdfSetupForm.ColorBox1.Selected;
|
|
|
|
if RxDBGridExportPdfSetupForm.cbExportColumnHeader.Checked then
|
|
FOptions:=FOptions + [repExportTitle]
|
|
else
|
|
FOptions:=FOptions - [repExportTitle];
|
|
|
|
if RxDBGridExportPdfSetupForm.cbExportColumnFooter.Checked then
|
|
FOptions:=FOptions + [repExportFooter]
|
|
else
|
|
FOptions:=FOptions - [repExportFooter];
|
|
|
|
if RxDBGridExportPdfSetupForm.cbExportCellColors.Checked then
|
|
FOptions:=FOptions + [repExportColors]
|
|
else
|
|
FOptions:=FOptions - [repExportColors];
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox6.Checked then
|
|
FOptions:=FOptions + [repExportImages]
|
|
else
|
|
FOptions:=FOptions - [repExportImages];
|
|
|
|
|
|
if RxDBGridExportPdfSetupForm.RadioGroup1.ItemIndex = 0 then
|
|
FPdfOptions.PaperOrientation:=ppoPortrait
|
|
else
|
|
FPdfOptions.PaperOrientation:=ppoLandscape;
|
|
|
|
FPdfOptions.PaperType:=TPDFPaperType(RxDBGridExportPdfSetupForm.ComboBox1.ItemIndex+1);
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox1.Checked then
|
|
FPdfOptions.Options:=FPdfOptions.Options + [poOutLine]
|
|
else
|
|
FPdfOptions.Options:=FPdfOptions.Options - [poOutLine];
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox2.Checked then
|
|
FPdfOptions.Options:=FPdfOptions.Options + [poCompressText]
|
|
else
|
|
FPdfOptions.Options:=FPdfOptions.Options - [poCompressText];
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox3.Checked then
|
|
FPdfOptions.Options:=FPdfOptions.Options + [poCompressFonts]
|
|
else
|
|
FPdfOptions.Options:=FPdfOptions.Options - [poCompressFonts];
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox4.Checked then
|
|
FPdfOptions.Options:=FPdfOptions.Options + [poCompressImages]
|
|
else
|
|
FPdfOptions.Options:=FPdfOptions.Options - [poCompressImages];
|
|
|
|
if RxDBGridExportPdfSetupForm.CheckBox5.Checked then
|
|
FPdfOptions.Options:=FPdfOptions.Options + [poUseRawJPEG]
|
|
else
|
|
FPdfOptions.Options:=FPdfOptions.Options - [poUseRawJPEG];
|
|
|
|
end;
|
|
RxDBGridExportPdfSetupForm.Free;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.DoSaveDocument;
|
|
var
|
|
F: TFileStream;
|
|
begin
|
|
F := TFileStream.Create(FFileName,fmCreate);
|
|
try
|
|
FPDFDocument.SaveToStream(F);
|
|
finally
|
|
F.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxDBGridExportPDF.InitFonts;
|
|
var
|
|
FontDirList: TStringList;
|
|
|
|
procedure CreateFontDirList;
|
|
{$IFDEF WINDOWS}
|
|
var
|
|
s: String;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF WINDOWS}
|
|
s := SHGetFolderPathUTF8(20); // CSIDL_FONTS = 20
|
|
if s <> '' then
|
|
FontDirList.Add(s);
|
|
{$ENDIF}
|
|
{$IFDEF linux}
|
|
//tested on Fedora 24
|
|
FontDirList.Add('/usr/share/cups/fonts/');
|
|
FontDirList.Add('/usr/share/fonts/');
|
|
FontDirList.Add('/usr/share/wine/fonts/');
|
|
FontDirList.Add('/usr/local/lib/X11/fonts/');
|
|
FontDirList.Add(GetUserDir + '.fonts/');
|
|
{$ENDIF}
|
|
end;
|
|
begin
|
|
FontDirList := TStringList.Create;
|
|
CreateFontDirList;
|
|
if gTTFontCache.Count = 0 then
|
|
begin
|
|
gTTFontCache.BuildFontCacheIgnoresErrors:=true;
|
|
CreateFontDirList;
|
|
gTTFontCache.SearchPath.Assign(FontDirList);
|
|
FreeAndNil(FontDirList);
|
|
gTTFontCache.BuildFontCache;
|
|
end;
|
|
end;
|
|
|
|
constructor TRxDBGridExportPDF.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FPageMargin:=TRxPageMargin.Create;
|
|
FPdfOptions:=TPdfExportOptions.Create(Self);
|
|
FTitleColor:=clSilver;
|
|
|
|
FCaption:=sToolsExportPDF;
|
|
FOpenAfterExport:=false;
|
|
end;
|
|
|
|
destructor TRxDBGridExportPDF.Destroy;
|
|
begin
|
|
FreeAndNil(FPdfOptions);
|
|
FreeAndNil(FPageMargin);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
end.
|
|
|