{
*********************************************************************
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,
  {$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
    );


  TgtRichViewInterface = class(TgtExportInterface)
  private
    {$IFDEF ExpIntfRepLinkEnabled}
    {$IFDEF RichView17Up}
    FOptions: TgtRVOptions;
    FLinkZoom: TgtRVLinkZoom;
    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: String;
      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;
      ScaleToScreenDPI: Boolean = True); 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: String;
      PageIndex, Left, Top: Integer;
  end;
  TLinkToCheckpoint = class (TCollectionItem)
    public
      CheckpointName: String;
      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: String;
    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: String;
  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.Width;
  if LinkZoom = rvglzPageWidth then
    PageHeight := 1
  else
    PageHeight := FFullPageSize.Height;
  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: String;
  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; ScaleToScreenDPI: Boolean);

  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;
    if ScaleToScreenDPI then
    begin
      IgtDocumentEngine(Engine).Page.Width  :=
        Round(ARVPrint.Preview100PercentWidth * Screen.PixelsPerInch / RV_GetPixelsPerInch);
      IgtDocumentEngine(Engine).Page.Height :=
        Round(ARVPrint.Preview100PercentHeight * Screen.PixelsPerInch / RV_GetPixelsPerInch);
    end;
    for LI := 1 to ARVPrint.PagesCount do
    begin
      if LI = 1 then
      begin
        StartDocument;
        if Engine.EngineStatus <> esStarted then
          Exit;
      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
      {$ENDIF}
        ARVPrint.DrawPage(LI, Engine.Canvas, True);
      DoProgress(LI, rvpsProceeding);
    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
        Exit;
      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; ScaleToScreenDPI: Boolean);
begin

end;

procedure TgtRichViewInterface.RenderDocument(ARVHelper: TRVReportHelper);
begin

end;
{$IFEND}

end.
