{
  *********************************************************************
  Gnostice eDocEngine
  Copyright (c) Gnostice Information Technologies Private Limited
  http://www.gnostice.com
  *********************************************************************
}

{ ------------------------------------ }
{ Editor Options }
{ ------------------------------------ }
{ }
{ Use Tab Character = False }
{ }
{ ------------------------------------ }

{$I ..\gtExpIntf.inc}
{$I ..\gtDefines.inc}
{$I ..\gtDocDefines.inc}
unit gtRichViewIntf;

interface

uses
  Classes, Windows, Forms,
{$IFDEF ExpIntfRepLinkEnabled}
  RichView, RVReport, CRVData, PtblRV, RVTypes,
{$ENDIF}
  gtCstDocEng, gtXportIntf, gtExPDFEng, gtPDFEng,
  gtUtils3;

type

{$IFNDEF ExpIntfRepLinkEnabled}
  TRVPrint = class
  end;

  TRVReportHelper = class
  end;
{$ENDIF}
{$IFDEF gtDelphiXE2Up}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  // Options for export
  TgtRVOption = (rvgoSaveExternalLinks,
    // saving external links (to URLs) in PDF
    rvgoSaveLinksToCheckpoints // saving internal links (to checkpoints) in PDF
    );
  TgtRVOptions = set of TgtRVOption;

  // Zooming options for internal links (how the destination is displayed)
  TgtRVLinkZoom = (rvglzPageWidth, // fit the page width
    rvglzPage // fit the full page
    );
{$IFDEF ExpIntfRepLinkEnabled}
  TgtRVCheckpointName =
{$IFDEF RichView173Up}TRVUnicodeString{$ELSE}String{$ENDIF};
{$ENDIF}

  TgtRichViewInterface = class(TgtExportInterface)
  private
    FOptions: TgtRVOptions;
    FLinkZoom: TgtRVLinkZoom;
{$IFDEF ExpIntfRepLinkEnabled}
{$IFDEF RichView17Up}
    FFullPageSize: TSize;
    FDocOffset: TPoint;
    FCheckpoints, FLinks: TCollection;
    FOldOnDrawHyperlink: TRVDrawHyperlinkEvent;
    FOldOnDrawCheckpoint: TRVDrawCheckpointEvent;
    FOldProcessAfterEachPage: Boolean;
    procedure DoDrawHyperlink(Sender: TCustomRVPrint; RVData: TCustomRVData;
      ItemNo: Integer; R: TRect);
    procedure DoDrawCheckpoint(Sender: TCustomRVPrint; RVData: TCustomRVData;
      ItemNo: Integer; X, Y: Integer);
    function FindCheckpoint(const CheckpointName: TgtRVCheckpointName;
      var PageIndex, Left, Top: Integer): Boolean;
    procedure SaveLinksToCheckpoints;
    procedure InitLinkCollections(ARVPrint: TCustomRVPrint);
    procedure DoneLinkCollections(ARVPrint: TCustomRVPrint);
{$ENDIF}
{$ENDIF}
  public
    constructor Create(AOwner: TComponent); override;
    procedure RenderDocument(ARVPrint: TRVPrint; IsFormatted: Boolean
{$IFDEF RichView17Up}; ScaleToScreenDPI: Boolean{$ENDIF}); overload;
    procedure RenderDocument(ARVHelper: TRVReportHelper); overload;
  published
{$IFDEF RichView17Up}
    property Options: TgtRVOptions read FOptions write FOptions
      default [rvgoSaveExternalLinks, rvgoSaveLinksToCheckpoints];
    property LinkZoom: TgtRVLinkZoom read FLinkZoom write FLinkZoom
      default rvglzPageWidth;
{$ENDIF}
    property Engine;
  end;

implementation

{$IFDEF ExpIntfRepLinkEnabled}

uses
  RVScroll, RVFuncs, RVItem, RVStyle, PtRVData;
{$ENDIF}
{ ================================ TgtRichViewInterface ======================== }

constructor TgtRichViewInterface.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
{$IFDEF RichView17Up}
  FOptions := [rvgoSaveExternalLinks, rvgoSaveLinksToCheckpoints];
  FLinkZoom := rvglzPageWidth;
{$ENDIF}
end;

{$IF Defined(ExpIntfRepLinkEnabled)}
{$IFDEF RichView17Up}

type
  TCheckpointLocation = class(TCollectionItem)
  public
    Name: TgtRVCheckpointName;
    PageIndex, Left, Top: Integer;
  end;

  TLinkToCheckpoint = class(TCollectionItem)
  public
    CheckpointName: TgtRVCheckpointName;
    PageIndex: Integer;
    Area: TRect;
  end;

  { ------------------------------------------------------------------------------ }
  { Event: Occurs when drawing a checkpoint.
    We add the location of this checkpoint to FCheckpoints collection }
procedure TgtRichViewInterface.DoDrawCheckpoint(Sender: TCustomRVPrint;
  RVData: TCustomRVData; ItemNo, X, Y: Integer);
var
  CheckpointData: TCheckpointData;
  CPTag: TRVTag;
  CPName: TgtRVCheckpointName;
  RE: Boolean;
begin
  if Assigned(FOldOnDrawCheckpoint) then
    FOldOnDrawCheckpoint(Sender, RVData, ItemNo, X, Y);
  if FCheckpoints = nil then
    exit;
  CheckpointData := RVData.GetItemCheckpoint(ItemNo);
  RVData.GetCheckpointInfo(CheckpointData, CPTag, CPName, RE);
  with FCheckpoints.Add as TCheckpointLocation do
  begin
    Name := CPName;
    PageIndex := Engine.CurrentPage;
    Left := X + FDocOffset.X;
    Top := Y + FDocOffset.Y;
  end;
end;

{ ------------------------------------------------------------------------------ }
{ Returns position of checkpoint with the given name }
function TgtRichViewInterface.FindCheckpoint(const CheckpointName
  : TgtRVCheckpointName; var PageIndex, Left, Top: Integer): Boolean;
var
  i: Integer;
  Item: TCheckpointLocation;
begin
  for i := 0 to FCheckpoints.Count - 1 do
  begin
    Item := TCheckpointLocation(FCheckpoints.Items[i]);
    if Item.Name = CheckpointName then
    begin
      PageIndex := Item.PageIndex;
      Left := Item.Left;
      Top := Item.Top;
      Result := True;
      exit;
    end;
  end;
  Result := False;
end;

{ ------------------------------------------------------------------------------ }
{ Saves all links to checkpoints to PDF }
procedure TgtRichViewInterface.SaveLinksToCheckpoints;
var
  i, PageIndex, Left, Top: Integer;
  Item: TLinkToCheckpoint;
  GotoAction: TgtAnnotGoToAction;
  LinkAnnot: TgtPDFLinkAnnot;
  PageWidth, PageHeight: Integer;
begin
  if (FLinks = nil) or not(rvgoSaveLinksToCheckpoints in Options) then
    exit;
  PageWidth := FFullPageSize.cx;
  if LinkZoom = rvglzPageWidth then
    PageHeight := 1
  else
    PageHeight := FFullPageSize.cy;
  for i := 0 to FLinks.Count - 1 do
  begin
    Item := TLinkToCheckpoint(FLinks.Items[i]);
    if FindCheckpoint(Item.CheckpointName, PageIndex, Left, Top) then
    begin
      (Engine as TgtPDFEngine).SetWorkingPage(Item.PageIndex);
      LinkAnnot := TgtPDFLinkAnnot.Create;
      LinkAnnot.Rect := gtRect(Item.Area.Left, Item.Area.Top, Item.Area.Right,
        Item.Area.Bottom);
      // LinkAnnot.BorderWidth := 1;
      GotoAction := TgtAnnotGoToAction.Create;
      GotoAction.Page := PageIndex;
      GotoAction.Rect := gtRect(0, Top, PageWidth, Top + PageHeight);
      GotoAction.Options := goFitRect;
      LinkAnnot.Action := GotoAction;
      (Engine as TgtPDFEngine).AddAnnotItem(LinkAnnot);
    end;
  end;
end;

{ ------------------------------------------------------------------------------ }
{ Event: on drawing hyperlinks. If this is an external hyperlink, we write it
  immediately. If this is a link to another location in the same document,
  we store it in FLinks collection
  (we will add it later, in SaveLinksToCheckpoints). }
procedure TgtRichViewInterface.DoDrawHyperlink(Sender: TCustomRVPrint;
  RVData: TCustomRVData; ItemNo: Integer; R: TRect);
var
  Target: TgtRVCheckpointName;
  LinkAction: TgtAnnotLinkAction;
  LinkAnnot: TgtPDFLinkAnnot;
begin
  if Assigned(FOldOnDrawHyperlink) then
    FOldOnDrawHyperlink(Sender, RVData, ItemNo, R);
  Target := RVData.GetItemTag(ItemNo);
  if Target = '' then
    exit;
  if Target[1] = '#' then
  begin
    if rvgoSaveLinksToCheckpoints in Options then
      with FLinks.Add as TLinkToCheckpoint do
      begin
        CheckpointName := Copy(Target, 2, Length(Target) - 1);
        PageIndex := Engine.CurrentPage;
        Area := R;
      end;
  end
  else
  begin
    if rvgoSaveExternalLinks in Options then
    begin
      LinkAnnot := TgtPDFLinkAnnot.Create;
      LinkAnnot.Rect := gtRect(R.Left, R.Top, R.Right, R.Bottom);
      // LinkAnnot.BorderWidth := 1;
      LinkAction := TgtAnnotLinkAction.Create;
      LinkAction.URI := Target;
      LinkAnnot.Action := LinkAction;
      (Engine as TgtPDFEngine).AddAnnotItem(LinkAnnot);
    end;
  end;
end;

{ ------------------------------------------------------------------------------ }
procedure TgtRichViewInterface.InitLinkCollections(ARVPrint: TCustomRVPrint);
begin
  if not(Engine is TgtPDFEngine) then
    exit;
  FOldOnDrawHyperlink := ARVPrint.OnDrawHyperlink;
  FOldOnDrawCheckpoint := ARVPrint.OnDrawCheckpoint;
  FOldProcessAfterEachPage := TgtPDFEngine(Engine)
    .Preferences.ProcessAfterEachPage;
  TgtPDFEngine(Engine).Preferences.ProcessAfterEachPage := False;
  ARVPrint.OnDrawHyperlink := DoDrawHyperlink;
  ARVPrint.OnDrawCheckpoint := DoDrawCheckpoint;
  FCheckpoints := TCollection.Create(TCheckpointLocation);
  FLinks := TCollection.Create(TLinkToCheckpoint);
end;

{ ------------------------------------------------------------------------------ }
procedure TgtRichViewInterface.DoneLinkCollections(ARVPrint: TCustomRVPrint);
begin
  if not(Engine is TgtPDFEngine) then
    exit;
  ARVPrint.OnDrawHyperlink := FOldOnDrawHyperlink;
  ARVPrint.OnDrawCheckpoint := FOldOnDrawCheckpoint;
  TgtPDFEngine(Engine).Preferences.ProcessAfterEachPage :=
    FOldProcessAfterEachPage;
  RVFreeAndNil(FCheckpoints);
  RVFreeAndNil(FLinks);
end;
{$ENDIF}

{ ------------------------------------------------------------------------------ }
{
  Exporting ARVPrint using the specified Engine.

  if IsFormatted = False, we format ARVPrint before exporting.

  If ScaleToScreenDPI = True (default), we set the Engine's page size
  equal to the print preview size in 100% zoom, and then draw pages
  scaled to this size. Exporting hyperlinks is not supported in this mode.

  If ScaleToScreenDPI = False, it is assumed that the Engine's page size,
  InputXRes and InputYRes are already set according to the printer,
  and pages are drawn unscaled. If this is a PDF export, hyperlinks are
  exported according to Options property.

  If TRichView version is older than 17, ScaleToScreenDPI is ignored
  (always processed as ScaleToScreenDPI = True)

  In all modes, the Engine's margins and header and footer height are zeroed.

  If ARVPrint.OnSendingToPrinter is assigned, it is called.

}
procedure TgtRichViewInterface.RenderDocument(ARVPrint: TRVPrint;
  IsFormatted: Boolean{$IFDEF RichView17Up}; ScaleToScreenDPI: Boolean{$ENDIF});

  procedure DoProgress(PageCompleted: Integer; Step: TRVPrintingStep);
  begin
    if Assigned(ARVPrint.OnSendingToPrinter) then
      ARVPrint.OnSendingToPrinter(ARVPrint.rv, PageCompleted, Step);
  end;

var
  LI: Integer;
  OldUnits: TgtUnitType;
begin
  {$IFDEF RichView16Up}
  ARVPrint.MetafileCompatibility := True;
  {$ENDIF}
  OldUnits := Engine.MeasurementUnit;
  {$IFDEF RichView17Up}
  if (Engine is TgtPDFEngine) and not ScaleToScreenDPI then
  begin
    InitLinkCollections(ARVPrint);
    FFullPageSize.cx := TCustomMainPtblRVData(ARVPrint.rv.RVData).GetPageWidth;
    FFullPageSize.cy := TCustomMainPtblRVData(ARVPrint.rv.RVData).GetPageHeight;
    FDocOffset.X := 0;
    FDocOffset.Y := 0;
  end;
  with IgtDocumentEngine(Engine).Page do
  begin
    LeftMargin := 0;
    RightMargin := 0;
    TopMargin := 0;
    BottomMargin := 0;
    HeaderHeight := 0;
    FooterHeight := 0;
  end;
  {$ENDIF}
  DoProgress(0, rvpsStarting);
  try
    if not IsFormatted then
      ARVPrint.FormatPages(rvdoALL);
    Engine.MeasurementUnit := muPixels;
    {$IFDEF RichView17Up}
    if ScaleToScreenDPI then
    begin
      IgtDocumentEngine(Engine).Page.Width :=
        {$IFDEF RichView18Up}
        ARVPrint.GetPreview100PercentWidth(Screen.PixelsPerInch);
        {$ELSE}
        Round(ARVPrint.Preview100PercentWidth * Screen.PixelsPerInch /
          RV_GetPixelsPerInch);
        {$ENDIF}
      IgtDocumentEngine(Engine).Page.Height :=
        {$IFDEF RichView18Up}
        ARVPrint.GetPreview100PercentHeight(Screen.PixelsPerInch);
        {$ELSE}
        Round(ARVPrint.Preview100PercentHeight * Screen.PixelsPerInch /
          RV_GetPixelsPerInch);
        {$ENDIF}
    end;
    {$ENDIF}
    for LI := 1 to ARVPrint.PagesCount do
    begin
      if LI = 1 then
      begin
        StartDocument;
        if Engine.EngineStatus <> esStarted then
        begin
          DocStarted := False;
          exit;
        end;
      end
      else
        IgtDocumentEngine(Engine).NewPage;
      {$IFDEF RichView17Up}
      if ScaleToScreenDPI then
        ARVPrint.DrawPreview(LI, Engine.Canvas,
          Rect(0, 0, Round(IgtDocumentEngine(Engine).Page.Width),
          Round(IgtDocumentEngine(Engine).Page.Height)))
      else

        ARVPrint.DrawPage(LI, Engine.Canvas, True);
      {$ELSE}
      ARVPrint.DrawPreview(LI, Engine.Canvas,
        Rect(0, 0, Round(IgtDocumentEngine(Engine).Page.Width),
        Round(IgtDocumentEngine(Engine).Page.Height)))
      {$ENDIF}
      {$IFDEF RichView17Up}DoProgress(LI, rvpsProceeding);{$ENDIF}
    end;
    {$IFDEF RichView17Up}
    SaveLinksToCheckpoints;
    {$ENDIF}
    EndDocument;
  finally
    {$IFDEF RichView17Up}
    if (Engine is TgtPDFEngine) and not ScaleToScreenDPI then
      DoneLinkCollections(ARVPrint);
    {$ENDIF}
    Engine.MeasurementUnit := OldUnits;
    DoProgress(ARVPrint.PagesCount, rvpsFinished);
  end;
end;

{ ------------------------------------------------------------------------------ }
{
  Exporting ARVHelper using the specified Engine.

  Before exporting, formatting ARVHelper according to the Engine's page size.
  Unlike TRVPrint export, we respect the Engine's margins.

  Hyperlinks are exported according to Options property.

}
procedure TgtRichViewInterface.RenderDocument(ARVHelper: TRVReportHelper);
var
  LI, LWidth, LHeight: Integer;
  OldUnits: TgtUnitType;
begin
{$IFDEF RichView16Up}
  ARVHelper.MetafileCompatibility := True;
{$ENDIF}
  OldUnits := Engine.MeasurementUnit;
  Engine.MeasurementUnit := muPixels;
  try
{$IFDEF RichView17Up}
    if Engine is TgtPDFEngine then
    begin
      InitLinkCollections(ARVHelper);
      with IgtDocumentEngine(Engine).Page do
      begin
        FFullPageSize.cx := Round(Width);
        FFullPageSize.cy := Round(Height);
        FDocOffset.X := Round(LeftMargin);
        FDocOffset.Y := Round(TopMargin + HeaderHeight);
      end;
    end;
{$ENDIF}
    try
      with IgtDocumentEngine(Engine).Page do
      begin
        LWidth := Round(Width - LeftMargin - RightMargin);
        LHeight := Round(Height - TopMargin - BottomMargin - HeaderHeight -
          FooterHeight);
      end;
      StartDocument;
      if Engine.EngineStatus <> esStarted then
      begin
        DocStarted := False;
        exit;
      end;
      ARVHelper.Init(Engine.Canvas, Round(LWidth));
      LI := 0;
      while ARVHelper.FormatNextPage(Round(LHeight)) do
      begin
        if LI <> 0 then
          IgtDocumentEngine(Engine).NewPage;
        ARVHelper.DrawPage(LI + 1, Engine.Canvas, True, LHeight);
        Inc(LI);
      end;
{$IFDEF RichView17Up}
      SaveLinksToCheckpoints;
{$ENDIF}
      EndDocument;
    finally
{$IFDEF RichView17Up}
      if Engine is TgtPDFEngine then
        DoneLinkCollections(ARVHelper);
{$ENDIF}
    end;
  finally
    Engine.MeasurementUnit := OldUnits;
  end;
end;
{$ELSE}

procedure TgtRichViewInterface.RenderDocument(ARVPrint: TRVPrint;
  IsFormatted: Boolean{$IFDEF RichView17Up}; ScaleToScreenDPI: Boolean{$ENDIF});
begin

end;

procedure TgtRichViewInterface.RenderDocument(ARVHelper: TRVReportHelper);
begin

end;
{$IFEND}

end.
