unit llPrintDBGrid;

interface

uses
  Windows, Graphics, Classes, Forms, SysUtils, DB, PDF, DBGrids;

type
  { Types for Print Grid Params }
  TllIndent = class(TPersistent)
  private
    FHeaderText: Double;
    FGridTop: Double;
    FGridBottom: Double;
  published
    property HeaderText: Double read FHeaderText Write FHeaderText;
    property GridTop: Double read FGridTop Write FGridTop;
    property GridBottom: Double read FGridBottom Write FGridBottom;
  end;

  TllRect = class(TPersistent)
  private
    FLeft: Integer;
    FTop: Integer;
    FRight: Integer;
    FBottom: Integer;
  published
    property Left: Integer read FLeft Write FLeft;
    property Top: Integer read FTop Write FTop;
    property Right: Integer read FRight Write FRight;
    property Bottom: Integer read FBottom Write FBottom;
  end;

  TllMargin = class(TPersistent)
  private
    FLeft: Double;
    FRight: Double;
    FTop: Double;
    FBottom: Double;
  published
    property Left: Double read FLeft Write FLeft;
    property Right: Double read FRight Write FRight;
    property Top: Double read FTop Write FTop;
    property Bottom: Double read FBottom Write FBottom;
  end;

  TPDFPrintGridParam = class(TComponent)
  private
    FFontCaption: TFont;
    FFontCaptionGrid: TFont;
    FFontGrid: TFont;
    FMargin: TllMargin;
    FPrintTopLine: Boolean;
    FPrintBotomLine: Boolean;
    FPrintPage: Boolean;
    FPrintPages: Boolean;
    FPrintDate: Boolean;
    FCurentDate: Boolean;
    FPrintedDate: TDateTime;
    FPrintHeaderText: Boolean;
    FHeaderText: string;
    FPrintCaptionText: Boolean;
    FCaptionText: string;
    FPrintFooterText: Boolean;
    FFooterText: string;
    FPrintEmptyGrid: Boolean;
    FCalculateWidth: Boolean;
    FColorGridLines: TColor;
    FColorCaptionGridFill: TColor;
    FColorGridFill: TColor;
    FGridTextIndent: TllRect;
    FAlignMasterGridCaption: Boolean;
    FAlignDataInColumns: Boolean;
    FAlignColumnsInPage: Boolean;
    FAlignColumnsInLastPage: Boolean;
    FDefaultAlignDataInColumns: TAlignment;
    FGetAlignFromField: Boolean;
    FIndent: TllIndent;
    FCountPagesBeforeReport: Longword;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ClearParams;
    procedure RestoreDefault;
  published
    property FontCaption: TFont read FFontCaption write FFontCaption;
    property FontCaptionGrid: TFont read FFontCaptionGrid write FFontCaptionGrid;
    property FontGrid: TFont read FFontGrid write FFontGrid;
    property Margin: TllMargin read FMargin write FMargin;
    property PrintTopLine: Boolean read FPrintTopLine write FPrintTopLine;
    property PrintBotomLine: Boolean read FPrintBotomLine write FPrintBotomLine;
    property PrintPage: Boolean read FPrintPage write FPrintPage;
    property PrintPages: Boolean read FPrintPages write FPrintPages;
    property PrintDate: Boolean read FPrintDate write FPrintDate;
    property CurentDate: Boolean read FCurentDate write FCurentDate;
    property PrintedDate: TDateTime read FPrintedDate write FPrintedDate;
    property PrintHeaderText: Boolean read FPrintHeaderText write FPrintHeaderText;
    property HeaderText: string read FHeaderText write FHeaderText;
    property PrintCaptionText: Boolean read FPrintCaptionText write FPrintCaptionText;
    property CaptionText: string read FCaptionText write FCaptionText;
    property PrintFooterText: Boolean read FPrintFooterText write FPrintFooterText;
    property FooterText: string read FFooterText write FFooterText;
    property PrintEmptyGrid: Boolean read FPrintEmptyGrid write FPrintEmptyGrid;
    property CalculateWidth: Boolean read FCalculateWidth write FCalculateWidth;
    property ColorGridLines: TColor read FColorGridLines write FColorGridLines;
    property ColorCaptionGridFill: TColor read FColorCaptionGridFill write FColorCaptionGridFill;
    property ColorGridFill: TColor read FColorGridFill write FColorGridFill;
    property GridTextIndent: TllRect read FGridTextIndent write FGridTextIndent;
    property AlignMasterGridCaption: Boolean read FAlignMasterGridCaption write FAlignMasterGridCaption;
    property AlignDataInColumns: Boolean read FAlignDataInColumns write FAlignDataInColumns;
    property AlignColumnsInPage: Boolean read FAlignColumnsInPage write FAlignColumnsInPage;
    property AlignColumnsInLastPage: Boolean read FAlignColumnsInLastPage write FAlignColumnsInLastPage;
    property DefaultAlignDataInColumns: TAlignment read FDefaultAlignDataInColumns write FDefaultAlignDataInColumns;
    property GetAlignFromField: Boolean read FGetAlignFromField write FGetAlignFromField;
    property Indent: TllIndent read FIndent write FIndent;
    property CountPagesBeforeReport: Longword read FCountPagesBeforeReport write FCountPagesBeforeReport;
  end;

  { Types for Report Params }
  TllReportParams = class(TPersistent)
  private
    FBeginDoc: Boolean;
    FEndDoc: Boolean;
  public
    constructor Create;
  published
    property BeginDoc: Boolean read FBeginDoc Write FBeginDoc;
    property EndDoc: Boolean read FEndDoc Write FEndDoc;
  end;

  {Type for Master Grid}
  TllMasterGrid = TCustomDBGrid;

  {Types for Detail Grids}
  TllDetailGrid = class(TCollectionItem)
  private
    FGrid: TCustomDBGrid;
    FCaptionGrid: string;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property Grid: TCustomDBGrid read FGrid write FGrid;
    property CaptionGrid: string read FCaptionGrid Write FCaptionGrid;
  end;

  TllDetailGrids = class(TCollection)
  private
    FOwner: TComponent;
    function GetItem(Index: Integer): TllDetailGrid;
    procedure SetItem(Index: Integer; Value: TllDetailGrid);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TComponent);
    function Add: TllDetailGrid;
    property Owner: TComponent read FOwner;
    property Items[Index: Integer]: TllDetailGrid Read GetItem Write SetItem; default;
  end;

  {Types for Pages}
  TllTypeInformation = (lltiCaption, lltiIndentGridTop, lltiIndentGridBottom, lltiGrid, lltiRule, lltiNone);

  TllElmentMarkingInfo = record
    x, y: Integer;
    NumberGrid: Integer;
    TypeInformation: TllTypeInformation;
    Col, Row: Integer;
    Col1, Row1: Integer;
  end;

  TllElmentsMarkingInfo = array of TllElmentMarkingInfo;

  TllPageInfo = record
    NumberPage: Integer;
    CountElements: Integer;
    Elements: TllElmentsMarkingInfo;
  end;

  TllPagesInfo = array of TllPageInfo;

  TllPages = record
    CountPages: Integer;
    Pages: TllPagesInfo;
  end;

  {Types for TPDFMDDBGridPrinter}

  TNextRecordEvent = procedure (Sender: TObject; var Continue: Boolean) of object;
  TFirstRecordEvent = TNotifyEvent;

  TPDFMDDBGridPrinter = class(TComponent)
  private
    FPrintGridParam: TPDFPrintGridParam;
    FPDFDocument: TPDFDocument;
    FMasterGrid: TllMasterGrid;
    FDetailGrids: TllDetailGrids;
    FReportParams: TllReportParams;
    FMultiRecordsReport: Boolean;
    FOnNextRecord: TNextRecordEvent;
    FOnFirstRecord: TFirstRecordEvent;
    procedure SetDetailGrids(Value: TllDetailGrids);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Print;
  published
    property DetailGrids: TllDetailGrids read FDetailGrids Write SetDetailGrids;
    property MasterGrid: TllMasterGrid read FMasterGrid Write FMasterGrid;
    property MultiRecordsReport: Boolean read FMultiRecordsReport Write FMultiRecordsReport;
    property ReportParams: TllReportParams read FReportParams;
    property PDFDocument: TPDFDocument read FPDFDocument Write FPDFDocument;
    property PrintGridParam: TPDFPrintGridParam read FPrintGridParam Write FPrintGridParam;
    property OnNextRecord: TNextRecordEvent read FOnNextRecord Write FOnNextRecord;
    property OnFirstRecord: TFirstRecordEvent read FOnFirstRecord Write FOnFirstRecord;
  end;

  {Types for TPDFDBGridPrinter}

  TPDFDBGridPrinter = class(TComponent)
  private
    FGrid: TllMasterGrid;
    FPrintGridParam: TPDFPrintGridParam;
    FPDFDocument: TPDFDocument;
    FReportParams: TllReportParams;
  public
    procedure Print;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Grid: TllMasterGrid read FGrid Write FGrid;
    property ReportParams: TllReportParams read FReportParams;
    property PDFDocument: TPDFDocument read FPDFDocument Write FPDFDocument;
    property PrintGridParam: TPDFPrintGridParam read FPrintGridParam Write FPrintGridParam;
  end;

  {Types for TPDFDBGridsPrinter}

  TPDFDBGridsPrinter = class(TComponent)
  private
    FPrintGridParam: TPDFPrintGridParam;
    FPDFDocument: TPDFDocument;
    FGrids: TllDetailGrids;
    FReportParams: TllReportParams;
    procedure SetDetailGrids(Value: TllDetailGrids);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Print;
  published
    property Grids: TllDetailGrids read FGrids Write SetDetailGrids;
    property ReportParams: TllReportParams read FReportParams;
    property PDFDocument: TPDFDocument read FPDFDocument Write FPDFDocument;
    property PrintGridParam: TPDFPrintGridParam read FPrintGridParam Write FPrintGridParam;
  end;

  procedure PaintTitlePage(PD: TPDFDocument; PrintGridParam: TPDFPrintGridParam; PrintCaption: Boolean; const Page: Integer = -1; const PageCount: Integer = -1);

implementation

uses TypInfo;

{ TllReportParams }

constructor TllReportParams.Create;
begin
  inherited Create;
  FBeginDoc := True;
  FEndDoc := True;
end;


{ TPDFPrintGridParam }

constructor TPDFPrintGridParam.Create(AOwner: TComponent);
begin
  inherited;
  FFontCaption := TFont.Create;
  FFontCaptionGrid := TFont.Create;
  FFontGrid := TFont.Create;
  FMargin := TllMargin.Create;
  FGridTextIndent := TllRect.Create;
  FIndent := TllIndent.Create;
  RestoreDefault;
end;

destructor TPDFPrintGridParam.Destroy;
begin
  FFontGrid.Free;
  FFontCaptionGrid.Free;
  FFontCaption.Free;
  FMargin.Free;
  FGridTextIndent.Free;
  FIndent.Free;
  inherited;
end;

procedure TPDFPrintGridParam.ClearParams;
begin
  FFontCaption.Name := 'Arial';
  FFontCaption.Size := 10;
  FFontCaption.Style := [];
  FFontCaptionGrid.Name := 'Arial';
  FFontCaptionGrid.Size := 10;
  FFontCaptionGrid.Style := [];
  FFontGrid.Name := 'Arial';
  FFontGrid.Size := 10;
  FFontGrid.Style := [];
  FMargin.Left := 0.5;
  FMargin.Right := 0.5;
  FMargin.Top := 0.5;
  FMargin.Bottom := 0.5;
  FPrintTopLine := False;
  FPrintBotomLine := False;
  FPrintPage := False;
  FPrintPages := False;
  FPrintDate := False;
  FCurentDate := True;
  FPrintedDate := Date;
  FPrintHeaderText := False;
  FHeaderText := '';
  FPrintCaptionText := False;
  FCaptionText := '';
  FPrintFooterText := False;
  FFooterText := '';
  FPrintEmptyGrid := True;
  FCalculateWidth := False;
  FColorGridLines := clBlack;
  FColorCaptionGridFill := clBtnFace;
  FColorGridFill := clWhite;
  FGridTextIndent.Left := 56;
  FGridTextIndent.Right := 56;
  FGridTextIndent.Top := 56;
  FGridTextIndent.Bottom := 56;
  FAlignMasterGridCaption := False;
  FAlignDataInColumns := False;
  FAlignColumnsInPage := False;
  FAlignColumnsInLastPage := False;
  FDefaultAlignDataInColumns := taLeftJustify;
  FGetAlignFromField := False;
  with FIndent do begin
    HeaderText := 0.2;
    GridTop := 0.2;
    GridBottom := 0.6;
  end;
  FCountPagesBeforeReport := 0;
end;

procedure TPDFPrintGridParam.RestoreDefault;
begin
  FontCaption.Name := 'Arial';
  FontCaption.Size := 14;
  FontCaption.Style := [fsBold];
  FontCaptionGrid.Name := 'Arial';
  FontCaptionGrid.Size := 12;
  FontCaptionGrid.Style := [fsBold, fsItalic];
  FontGrid.Name := 'Arial';
  FontGrid.Size := 10;
  FontGrid.Style := [];
  Margin.Left := 0.5;
  Margin.Right := 0.5;
  Margin.Top := 0.5;
  Margin.Bottom := 0.5;
  PrintTopLine := True;
  PrintBotomLine := True;
  PrintPage := True;
  PrintPages := True;
  PrintDate := True;
  CurentDate := True;
  PrintedDate := Date;
  PrintHeaderText := True;
  HeaderText := '';
  PrintCaptionText := True;
  CaptionText := '';
  PrintFooterText := True;
  FooterText := '';
  PrintEmptyGrid := False;
  CalculateWidth := True;
  ColorGridLines := clBlack;
  ColorCaptionGridFill := clBtnFace;
  ColorGridFill := clWhite;
  GridTextIndent.Left := 280;
  GridTextIndent.Right := 280;
  GridTextIndent.Top := 112;
  GridTextIndent.Bottom := 112;
  AlignMasterGridCaption := True;
  AlignDataInColumns := True;
  AlignColumnsInPage := True;
  AlignColumnsInLastPage := False;
  DefaultAlignDataInColumns := taLeftJustify;
  GetAlignFromField := False;
  with Indent do begin
    HeaderText := 0.2;
    GridTop := 0.2;
    GridBottom := 0.6;
  end;
  CountPagesBeforeReport := 0;
end;


{ TllDetailGrid }

procedure TllDetailGrid.Assign(Source: TPersistent);
begin
  if Source is TllDetailGrid then begin
    FGrid := TllDetailGrid(Source).FGrid;
    FCaptionGrid := TllDetailGrid(Source).FCaptionGrid;
  end;
  inherited Assign(Source);
end;


{ TllDetailGrids }

constructor TllDetailGrids.Create(AOwner: TComponent);
begin
  inherited Create(TllDetailGrid);
  FOwner := AOwner;
end;

function TllDetailGrids.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TllDetailGrids.GetItem(Index: Integer): TllDetailGrid;
begin
  Result := TllDetailGrid(inherited GetItem(Index));
end;

procedure TllDetailGrids.SetItem(Index: Integer; Value: TllDetailGrid);
begin
  inherited SetItem(Index, Value);
end;

function TllDetailGrids.Add: TllDetailGrid;
begin
  Result := TllDetailGrid(inherited Add);
end;


{------------------------------------------------------------------------------}
{ Internal Types }

type

  TColumnData = array of array of string;

  TColumnInfo = record
    Name: string;
    MaxWidth: Integer;
    Align: Integer;
    RealNumber: Integer;
  end;

  TGridColumns = array of TColumnInfo;

  TGridColumnsInPages = array of Integer;

  TGrid = record
    ColCount, RowCount: Integer;
    Columns: TGridColumns;
    ColumnsInPages: TGridColumnsInPages;
    Items: TColumnData
  end;

  TGridInfo = record
    Grid: TGrid;
    CaptionGrid: string;
    PrintCaption: Boolean;
    PageInWidth: Integer;
    RowHeight: Integer
  end;

  TGrids = array of TGridInfo;

  TGetParam = (Left, Right, Top, Bottom, Height, Width);

  TRealIdentFromPage = record
    First: TRect;
    Old: TRect;
  end;

  TDrawSizeToPage = record
    WidthPage, HeightPage: Integer;
    WidthPageFirst, HeightPageFirst: Integer;
  end;

  TWorkParam = class(TObject)
  private
    FIndentGrid: TllIndent;
  public
    scrPixelPerInch: Integer;
    PageCount: Integer;
    RowHeight: Integer;
    DrawSizeToPage: TDrawSizeToPage;
    ReportPages: TllPages;
    Indent: TRect;
    RealIdentFromPage: TRealIdentFromPage;
    constructor Create;
    destructor Destroy; override;
    property IndentGrid: TllIndent read FIndentGrid;
  end;


{ TWorkParam }

constructor TWorkParam.Create;
begin
  inherited Create;
  FIndentGrid := TllIndent.Create;
end;

destructor TWorkParam.Destroy;
begin
  FIndentGrid.Free;
  inherited Destroy;
end;


{ Internal Procedures and Fuctions }

function GetWidthColumn(AObject: TObject; AIndex: Integer; var APropertyValue: Integer): Boolean;
var PropInfo: PPropInfo;
    Cols: TObject;
    Col: TObject;
begin
  Result := False;
  PropInfo := GetPropInfo(AObject, 'Columns');
  if PropInfo <> nil then
    if PropInfo^.PropType^.Kind = tkClass then begin
      Cols := GetObjectProp(AObject, PropInfo);
      if Cols is TCollection then
        if AIndex < TCollection(Cols).Count then begin
          Col := TCollection(Cols).Items[AIndex];
          PropInfo := GetPropInfo(Col, 'Width');
          if PropInfo <> nil then
            if PropInfo^.PropType^.Kind = tkInteger then begin
              APropertyValue := GetOrdProp(Col, PropInfo);
              Result := True;
          end;
        end;
    end;
end;

function GetAlignmentColumn(AObject: TObject; AIndex: Integer; var APropertyValue: TAlignment): Boolean;
var PropInfo: PPropInfo;
    Cols: TObject;
    Col: TObject;
begin
  Result := False;
  PropInfo := GetPropInfo(AObject, 'Columns');
  if PropInfo <> nil then
    if PropInfo^.PropType^.Kind = tkClass then begin
      Cols := GetObjectProp(AObject, PropInfo);
      if Cols is TCollection then
        if AIndex < TCollection(Cols).Count then begin
          Col := TCollection(Cols).Items[AIndex];
          PropInfo := GetPropInfo(Col, 'Alignment');
          if PropInfo <> nil then
            if PropInfo^.PropType^.Kind = tkEnumeration then begin
              APropertyValue := TAlignment(GetOrdProp(Col, PropInfo));
              Result := True;
          end;
        end;
    end;
end;

function GetTitleCaptionColumn(AObject: TObject; AIndex: Integer; var APropertyValue: string): Boolean;
var PropInfo: PPropInfo;
    Cols: TObject;
    Col: TObject;
    Title: TObject;
begin
  Result := False;
  PropInfo := GetPropInfo(AObject, 'Columns');
  if PropInfo <> nil then
    if PropInfo^.PropType^.Kind = tkClass then begin
      Cols := GetObjectProp(AObject, PropInfo);
      if Cols is TCollection then
        if AIndex < TCollection(Cols).Count then begin
          Col := TCollection(Cols).Items[AIndex];
          PropInfo := GetPropInfo(Col, 'Title');
          if PropInfo <> nil then
            if PropInfo^.PropType^.Kind = tkClass then begin
              Title := GetObjectProp(Col, PropInfo);
              PropInfo := GetPropInfo(Title, 'Caption');
              if PropInfo <> nil then
                if PropInfo^.PropType^.Kind in [tkString, tkLString] then begin
                  APropertyValue := GetStrProp(Title, PropInfo);
                  Result := True;
                end;
            end;
        end;
    end;
end;

function UnitToX(PD: TPDFDocument; Units: Double): Longint;
begin
  Result := Round(Units * PD.Canvas.Font.PixelsPerInch);
end;

function UnitToY(PD: TPDFDocument; Units: Double): Longint;
begin
  Result := UnitToX(PD, Units);
end;

function ChangeNoVisibleSymbol(Str: string): string;
var
  tmpStr: string;
  i: Integer;
begin
  tmpStr := '';
  for i := 1 to Length(Str) do
    if Str[i] >= #32 then
      tmpStr := tmpStr + Str[i]
    else
      tmpStr := tmpStr + ' ';
  Result := tmpStr;
end;

function GetPageParam(WorkParam: TWorkParam; What: TGetParam; NumberPage: Integer): Integer;
begin
  Result := 0;
  if NumberPage = 1 then
    case What of
      Left: Result := WorkParam.RealIdentFromPage.First.Left;
      Right: Result := WorkParam.RealIdentFromPage.First.Right;
      Top: Result := WorkParam.RealIdentFromPage.First.Top;
      Bottom: Result := WorkParam.RealIdentFromPage.First.Bottom;
      Height: Result := WorkParam.DrawSizeToPage.HeightPageFirst;
      Width: Result := WorkParam.DrawSizeToPage.WidthPageFirst;
    end
  else
    case What of
      Left: Result := WorkParam.RealIdentFromPage.Old.Left;
      Right: Result := WorkParam.RealIdentFromPage.Old.Right;
      Top: Result := WorkParam.RealIdentFromPage.Old.Top;
      Bottom: Result := WorkParam.RealIdentFromPage.Old.Bottom;
      Height: Result := WorkParam.DrawSizeToPage.HeightPage;
      Width: Result := WorkParam.DrawSizeToPage.WidthPage;
    end;
end;

procedure SetupFont(_Canvas: TCanvas; _Font: TFont);
begin
  _Canvas.Font.Assign(_Font);
end;

procedure PaintTitle(PD: TPDFDocument; Param: TPDFPrintGridParam; WorkParam: TWorkParam; const PrintCaption: Boolean = True; const Page: Integer = -1; const PageCount: Integer = -1);
var
  DC: hDC;
  ARect: TRect;
  str: string;
begin
  PD.Canvas.Font.Size := 10;
  PD.Canvas.Font.Style := [];
  PD.Canvas.Font.Color := clBlack;
  PD.Canvas.Brush.Style := bsClear;
  PD.Canvas.Pen.Color := clBlack;
  DC := PD.Canvas.Handle;
  //Draw Top Line
  if Param.PrintTopLine then begin
    PD.Canvas.MoveTo(WorkParam.RealIdentFromPage.Old.Left, trunc(0.7 * WorkParam.RealIdentFromPage.Old.Top));
    PD.Canvas.LineTo(PD.PageWidth - WorkParam.RealIdentFromPage.Old.Right, trunc(0.7 * WorkParam.RealIdentFromPage.Old.Top));
  end;

  //Draw Bottom Line
  if Param.PrintBotomLine then begin
    PD.Canvas.MoveTo(WorkParam.RealIdentFromPage.Old.Left, PD.PageHeight - trunc(0.8 * WorkParam.RealIdentFromPage.Old.Bottom));
    PD.Canvas.LineTo(PD.PageWidth - WorkParam.RealIdentFromPage.Old.Right, PD.PageHeight - trunc(0.8 * WorkParam.RealIdentFromPage.Old.Bottom));
  end;

  //Calculate rectangle for Date|Page|Header Text
  ARect.Left := WorkParam.RealIdentFromPage.Old.Left;
  ARect.Right := PD.PageWidth - WorkParam.RealIdentFromPage.Old.Right;
  ARect.Top := 0;
  ARect.Bottom := trunc(0.7 * WorkParam.RealIdentFromPage.Old.Top);

  //Print Date Text
  if Param.CurentDate then
    str := DateToStr(Date)
  else
    str := DateToStr(Param.PrintedDate);
  if Param.PrintDate and (str <> '') then
    Windows.DrawText(DC, PChar(str), Length(str), ARect, DT_SINGLELINE or DT_LEFT or DT_BOTTOM);
  ARect.Left := ARect.Left + PD.Canvas.TextWidth(str) + UnitToX(PD, WorkParam.IndentGrid.HeaderText);

  //Print Page Text
  str := '';
  if Param.PrintPage and (Page > -1) then begin
    str := 'Page ' + inttostr(Page);
    if Param.PrintPages and (PageCount > -1) then
      str := str + ' of ' + inttostr(PageCount);
    Windows.DrawText(DC, PChar(str), Length(str), ARect, DT_SINGLELINE or DT_RIGHT or DT_BOTTOM);
    ARect.Right := ARect.Right - PD.Canvas.TextWidth(str) - UnitToX(PD, WorkParam.IndentGrid.HeaderText);
  end;

  PD.Canvas.Font.Style:=PD.Canvas.Font.Style+[fsBold, fsItalic];
  DC := PD.Canvas.Handle;
  //Print Header Text
  str := ChangeNoVisibleSymbol(Param.HeaderText);
  if Param.PrintHeaderText and (str <> '') then
    Windows.DrawText(DC, PChar(str), Length(str), ARect, DT_SINGLELINE or DT_LEFT or DT_BOTTOM);

  //Calculate rectangle for Footer Text
  ARect.Left := WorkParam.RealIdentFromPage.Old.Left;
  ARect.Right := PD.PageWidth - WorkParam.RealIdentFromPage.Old.Right;
  ARect.Top := PD.PageHeight - Trunc(0.8 * WorkParam.RealIdentFromPage.Old.Bottom);
  ARect.Bottom := PD.PageHeight;

  //Print Footer Text
  str := ChangeNoVisibleSymbol(Param.FooterText);
  if Param.PrintFooterText and (str <> '') then
    Windows.DrawText(DC, PChar(str), Length(str), ARect, DT_SINGLELINE or DT_LEFT or DT_TOP);

  SetupFont(PD.Canvas, Param.FontCaption);
  DC := PD.Canvas.Handle;
  //Calculate rectangle for Caption Text
  ARect.Left := Trunc(1.2 * WorkParam.RealIdentFromPage.Old.Left);
  ARect.Right := PD.PageWidth - Trunc(1.2 * WorkParam.RealIdentFromPage.Old.Right);
  ARect.Top := Trunc(0.74 * WorkParam.RealIdentFromPage.Old.Top);
  //ARect.Bottom:=PD.PageHeight;

  //Print Caption Text
  str := ChangeNoVisibleSymbol(Param.CaptionText);
  if Param.PrintCaptionText and (str <> '') and PrintCaption then
    Windows.DrawText(DC, PChar(str), Length(str), ARect, DT_SINGLELINE or DT_LEFT or DT_TOP);
end;

function FillMasterGrid(PD: TPDFDocument; Param: TPDFPrintGridParam; WorkParam: TWorkParam; var _GridInfo: TGridInfo; Grid: TCustomDBGrid; CalcWidth: Boolean): boolean;
var
  Col: Integer;
  _Width: Integer;
  Str: string;
begin
  Result := False;
  if not (Grid.Visible and (Grid.FieldCount > 0) and (Grid.DataSource.DataSet.RecordCount > 0)) then
    Exit;

  //Set well-known parametrs
  _GridInfo.PrintCaption := False;
  _GridInfo.CaptionGrid := '';
  _GridInfo.Grid.RowCount := 1;
  _GridInfo.RowHeight := WorkParam.RowHeight + WorkParam.Indent.Top + WorkParam.Indent.Bottom;
  SetLength(_GridInfo.Grid.ColumnsInPages, 0);
  _GridInfo.Grid.ColCount := 0;
  SetLength(_GridInfo.Grid.Columns, _GridInfo.Grid.ColCount);
  SetLength(_GridInfo.Grid.Items, _GridInfo.Grid.RowCount, _GridInfo.Grid.ColCount);
  //Create Data
  SetupFont(PD.Canvas, Param.FontGrid);
  for Col := 0 to Grid.FieldCount - 1 do
    if Grid.Fields[Col].DataType in [ftString, ftSmallint, ftInteger, ftWord,
         ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftAutoInc,
         ftMemo, ftFmtMemo, ftFixedChar, ftWideString, ftLargeint, ftGuid] then begin
      _GridInfo.Grid.ColCount := _GridInfo.Grid.ColCount + 1;
      SetLength(_GridInfo.Grid.Columns, _GridInfo.Grid.ColCount);
      SetLength(_GridInfo.Grid.Items, _GridInfo.Grid.RowCount, _GridInfo.Grid.ColCount);
      if not GetTitleCaptionColumn(Grid, Col, Str) then
        Str := Grid.Fields[Col].DisplayLabel;
      _GridInfo.Grid.Columns[_GridInfo.Grid.ColCount - 1].Name := Trim(str);
      _GridInfo.Grid.Items[0, _GridInfo.Grid.ColCount - 1] := Trim(Grid.Fields[Col].AsString);
      _GridInfo.Grid.Columns[_GridInfo.Grid.ColCount - 1].Align := DT_LEFT;
      //Calculate MaxWidth column for curent row
      if (not CalcWidth) and GetWidthColumn(Grid, Col, _Width) then
        _GridInfo.Grid.Columns[_GridInfo.Grid.ColCount - 1].MaxWidth := UnitToX(PD, _Width / WorkParam.scrPixelPerInch) + WorkParam.Indent.Left + WorkParam.Indent.Right
      else
        _GridInfo.Grid.Columns[_GridInfo.Grid.ColCount - 1].MaxWidth := PD.Canvas.TextWidth(_GridInfo.Grid.Columns[_GridInfo.Grid.ColCount - 1].Name) + WorkParam.Indent.Left + WorkParam.Indent.Right;
    end;

  Result := True;
end;

procedure GetDataColumns(PD: TPDFDocument; Param: TPDFPrintGridParam; WorkParam: TWorkParam; var _Grid: TGrid; _DataStrings: TStringList; CalcWidth: boolean);
var
  Row, Col, i, CurentWidth: Integer;
  str: string;
begin
  for Row := 0 to _DataStrings.Count - 1 do begin
    //Create Data for curent row
    Col := 0;
    str := '';
    SetupFont(PD.Canvas, Param.FontGrid);
    for i := 1 to Length(_DataStrings.Strings[Row]) do
      if _DataStrings.Strings[Row][i] = #9 then begin
        _Grid.Items[Row, Col] := Trim(str);
        //Calculate MaxWidth column for curent row
        if CalcWidth then begin
          CurentWidth := PD.Canvas.TextWidth(_Grid.Items[Row, Col]) + WorkParam.Indent.Left + WorkParam.Indent.Right;
          if CurentWidth > _Grid.Columns[Col].MaxWidth then
            _Grid.Columns[Col].MaxWidth := CurentWidth;
        end;
        Inc(Col);
        str := '';
      end else
        str := str + _DataStrings.Strings[Row][i];
    _Grid.Items[Row, Col] := Trim(str);
    //Calculate MaxWidth last column for curent row
    if CalcWidth then begin
      CurentWidth := PD.Canvas.TextWidth(_Grid.Items[Row, Col]) + WorkParam.Indent.Left + WorkParam.Indent.Right;
      if CurentWidth > _Grid.Columns[Col].MaxWidth then
        _Grid.Columns[Col].MaxWidth := CurentWidth;
    end;
  end;
end;

procedure SaveAllToStrings(Grid: TCustomDBGrid; DataStrings: TStringList);
var B: TBookmark;
    str, str1: string;
    i: Integer;
begin
  DataStrings.Clear;
  B := Grid.DataSource.DataSet.GetBookmark;
  try
    Grid.DataSource.DataSet.DisableControls;
    try
      str := '';
      for i := 0 to Grid.FieldCount - 1 do
        if Grid.Fields[i].DataType in [ftString, ftSmallint, ftInteger, ftWord,
           ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftAutoInc,
           ftMemo, ftFmtMemo, ftFixedChar, ftWideString, ftLargeint, ftGuid] then begin
          if str <> '' then
            str := str + #09;
          if not GetTitleCaptionColumn(Grid, i, Str1) then
            Str1 := Grid.Fields[i].DisplayLabel;
          str := str + TrimRight(Str1);
        end;
      DataStrings.Add(str);

      Grid.DataSource.DataSet.First;
      while not Grid.DataSource.DataSet.Eof do begin
        str := '';
        for i := 0 to Grid.FieldCount - 1 do
          if Grid.Fields[i].DataType in [ftString, ftSmallint, ftInteger, ftWord,
             ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftAutoInc,
             ftMemo, ftFmtMemo, ftFixedChar, ftWideString, ftLargeint, ftGuid] then begin
            if str <> '' then
              str := str + #09;
            str := str + TrimRight(Grid.Fields[i].AsString);
          end;
        DataStrings.Add(str);
        Grid.DataSource.DataSet.Next;
      end;
    finally
      Grid.DataSource.DataSet.EnableControls;
    end;
  finally
    Grid.DataSource.DataSet.GotoBookmark(B);
    Grid.DataSource.DataSet.FreeBookmark(B);
  end;
end;

procedure FillDetailGrid(PD: TPDFDocument; Param: TPDFPrintGridParam; WorkParam: TWorkParam; var _GridInfo: TGridInfo; DetailGrid: TllDetailGrid; CalcWidth: Boolean);
var
  DataStrings: TStringList;
  RCol, Col, _Width: Integer;
  Align: TAlignment;
  Str: string;
begin
  DataStrings := TStringList.Create;
  try
    SaveAllToStrings(DetailGrid.Grid, DataStrings);
    _GridInfo.CaptionGrid := DetailGrid.CaptionGrid;
    _GridInfo.PrintCaption := (_GridInfo.CaptionGrid <> '');
    _GridInfo.RowHeight := WorkParam.RowHeight + WorkParam.Indent.Top + WorkParam.Indent.Bottom;
    _GridInfo.Grid.ColCount := DetailGrid.Grid.FieldCount;
    _GridInfo.Grid.RowCount := DataStrings.Count;
    SetLength(_GridInfo.Grid.ColumnsInPages, 0);
    SetLength(_GridInfo.Grid.Columns, _GridInfo.Grid.ColCount);
    SetLength(_GridInfo.Grid.Items, _GridInfo.Grid.RowCount, _GridInfo.Grid.ColCount);
    SetupFont(PD.Canvas, Param.FontGrid);
    RCol := 0;
    for Col := 0 to DetailGrid.Grid.FieldCount - 1 do
      if DetailGrid.Grid.Fields[Col].DataType in [ftString, ftSmallint, ftInteger, ftWord,
         ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, ftAutoInc,
         ftMemo, ftFmtMemo, ftFixedChar, ftWideString, ftLargeint, ftGuid] then begin
        if not GetTitleCaptionColumn(DetailGrid.Grid, Col, Str) then
          Str := DetailGrid.Grid.Fields[Col].DisplayLabel;
        _GridInfo.Grid.Columns[RCol].Name := Trim(Str);
        if Param.AlignDataInColumns then begin
          if Param.GetAlignFromField or (not GetAlignmentColumn(DetailGrid.Grid, Col, Align)) then
            Align := DetailGrid.Grid.Fields[Col].Alignment;
        end else
          Align := Param.DefaultAlignDataInColumns;
        case Align of
          taRightJustify: _GridInfo.Grid.Columns[RCol].Align := DT_RIGHT;
          taLeftJustify: _GridInfo.Grid.Columns[RCol].Align := DT_LEFT;
          taCenter: _GridInfo.Grid.Columns[RCol].Align := DT_CENTER;
        end;
        if not(CalcWidth) and GetWidthColumn(DetailGrid.Grid, Col, _Width) then
          _GridInfo.Grid.Columns[RCol].MaxWidth := UnitToX(PD, _Width / WorkParam.scrPixelPerInch) + WorkParam.Indent.Left + WorkParam.Indent.Right
        else
          _GridInfo.Grid.Columns[RCol].MaxWidth := PD.Canvas.TextWidth(_GridInfo.Grid.Columns[RCol].Name) + WorkParam.Indent.Left + WorkParam.Indent.Right;
        Inc(RCol);
      end;
    _GridInfo.Grid.ColCount := RCol;
    SetLength(_GridInfo.Grid.Columns, _GridInfo.Grid.ColCount);
    GetDataColumns(PD, Param, WorkParam, _GridInfo.Grid, DataStrings, CalcWidth);
  finally
    DataStrings.Free;
  end;
end;

procedure AnaliseLayout(PD: TPDFDocument; Param: TPDFPrintGridParam; var WorkParam: TWorkParam; var _MasterGrid: TGridInfo; var _DetailGrids: TGrids);
var
  CurentGrid, Col, Row: Integer;
  tmpPIW: Integer;
  Rules: TStringList;
  x, y, Page: Integer;
  a, Element: Integer;
  CurentPagesInWidth: Integer;
  Elements: array of Integer;

  procedure AddEndElement(Page: Integer; Element: Integer; Row1: Integer = 0; Col1: Integer = 0);
  begin
    if (Element >= 0) and (Col1 >= 0) and (Row1 >= 0) then begin
      WorkParam.ReportPages.Pages[Page - 1].Elements[Element].Col1 := Col1;
      WorkParam.ReportPages.Pages[Page - 1].Elements[Element].Row1 := Row1;
    end;
  end;

  function AddElement(Page: Integer; x, y: Integer; NumberGrid: Integer;
    TypeInformation: TllTypeInformation; Row: Integer = 0; Col: Integer = 0): integer;
  begin
    if WorkParam.ReportPages.CountPages < Page then begin
      WorkParam.ReportPages.CountPages := Page;
      SetLength(WorkParam.ReportPages.Pages, WorkParam.ReportPages.CountPages);
      WorkParam.ReportPages.Pages[Page - 1].NumberPage := Page;
      WorkParam.ReportPages.Pages[Page - 1].CountElements := 0;
    end;
    if TypeInformation = lltiNone then begin
      WorkParam.ReportPages.Pages[Page - 1].CountElements := 0;
      SetLength(WorkParam.ReportPages.Pages[Page - 1].Elements, WorkParam.ReportPages.Pages[Page - 1].CountElements);
    end else begin
      WorkParam.ReportPages.Pages[Page - 1].CountElements := WorkParam.ReportPages.Pages[Page - 1].CountElements + 1;
      SetLength(WorkParam.ReportPages.Pages[Page - 1].Elements, WorkParam.ReportPages.Pages[Page - 1].CountElements);
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].x := x;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].y := y;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].NumberGrid := NumberGrid;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].TypeInformation := TypeInformation;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].Col := Col;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].Row := Row;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].Col1 := 0;
      WorkParam.ReportPages.Pages[Page - 1].Elements[WorkParam.ReportPages.Pages[Page - 1].CountElements - 1].Row1 := 0;
    end;
    Result := WorkParam.ReportPages.Pages[Page - 1].CountElements - 1;
  end;

begin
  WorkParam.PageCount := 0;

  SetupFont(PD.Canvas, Param.FontGrid);
  //Init variable
  y := 0;
  x := 0;
  Page := WorkParam.PageCount + 1;

  SetLength(_MasterGrid.Grid.ColumnsInPages, 1);
  _MasterGrid.Grid.ColumnsInPages[0] := 0;
  tmpPIW := 1;

  if _MasterGrid.Grid.ColCount > 0 then begin
    Element := AddElement(Page, x, y, -1, lltiGrid);

    //Add Master Grid
    for Col := 0 to _MasterGrid.Grid.ColCount - 1 do begin
      if (y + _MasterGrid.RowHeight - 1) <= GetPageParam(WorkParam, Height, Page) then
        y := y + _MasterGrid.RowHeight - 1 - 2
      else begin
        if _MasterGrid.RowHeight <= GetPageParam(WorkParam, Height, Page) then begin
          Inc(Page);
          y:=0;
          AddEndElement(Page - 1, Element, 0, Col - 1);
          Element := AddElement(Page, x, y, -1, lltiGrid, 0, Col);
          y := _MasterGrid.RowHeight - 1;
        end else begin
          if y <> 0 then begin
            Inc(Page);
            y := 0;
            AddEndElement(Page - 1, Element, 0, Col - 1);
            Element := AddElement(Page, x, y, -1, lltiGrid, 0, Col);
          end;
          y := GetPageParam(WorkParam, Height, Page) - 1;
        end;
      end;
    end;
    AddEndElement(Page, Element, 0, _MasterGrid.Grid.ColCount - 1);

    //Add Indent Bottom
    AddElement(Page, x, y, -1, lltiIndentGridBottom);
    if (y + UnitToY(PD, WorkParam.IndentGrid.GridBottom)) > (GetPageParam(WorkParam, Height, Page) - 1) then
      y := GetPageParam(WorkParam, Height, Page) - 1
    else
      y := y + UnitToY(PD, WorkParam.IndentGrid.GridBottom);
  end;

  //Set calculated variables
    _MasterGrid.PageInWidth := tmpPIW;
  CurentPagesInWidth := _MasterGrid.PageInWidth;

  //Set Print Info for Detail Grids (only Calculate Page in Width)
  for CurentGrid := 0 to Length(_DetailGrids) - 1 do begin
    //Calculate Page in Width
    tmpPIW := 1;
    x := 0;
    for Col := 0 to _DetailGrids[CurentGrid].Grid.ColCount - 1 do begin
      if Col = 0 then begin
        SetLength(_DetailGrids[CurentGrid].Grid.ColumnsInPages, 1);
        _DetailGrids[CurentGrid].Grid.ColumnsInPages[0] := Col;
      end;
      if (x + _DetailGrids[CurentGrid].Grid.Columns[Col].MaxWidth - 1) > WorkParam.DrawSizeToPage.WidthPage then begin  //Only for 2-n pages
        if (_DetailGrids[CurentGrid].Grid.Columns[Col].MaxWidth - 1) <= WorkParam.DrawSizeToPage.WidthPage then begin //Only for 2-n pages
          SetLength(_DetailGrids[CurentGrid].Grid.ColumnsInPages, Length(_DetailGrids[CurentGrid].Grid.ColumnsInPages) + 1);
          _DetailGrids[CurentGrid].Grid.ColumnsInPages[Length(_DetailGrids[CurentGrid].Grid.ColumnsInPages) - 1] := Col;
          Inc(tmpPIW);
          x := _DetailGrids[CurentGrid].Grid.Columns[Col].MaxWidth - 1 - 1;
        end else begin
          if x <> 0 then begin
            SetLength(_DetailGrids[CurentGrid].Grid.ColumnsInPages, Length(_DetailGrids[CurentGrid].Grid.ColumnsInPages) + 1);
            _DetailGrids[CurentGrid].Grid.ColumnsInPages[Length(_DetailGrids[CurentGrid].Grid.ColumnsInPages) - 1] := Col;
            Inc(tmpPIW);
          end;
          x := WorkParam.DrawSizeToPage.WidthPage - 1; //Anly for 2-n pages
        end;
      end else
        x := x + _DetailGrids[CurentGrid].Grid.Columns[Col].MaxWidth - 1 - 1;
    end;
    //Set calculated variables
    _DetailGrids[CurentGrid].PageInWidth := tmpPIW;
  end;

  //Set Print Info for Detail Grids
  x := 0;
  for CurentGrid := 0 to Length(_DetailGrids) - 1 do begin
    if CurentPagesInWidth <> _DetailGrids[CurentGrid].PageInWidth then begin
      if y > 0 then begin
        Inc(Page, CurentPagesInWidth);
        y := 0;
      end;
      CurentPagesInWidth := _DetailGrids[CurentGrid].PageInWidth;
    end;
    SetLength(Elements, CurentPagesInWidth);

    SetupFont(PD.Canvas, Param.FontCaptionGrid);
    //Add Indent for Caption Grid
    if _DetailGrids[CurentGrid].PrintCaption and (_DetailGrids[CurentGrid].CaptionGrid <> '') then begin
      a := PD.Canvas.TextHeight(_DetailGrids[CurentGrid].CaptionGrid);
      if (y+_DetailGrids[CurentGrid].RowHeight * 2 + UnitToY(PD, WorkParam.IndentGrid.GridTop) + a) > GetPageParam(WorkParam, Height, Page) then
        if (_DetailGrids[CurentGrid].RowHeight * 2 + UnitToY(PD, WorkParam.IndentGrid.GridTop) + a) <= GetPageParam(WorkParam, Height, Page) then begin
          y:=0;
          Inc(Page, CurentPagesInWidth);
        end;
      if (y + a) <= (GetPageParam(WorkParam, Height, Page) - 1) then begin
        AddElement(Page, x, y, CurentGrid, lltiCaption);
        y := y + a + 1; //Add 1 pixel for indent
      end
      else
      if a <= GetPageParam(WorkParam, Height, Page) then begin
        Page := WorkParam.ReportPages.CountPages;
        Inc(Page, CurentPagesInWidth);
        AddElement(Page, x, 0, CurentGrid, lltiCaption);
        y := a + 1; //Add 1 pixel for indent
      end else begin
        if y = 0 then
          AddElement(Page, x, y, CurentGrid, lltiCaption)
        else begin
          Page := WorkParam.ReportPages.CountPages;
          Inc(Page, CurentPagesInWidth);
          AddElement(Page, x, 0, CurentGrid, lltiCaption);
        end;
        y := GetPageParam(WorkParam, Height, Page) - 1;
      end;
    end;

    //Add Indent Top
    AddElement(Page, x, y, CurentGrid, lltiIndentGridTop);
    if (y + UnitToY(PD, WorkParam.IndentGrid.GridTop) + _DetailGrids[CurentGrid].RowHeight) > GetPageParam(WorkParam, Height, Page) then
      y := GetPageParam(WorkParam, Height, Page) - 1
    else
      y := y + UnitToY(PD, WorkParam.IndentGrid.GridTop);

    //Calculate end of Detail Grid
    SetupFont(PD.Canvas, Param.FontGrid);
    if (y > 0) and ((y+_DetailGrids[CurentGrid].RowHeight * 2) > GetPageParam(WorkParam, Height, Page)) then begin
      y:=0;
      Inc(Page, CurentPagesInWidth);
    end;
    for a := 0 to CurentPagesInWidth - 1 do
      Elements[a] := AddElement(Page + a, x, y, CurentGrid, lltiGrid, 0, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a]);
    for Row := 0 to _DetailGrids[CurentGrid].Grid.RowCount - 1 do begin
      if (y + _DetailGrids[CurentGrid].RowHeight - 1) <= (GetPageParam(WorkParam, Height, Page) - 1) then
        y := y + _DetailGrids[CurentGrid].RowHeight - 1 - 2
      else
      if (_DetailGrids[CurentGrid].RowHeight - 1) <= GetPageParam(WorkParam, Height, Page) then begin
        for a := 0 to CurentPagesInWidth - 1 do
          if a = CurentPagesInWidth - 1 then
            AddEndElement(Page + a, Elements[a], Row - 1, _DetailGrids[CurentGrid].Grid.ColCount - 1)
          else
            AddEndElement(Page + a, Elements[a], Row - 1, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a + 1] - 1);
        Inc(Page, CurentPagesInWidth);
        for a := 0 to CurentPagesInWidth - 1 do
          Elements[a] := AddElement(Page + a, x, 0, CurentGrid, lltiGrid, Row, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a]);
        y := _DetailGrids[CurentGrid].RowHeight - 1 - 2;
      end else begin
        if y <> 0 then begin
          for a := 0 to CurentPagesInWidth - 1 do
            if a = CurentPagesInWidth - 1 then
              AddEndElement(Page + a, Elements[a], Row - 1, _DetailGrids[CurentGrid].Grid.ColCount - 1)
            else
              AddEndElement(Page + a, Elements[a], Row - 1, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a + 1] - 1);
          Inc(Page, CurentPagesInWidth);
          for a := 0 to CurentPagesInWidth - 1 do
            Elements[a] := AddElement(Page + a, x, 0, CurentGrid, lltiGrid, Row, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a]);
        end;
        y := GetPageParam(WorkParam, Height, Page) - 1;
      end;
    end;
    for a := 0 to CurentPagesInWidth - 1 do
      if a = CurentPagesInWidth - 1 then
        AddEndElement(Page + a, Elements[a], _DetailGrids[CurentGrid].Grid.RowCount - 1, _DetailGrids[CurentGrid].Grid.ColCount - 1)
      else
        AddEndElement(Page + a, Elements[a], _DetailGrids[CurentGrid].Grid.RowCount - 1, _DetailGrids[CurentGrid].Grid.ColumnsInPages[a + 1] - 1);

    //Add Indent Bottom
    AddElement(Page, x, y, CurentGrid, lltiIndentGridBottom);
    if (y + UnitToY(PD, WorkParam.IndentGrid.GridBottom)) > (GetPageParam(WorkParam, Height, Page) - 1) then
      y := GetPageParam(WorkParam, Height, Page) - 1
    else
      y := y + UnitToY(PD, WorkParam.IndentGrid.GridBottom);
  end;

  WorkParam.PageCount := WorkParam.ReportPages.CountPages;
end;

procedure AddPage(PD: TPDFDocument; Param: TPDFPrintGridParam ; WorkParam: TWorkParam; CurentPage: Integer; FirstPageCorrect: Integer = 0);
begin
  PD.NewPage;
  if FirstPageCorrect > -1 then
    PaintTitle(PD, Param, WorkParam, CurentPage = 1, CurentPage + FirstPageCorrect, WorkParam.PageCount + FirstPageCorrect);
end;

procedure _PrintMasterGrid(PD: TPDFDocument; Param: TPDFPrintGridParam ; WorkParam: TWorkParam; var _MasterGrid: TGridInfo; NumberPage: Integer; Element: TllElmentMarkingInfo);
var
  Col, y, MaxWidth: Integer;
  DC: HDC;
  _Left, _Right, _Top, _Bottom: Integer;
  RectFrame, RectText: TRect;
begin
  _Left := GetPageParam(WorkParam, Left, NumberPage) + Element.x;
  _Right := PD.PageWidth - GetPageParam(WorkParam, Right, NumberPage) - 1;
  _Top := GetPageParam(WorkParam, Top, NumberPage) + Element.y;
  _Bottom := PD.PageHeight - GetPageParam(WorkParam, Bottom, NumberPage) - 1;
  SetupFont(PD.Canvas, Param.FontGrid);
  PD.Canvas.Brush.Color := Param.ColorCaptionGridFill;
  PD.Canvas.Pen.Color := Param.ColorGridLines;
  DC := PD.Canvas.Handle;
  y := _Top;
  MaxWidth := 0;
  if Param.AlignMasterGridCaption then
    for Col := Element.Col to Element.Col1 do
      if _MasterGrid.Grid.Columns[Col].MaxWidth > MaxWidth then
        MaxWidth := _MasterGrid.Grid.Columns[Col].MaxWidth;
  for Col := Element.Col to Element.Col1 do begin
    RectFrame.Left := _Left;
    RectFrame.Top := y;
    if Param.AlignMasterGridCaption then
      RectFrame.Right := RectFrame.Left + MaxWidth - 1
    else
      RectFrame.Right := RectFrame.Left + _MasterGrid.Grid.Columns[Col].MaxWidth - 1;
    if RectFrame.Right > _Right then
      RectFrame.Right := _Right;
    RectFrame.Bottom := RectFrame.Top + _MasterGrid.RowHeight - 1;
    if RectFrame.Bottom > _Bottom then
      RectFrame.Bottom := _Bottom;
    PD.Canvas.Brush.Color := Param.ColorCaptionGridFill;
    PD.Canvas.Pen.Color := Param.ColorGridLines;
    PD.Canvas.Brush.Style := bsSolid;
    PD.Canvas.Rectangle(RectFrame);
    RectText.Left := RectFrame.Left + WorkParam.Indent.Left;
    RectText.Top := RectFrame.Top + WorkParam.Indent.Top;
    RectText.Right := RectFrame.Right - WorkParam.Indent.Right;
    RectText.Bottom := RectFrame.Bottom - WorkParam.Indent.Bottom;
    Windows.DrawText(DC, PChar(_MasterGrid.Grid.Columns[Col].Name), Length(_MasterGrid.Grid.Columns[Col].Name), RectText, DT_SINGLELINE or DT_Left or DT_VCENTER);

    RectFrame.Left := RectFrame.Right - 1 - 1;
    RectFrame.Right := _Right;
    PD.Canvas.Brush.Color := Param.ColorGridFill;
    PD.Canvas.Pen.Color := Param.ColorGridLines;
    PD.Canvas.Brush.Style := bsSolid;
    PD.Canvas.Rectangle(RectFrame);
    RectText.Left := RectFrame.Left + WorkParam.Indent.Left;
    RectText.Right := RectFrame.Right - WorkParam.Indent.Right;
    Windows.DrawText(DC, PChar(_MasterGrid.Grid.Items[0, Col]), Length(_MasterGrid.Grid.Items[0, Col]), RectText, DT_SINGLELINE or DT_Left or DT_VCENTER);
    y := RectFrame.Bottom - 1 - 1;
  end;
end;

procedure _PrintDetailGrid(PD: TPDFDocument; Param: TPDFPrintGridParam ; WorkParam: TWorkParam; var _DetailGrids: TGrids; NumberPage: Integer; Element: TllElmentMarkingInfo);
var
  Col, Row, y, x, AddX: Integer;
  DC: HDC;
  _Left, _Right, _Top, _Bottom: Integer;
  RectFrame, RectText: TRect;
begin
  _Left := GetPageParam(WorkParam, Left, NumberPage) + Element.x;
  _Right := PD.PageWidth - GetPageParam(WorkParam, Right, NumberPage) - 1;
  _Top := GetPageParam(WorkParam, Top, NumberPage) + Element.y;
  _Bottom := PD.PageHeight - GetPageParam(WorkParam, Bottom, NumberPage) - 1;
  SetupFont(PD.Canvas, Param.FontGrid);
  PD.Canvas.Brush.Color := Param.ColorCaptionGridFill;
  PD.Canvas.Brush.Style := bsSolid;
  PD.Canvas.Pen.Color := Param.ColorGridLines;
  DC := PD.Canvas.Handle;
  y := _Top;

  AddX := 0;
  if Param.AlignColumnsInPage and ((Element.Col1 - Element.Col) > -1) and
     ((Element.Col1 <> (_DetailGrids[Element.NumberGrid].Grid.ColCount-1)) or
      (Param.AlignColumnsInLastPage and (Element.Col1 =(_DetailGrids[Element.NumberGrid].Grid.ColCount-1)))) then begin
    for Col := Element.Col to Element.Col1 do
      AddX := AddX + _DetailGrids[Element.NumberGrid].Grid.Columns[Col].MaxWidth - 1;
    AddX := WorkParam.DrawSizeToPage.WidthPage - (AddX + 1); //Anly for 2-n pages
    if AddX > 0 then
      AddX := AddX div (Element.Col1 - Element.Col + 1)
    else
      AddX := 0;
  end;

  for Row := Element.Row to Element.Row1 do begin
    x := _Left;
    for Col := Element.Col to Element.Col1 do begin
      RectFrame.Left := x;
      RectFrame.Top := y;
      if Param.AlignColumnsInPage and (Col = Element.Col1) and
         ((Element.Col1 <> (_DetailGrids[Element.NumberGrid].Grid.ColCount-1)) or
         (Param.AlignColumnsInLastPage and (Element.Col1 =(_DetailGrids[Element.NumberGrid].Grid.ColCount-1)))) then
        RectFrame.Right := _Right
      else begin
        RectFrame.Right := RectFrame.Left + _DetailGrids[Element.NumberGrid].Grid.Columns[Col].MaxWidth - 1 + AddX;
        if RectFrame.Right > _Right then
          RectFrame.Right := _Right;
      end;
      RectFrame.Bottom := RectFrame.Top + _DetailGrids[Element.NumberGrid].RowHeight - 1;
      if RectFrame.Bottom > _Bottom then
        RectFrame.Bottom := _Bottom;
      if Row = 0 then
        PD.Canvas.Brush.Color := Param.ColorCaptionGridFill
      else
        PD.Canvas.Brush.Color := Param.ColorGridFill;
      PD.Canvas.Rectangle(RectFrame);

      RectText.Left := RectFrame.Left + WorkParam.Indent.Left;
      RectText.Top := RectFrame.Top + WorkParam.Indent.Top;
      RectText.Right := RectFrame.Right - WorkParam.Indent.Right;
      RectText.Bottom := RectFrame.Bottom - WorkParam.Indent.Bottom;

      if Row = 0 then
        Windows.DrawText(DC, PChar(_DetailGrids[Element.NumberGrid].Grid.Items[Row, Col]), Length(_DetailGrids[Element.NumberGrid].Grid.Items[Row, Col]), RectText, DT_SINGLELINE or DT_CENTER or DT_VCENTER)
      else
        Windows.DrawText(DC, PChar(_DetailGrids[Element.NumberGrid].Grid.Items[Row, Col]), Length(_DetailGrids[Element.NumberGrid].Grid.Items[Row, Col]), RectText, DT_SINGLELINE or _DetailGrids[Element.NumberGrid].Grid.Columns[Col].Align{DT_LEFT} or DT_VCENTER);
      x := RectFrame.Right - 1 - 1;
    end;
    y := RectFrame.Bottom - 1 - 1;
  end;
end;

procedure _PrintCaption(PD: TPDFDocument; Param: TPDFPrintGridParam ; WorkParam: TWorkParam; var _DetailGrids: TGrids; Element: TllElmentMarkingInfo; NumberPage: Integer);
var
  DC: HDC;
  _Left, _Right, _Top, _Bottom: Integer;
  RectText: TRect;
  Str: string;
begin
  _Left := GetPageParam(WorkParam, Left, NumberPage) + Element.x;
  _Right := PD.PageWidth - GetPageParam(WorkParam, Right, NumberPage) - 1;
  _Top := GetPageParam(WorkParam, Top, NumberPage) + Element.y;
  _Bottom := PD.PageHeight - GetPageParam(WorkParam, Bottom, NumberPage) - 1;
  SetupFont(PD.Canvas, Param.FontCaptionGrid);
  if PD.Canvas.Brush.Style = bsSolid then
    PD.Canvas.Brush.Style := bsClear;
  DC := PD.Canvas.Handle;

  RectText.Left := _Left;
  RectText.Right := _Right;
  RectText.Top := _Top;
  RectText.Bottom := _Bottom;

  Str := ChangeNoVisibleSymbol(_DetailGrids[Element.NumberGrid].CaptionGrid);
  Windows.DrawText(DC, PChar(Str), Length(Str), RectText, DT_SINGLELINE or DT_Left or DT_TOP);
end;

procedure GenerateReport(PD: TPDFDocument; Param: TPDFPrintGridParam ; WorkParam: TWorkParam; var _MasterGrid: TGridInfo; var _DetailGrids: TGrids; FirstPageCorrect: Integer = 0);
var
  _Page, Page, _Element: Integer;
begin
  for _Page := 0 to WorkParam.ReportPages.CountPages - 1 do begin
    Page := WorkParam.ReportPages.Pages[_Page].NumberPage;
    if Page > 1 then
      AddPage(PD, Param, WorkParam, Page, FirstPageCorrect);
    for _Element := 0 to WorkParam.ReportPages.Pages[_Page].CountElements - 1 do
      case WorkParam.ReportPages.Pages[_Page].Elements[_Element].TypeInformation of
        lltiGrid:if WorkParam.ReportPages.Pages[_Page].Elements[_Element].NumberGrid = -1 then
                   _PrintMasterGrid(PD, Param, WorkParam, _MasterGrid, Page, WorkParam.ReportPages.Pages[_Page].Elements[_Element])
                 else
                   _PrintDetailGrid(PD, Param, WorkParam, _DetailGrids, Page, WorkParam.ReportPages.Pages[_Page].Elements[_Element]);
        lltiCaption: _PrintCaption(PD, Param, WorkParam, _DetailGrids, WorkParam.ReportPages.Pages[_Page].Elements[_Element], Page);
      end;
  end;
end;

procedure SetUpParam(PD: TPDFDocument; PrintGridParam: TPDFPrintGridParam; var WorkParam: TWorkParam);
begin
  with WorkParam do begin
    scrPixelPerInch := screen.PixelsPerInch; //Resolution screen
    SetupFont(PD.Canvas, PrintGridParam.FontCaption);
    RealIdentFromPage.First.Left := UnitToX(PD, PrintGridParam.Margin.Left);
    RealIdentFromPage.First.Top := UnitToY(PD, PrintGridParam.Margin.Top) + (PD.Canvas.TextHeight(PrintGridParam.CaptionText) - Trunc((1 - 0.74) * UnitToY(PD, PrintGridParam.Margin.Top)) + 1);
    RealIdentFromPage.First.Right := UnitToX(PD, PrintGridParam.Margin.Right);
    RealIdentFromPage.First.Bottom := UnitToY(PD, PrintGridParam.Margin.Bottom);
    RealIdentFromPage.Old.Left := UnitToX(PD, PrintGridParam.Margin.Left);
    RealIdentFromPage.Old.Top := UnitToY(PD, PrintGridParam.Margin.Top);
    RealIdentFromPage.Old.Right := UnitToX(PD, PrintGridParam.Margin.Right);
    RealIdentFromPage.Old.Bottom := UnitToY(PD, PrintGridParam.Margin.Bottom);
    DrawSizeToPage.WidthPage := PD.PageWidth - RealIdentFromPage.Old.Left - RealIdentFromPage.Old.Right;
    DrawSizeToPage.HeightPage := PD.PageHeight - RealIdentFromPage.Old.Top - RealIdentFromPage.Old.Bottom;
    DrawSizeToPage.WidthPageFirst := PD.PageWidth - RealIdentFromPage.First.Left - RealIdentFromPage.First.Right; //Don`t ready for first page
    DrawSizeToPage.HeightPageFirst := PD.PageHeight - RealIdentFromPage.First.Top - RealIdentFromPage.First.Bottom;
    Indent.Left := UnitToX(PD, PrintGridParam.GridTextIndent.Left / 10000) + 1;
    Indent.Right := UnitToX(PD, PrintGridParam.GridTextIndent.Right / 10000) + 2;
    Indent.Top := UnitToX(PD, PrintGridParam.GridTextIndent.Top / 10000) + 1;
    Indent.Bottom := UnitToX(PD, PrintGridParam.GridTextIndent.Bottom / 10000) + 2;
    IndentGrid.HeaderText := PrintGridParam.Indent.HeaderText;
    IndentGrid.GridTop := PrintGridParam.Indent.GridTop;
    IndentGrid.GridBottom := PrintGridParam.Indent.GridBottom;
    if IndentGrid.HeaderText < 0 then
      IndentGrid.HeaderText := 0;
    if IndentGrid.GridTop < 0 then
      IndentGrid.GridTop := 0;
    if IndentGrid.GridBottom < 0 then
      IndentGrid.GridBottom := 0;
    PageCount := 0;
    ReportPages.CountPages := 0;
    SetLength(ReportPages.Pages, PageCount);

    SetupFont(PD.Canvas, PrintGridParam.FontGrid);
    RowHeight := Trunc(PD.Canvas.TextHeight('^_Wg') * 1.2);
  end;
end;

{------------------------------------------------------------------------------}

{ TPDFMDDBGridPrinter }

constructor TPDFMDDBGridPrinter.Create(AOwner: TComponent);
begin
  inherited;
  FDetailGrids := TllDetailGrids.Create(Self);
  FReportParams := TllReportParams.Create;
end;

destructor TPDFMDDBGridPrinter.Destroy;
begin
  FDetailGrids.Free;
  FReportParams.Free;
  inherited;
end;

procedure TPDFMDDBGridPrinter.SetDetailGrids(Value: TllDetailGrids);
begin
  FDetailGrids.Assign(Value);
end;

procedure TPDFMDDBGridPrinter.Print;
var
  WorkParam: TWorkParam;
  i: Integer;
  _MasterGrid: TGridInfo;
  _DetailGrids: TGrids;
  CountDetailGrids: Integer;
  NextRecord: Boolean;
  RealCountPages: Integer;
  NumberFistPage: Integer;
begin
  if not (Assigned(FPDFDocument) and Assigned(FPrintGridParam) and Assigned(FMasterGrid)) then
    Exit;

  //Paint Doc
  if FReportParams.FBeginDoc then
    FPDFDocument.BeginDoc;
  WorkParam := TWorkParam.Create;
  try
    //Calculate global variable
    NumberFistPage := FPDFDocument.GetCurrentPageIndex;
    SetUpParam(FPDFDocument, FPrintGridParam, WorkParam);
    RealCountPages := 0;
    if Assigned(FOnFirstRecord) then
      FOnFirstRecord(Self);
    repeat
      WorkParam.ReportPages.CountPages := 0;
      SetLength(WorkParam.ReportPages.Pages, WorkParam.ReportPages.CountPages);
      CountDetailGrids := 0;
      SetLength(_DetailGrids, CountDetailGrids);

      //Create Grids
      if FillMasterGrid(FPDFDocument, FPrintGridParam, WorkParam, _MasterGrid, FMasterGrid, FPrintGridParam.CalculateWidth) then begin
        for i := 0 to FDetailGrids.Count - 1 do
          if FDetailGrids[i].Grid.Visible and (FDetailGrids[i].Grid.FieldCount > 0) then begin
            if (FDetailGrids[i].Grid.DataSource.DataSet.RecordCount = 0) and not FPrintGridParam.PrintEmptyGrid then
              Continue;
            CountDetailGrids := CountDetailGrids + 1;
            SetLength(_DetailGrids, CountDetailGrids);
            FillDetailGrid(FPDFDocument, FPrintGridParam, WorkParam, _DetailGrids[CountDetailGrids - 1], FDetailGrids[i], FPrintGridParam.CalculateWidth);
          end;

        //Analise Layout
        AnaliseLayout(FPDFDocument, FPrintGridParam, WorkParam, _MasterGrid, _DetailGrids);
      end;

      if WorkParam.PageCount > 0 then begin
        GenerateReport(FPDFDocument, FPrintGridParam, WorkParam, _MasterGrid, _DetailGrids, -1);
        RealCountPages := RealCountPages + WorkParam.PageCount;
      end;

      NextRecord := False;

      if FMultiRecordsReport and Assigned(FOnNextRecord) then begin
        FOnNextRecord(Self, NextRecord);
        if NextRecord then
          FPDFDocument.NewPage;
      end;
    until not NextRecord;
    for i := 1 to RealCountPages do begin
      FPDFDocument.SetCurrentPage(NumberFistPage + i - 1);
{$WARNINGS OFF}
      PaintTitle(FPDFDocument, FPrintGridParam, WorkParam, i = 1, i + FPrintGridParam.CountPagesBeforeReport, RealCountPages + FPrintGridParam.CountPagesBeforeReport);
{$WARNINGS ON}
    end;
  finally
    WorkParam.Free;
    if FReportParams.FEndDoc then
      FPDFDocument.EndDoc;
  end;
end;


{ TPDFDBGridPrinter }

constructor TPDFDBGridPrinter.Create(AOwner: TComponent);
begin
  inherited;
  FReportParams := TllReportParams.Create;
end;

destructor TPDFDBGridPrinter.Destroy;
begin
  FReportParams.Free;
  inherited;
end;

procedure TPDFDBGridPrinter.Print;
var
  WorkParam: TWorkParam;
  _MasterGrid: TGridInfo;
  _DetailGrids: TGrids;
  CountDetailGrids: Integer;
  DetailGrid: TllDetailGrid;
begin
  if not (Assigned(FPDFDocument) and Assigned(FPrintGridParam) and Assigned(FGrid)) then
    Exit;

  //Paint Doc
  if FReportParams.FBeginDoc then
    FPDFDocument.BeginDoc;
  WorkParam := TWorkParam.Create;
  try
    //Calculate global variable
    SetUpParam(FPDFDocument, PrintGridParam, WorkParam);

    WorkParam.ReportPages.CountPages := 0;
    SetLength(WorkParam.ReportPages.Pages, WorkParam.ReportPages.CountPages);
    CountDetailGrids := 0;
    SetLength(_DetailGrids, CountDetailGrids);

    _MasterGrid.CaptionGrid := '';
    _MasterGrid.PrintCaption := False;
    _MasterGrid.PageInWidth := 1;
    _MasterGrid.RowHeight := WorkParam.RowHeight;
    _MasterGrid.Grid.ColCount := 0;
    _MasterGrid.Grid.RowCount := 0;
    SetLength(_MasterGrid.Grid.Columns, 0);
    SetLength(_MasterGrid.Grid.ColumnsInPages, 0);
    SetLength(_MasterGrid.Grid.Items, 0);

    //Create Grids
    if Grid.Visible and (Grid.FieldCount > 0) and not ((Grid.DataSource.DataSet.RecordCount = 0) and not PrintGridParam.PrintEmptyGrid) then begin
      Inc(CountDetailGrids);
      SetLength(_DetailGrids, CountDetailGrids);
      DetailGrid := TllDetailGrid.Create(nil);
      try
        DetailGrid.Grid := FGrid;
        DetailGrid.CaptionGrid := '';
        FillDetailGrid(FPDFDocument, PrintGridParam, WorkParam, _DetailGrids[0], DetailGrid, PrintGridParam.CalculateWidth);
      finally
        DetailGrid.Free;
      end;

      //Analise Layout
      AnaliseLayout(FPDFDocument, PrintGridParam, WorkParam, _MasterGrid, _DetailGrids);
      if WorkParam.PageCount > 0 then begin
{$WARNINGS OFF}
        PaintTitle(FPDFDocument, PrintGridParam, WorkParam, True, 1 + PrintGridParam.CountPagesBeforeReport, WorkParam.PageCount + PrintGridParam.CountPagesBeforeReport);
{$WARNINGS ON}
        GenerateReport(FPDFDocument, PrintGridParam, WorkParam, _MasterGrid, _DetailGrids, PrintGridParam.CountPagesBeforeReport);
      end;
    end;
  finally
    WorkParam.Free;
    if FReportParams.FEndDoc then
      FPDFDocument.EndDoc;
  end;
end;


{ TPDFDBGridsPrinter }

constructor TPDFDBGridsPrinter.Create(AOwner: TComponent);
begin
  inherited;
  FGrids := TllDetailGrids.Create(Self);
  FReportParams := TllReportParams.Create;
end;

destructor TPDFDBGridsPrinter.Destroy;
begin
  FGrids.Free;
  FReportParams.Free;
  inherited;
end;

procedure TPDFDBGridsPrinter.SetDetailGrids(Value: TllDetailGrids);
begin
  FGrids.Assign(Value);
end;

procedure TPDFDBGridsPrinter.Print;
var
  WorkParam: TWorkParam;
  i: Integer;
  _MasterGrid: TGridInfo;
  _DetailGrids: TGrids;
  CountDetailGrids: Integer;
begin
  if not (Assigned(FPDFDocument) and Assigned(FPrintGridParam)) then
    Exit;

  //Paint Doc
  if FReportParams.FBeginDoc then
    FPDFDocument.BeginDoc;
  WorkParam := TWorkParam.Create;
  try
    //Calculate global variable
    SetUpParam(FPDFDocument, PrintGridParam, WorkParam);

    _MasterGrid.CaptionGrid := '';
    _MasterGrid.PrintCaption := False;
    _MasterGrid.PageInWidth := 1;
    _MasterGrid.RowHeight := WorkParam.RowHeight;
    _MasterGrid.Grid.ColCount := 0;
    _MasterGrid.Grid.RowCount := 0;
    SetLength(_MasterGrid.Grid.Columns, 0);
    SetLength(_MasterGrid.Grid.ColumnsInPages, 0);
    SetLength(_MasterGrid.Grid.Items, 0);

    WorkParam.ReportPages.CountPages := 0;
    SetLength(WorkParam.ReportPages.Pages, WorkParam.ReportPages.CountPages);
    CountDetailGrids := 0;
    SetLength(_DetailGrids, CountDetailGrids);

    //Create Grids
    for i := 0 to FGrids.Count - 1 do
      if FGrids[i].Grid.Visible and (FGrids[i].Grid.FieldCount > 0) then begin
        if (FGrids[i].Grid.DataSource.DataSet.RecordCount = 0) and not PrintGridParam.PrintEmptyGrid then
          Continue;
        CountDetailGrids := CountDetailGrids + 1;
        SetLength(_DetailGrids, CountDetailGrids);
        FillDetailGrid(FPDFDocument, PrintGridParam, WorkParam, _DetailGrids[CountDetailGrids - 1], FGrids[i], PrintGridParam.CalculateWidth);
      end;
    if CountDetailGrids > 0 then begin
      //Analise Layout
      AnaliseLayout(FPDFDocument, PrintGridParam, WorkParam, _MasterGrid, _DetailGrids);
      if WorkParam.PageCount > 0 then begin
{$WARNINGS OFF}
        PaintTitle(FPDFDocument, PrintGridParam, WorkParam, True, 1 + PrintGridParam.CountPagesBeforeReport, WorkParam.PageCount + PrintGridParam.CountPagesBeforeReport);
{$WARNINGS ON}
        GenerateReport(FPDFDocument, PrintGridParam, WorkParam, _MasterGrid, _DetailGrids, PrintGridParam.CountPagesBeforeReport);
      end;
    end;
  finally
    WorkParam.Free;
    if FReportParams.FEndDoc then
      FPDFDocument.EndDoc;
  end;
end;


{ PaintTitlePage }

procedure PaintTitlePage(PD: TPDFDocument; PrintGridParam: TPDFPrintGridParam; PrintCaption: Boolean; const Page: Integer = -1; const PageCount: Integer = -1);
var WorkParam: TWorkParam;
begin
  WorkParam := TWorkParam.Create;
  try
    SetUpParam(PD, PrintGridParam, WorkParam);
    PaintTitle(PD, PrintGridParam, WorkParam, PrintCaption, Page, PageCount);
  finally
    WorkParam.Free;
  end;
end;

end.

