{******************************************}
{                                          }
{         Excel export filter              }
{                                          }
{                                          }
{                                          }
{******************************************}

unit U_frOLEExl;

{$I Fr.inc}

interface

uses
  Windows, U_LNG, U_BaseConstants, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, extctrls, Clipbrd, Printers, ComObj, FR_Class, XLSFile, XLSWorkbook, XLSFormat
//{$IFDEF Delphi6}
, Variants,
//{$ENDIF},
  U_Common_Classes, FR_Progr, FR_Ctrls, siComp, siLngLnk, jpeg, PDF, cxLookAndFeelPainters,
  cxButtons, cxGraphics, cxLookAndFeels, Menus;

function ComparePoints(Item1, Item2: Pointer): Integer;
function CompareObjects(Item1, Item2: Pointer): Integer;

const

  SheetName = cfrOLEExl_Msg1; 

  Xdivider = 1;

  Ydivider = 1.3;
  XLMaxHeight = 409;

  xlLeft = -4131;
  xlRight = -4152;
  xlTop = -4160;
  xlCenter = -4108 ;
  xlBottom = -4107;
  xlJustify = -4130 ;
  xlThin = 2;
  xlHairline = 1;
  xlNone = -4142;
  xlAutomatic = -4105;
  xlInsideHorizontal = 12 ;
  xlInsideVertical = 11 ;
  xlEdgeBottom = 9 ;
  xlEdgeLeft = 7 ;
  xlEdgeRight = 10 ;
  xlEdgeTop = 8 ;
  xlSolid = 1 ;
  xlTextWindows = 20 ;
  xlNormal = -4143 ;
  xlNoChange = 1 ;
  xlPageBreakManual = -4135 ;

  tgUnXls = '#UNXLS';

type

  TExlStartExportPageEvent = procedure(Sender: TObject; ACaption: string; AObjCount: Integer) of object;
  TExlProgressExportPageEvent = procedure(Sender: TObject; var AWasCancel: Boolean; AObjIndex, AObjectCount: Integer) of object;
  TExlEndExportPageEvent = procedure(Sender: TObject; AWasCancel: Boolean) of object;


  TfrOLEExcelSet = class(TForm)
    OK: TcxButton;
    Cancel: TcxButton;
      GroupPageSettings: TGroupBox;
      GroupPageRange: TGroupBox;
      LeftM: TLabel;
      Pages: TLabel;
      E_Range: TEdit;
      Descr: TLabel;
      E_LMargin: TEdit;
      TopM: TLabel;
      E_TMargin: TEdit;
      ScX: TLabel;
      E_ScaleX: TEdit;
      Label2: TLabel;
      ScY: TLabel;
      E_ScaleY: TEdit;
      Label9: TLabel;
      GroupCellProp: TGroupBox;
      CB_Merged: TCheckBox;
      CB_Align: TCheckBox;
      CB_FillColor: TCheckBox;
      CB_Borders: TCheckBox;
      CB_WrapWords: TCheckBox;
      CB_FontName: TCheckBox;
      CB_FontSize: TCheckBox;
      CB_FontStyle: TCheckBox;
      CB_FontColor: TCheckBox;
      CB_PageBreaks: TCheckBox;
      CB_OpenExcel: TCheckBox;
      Better: TButton;
      Faster: TButton;
      CB_Pictures: TCheckBox;
      lng_Forms: TsiLangLinked;

      procedure BetterClick(Sender: TObject);
      procedure FasterClick(Sender: TObject);
      procedure FormCreate(Sender: TObject);
   private
      procedure Localize;
  end;

  TFrExcel = class;

  TObjCell = class(TObject)
  public
    Value: integer;
  end;

  TObjPos = class(TObject)
  public
    obj: integer;
    x,y: integer;
    dx, dy: integer;
  end;

  TfrBasicExpFilter = class(TfrExportFilter)
    private
      FFileCaption: String;
      FFileName: String;
      FTitle: String;

      FCanceledExport: Boolean;
      FLeaveCellsWithTag: Boolean;
      FTagForLeaveCell: String;

      FOnStartExportPageEvent: TExlStartExportPageEvent;
      FOnProgressExportPageEvent: TExlProgressExportPageEvent;
      FOnEndExportPageEvent: TExlEndExportPageEvent;
    public
      constructor Create(AOwner: TComponent); override;

      property FileCaption: String read FFileCaption write FFileCaption;
      property FileName: String read FFileName write FFileName;
      property Title: string read FTitle write FTitle; 
      property LeaveCellsWithTag: Boolean read FLeaveCellsWithTag write FLeaveCellsWithTag; //#From Oleg#
      property TagForLeaveCell: String read FTagForLeaveCell write FTagForLeaveCell;        //#From Oleg#
      property OnStartExportPageEvent: TExlStartExportPageEvent read FOnStartExportPageEvent write FOnStartExportPageEvent;
      property OnProgressExportPageEvent: TExlProgressExportPageEvent read FOnProgressExportPageEvent write FOnProgressExportPageEvent;
      property OnEndExportPageEvent: TExlEndExportPageEvent read FOnEndExportPageEvent write FOnEndExportPageEvent;
  end;

  TMyfrOleExl = class(TfrBasicExpFilter)
    private
      CurrentPage: integer;
      FirstPage: boolean;
      CurY: integer;
      RX: TList;
      RY: TList;
      ObjectPos: TList;
      PageObj: TList;
      Excel: TFrExcel;
      CY, LastY: integer;
      frExportSet: TfrOLEExcelSet;
      pgList: TStringList;
      pgBreakList: TStringList;
      PicFormat: Word;
      PicData: Cardinal;
      PicPalette: HPALETTE;
      CntPics: integer;
      expMerged, expWrapWords, expFillColor, expBorders, expAlign,
        expPageBreaks, expFontName, expFontSize, expFontStyle,
        expFontColor, expPictures, expOpenAfter: boolean;
      expScaleX, expScaleY, expTopMargin, expLeftMargin: Double;

      FTmpDir: String;
      FTmpFiles: TStringList;
      //FOnStartExportPageEvent: TExlStartExportPageEvent;
      //FOnProgressExportPageEvent: TExlProgressExportPageEvent;
      //FOnEndExportPageEvent: TExlEndExportPageEvent;

      procedure ObjCellAdd(Vector: TList; Value: integer);
      procedure ObjPosAdd(Vector: TList; x, y, dx, dy, obj: integer);
      procedure DeleteMultiplePoint(Vector: TList);
      procedure ClearLastPage;
      procedure OrderObjectByCells;

      procedure ExportPage;

      function CleanReturns(Str: string): string;
      procedure AfterExport(const FileName: string);
      procedure ClearTmpFiles;
    public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;
      function ShowModal: Word; override;
      procedure OnBeginDoc; override;
      procedure OnEndDoc; override;
      procedure OnEndPage; override;
      procedure OnBeginPage; override;
      procedure OnData(x, y: Integer; View: TfrView); override;
    published
      property CellsAlign : Boolean read expAlign write expAlign default True;
      property CellsBorders : Boolean read expBorders write expBorders default True;
      property CellsFillColor : Boolean read expFillColor write expFillColor default True;
      property CellsFontColor : Boolean read expFontColor write expFontColor default True;
      property CellsFontName : Boolean read expFontName write expFontName default True;
      property CellsFontSize : Boolean read expFontSize write expFontSize default True;
      property CellsFontStyle : Boolean read expFontStyle write expFontStyle default True;
      property CellsMerged : Boolean read expMerged write expMerged default True;
      property CellsWrapWords : Boolean read expWrapWords write expWrapWords default True;
      property ExportPictures : Boolean read expPictures write expPictures default True;
      property LeftMargin : Double read expLeftMargin write expLeftMargin;
      property OpenExcelAfterExport : Boolean read expOpenAfter write expOpenAfter default False;
      property PageBreaks : Boolean read expPageBreaks write expPageBreaks default True;
      property TopMargin : Double read expTopMargin write expTopMargin;

      {property LeaveCellsWithTag: Boolean read FLeaveCellsWithTag write FLeaveCellsWithTag; //#From Oleg#
      property TagForLeaveCell: String read FTagForLeaveCell write FTagForLeaveCell;        //#From Oleg#
      property OnStartExportPageEvent: TExlStartExportPageEvent read FOnStartExportPageEvent write FOnStartExportPageEvent;
      property OnProgressExportPageEvent: TExlProgressExportPageEvent read FOnProgressExportPageEvent write FOnProgressExportPageEvent;
      property OnEndExportPageEvent: TExlEndExportPageEvent read FOnEndExportPageEvent write FOnEndExportPageEvent;
      }
  end;

  TFrExcel = class(TComponent)
  private
    IsOpened: Boolean;
    IsVisible: Boolean;
    BorderStyle: TXLBorderStyle;
    RangeXF: TRange;
    XF: TXLSFile;
  protected
    procedure SetVisible(DoShow: Boolean);
    function GetCell(x, y: Integer): string;
    procedure SetCell(x, y: Integer; const Value: string);
    function Pos2Str(Pos: Integer): string;
    function IntToCoord(X, Y: Integer): string;
  public
    constructor Create (AOwner: TComponent); override;
    destructor Destroy; override;
    procedure OpenExcel;
    procedure SetRange(x, y, dx, dy: integer);
    procedure SetColSize(x: integer; Size: Extended);
    procedure SetRowSize(y: integer; Size: Extended);
    procedure MergeCells;
    procedure SetPageMargin(Left, Right, Top, Bottom: Extended; Orient: integer);
    procedure SetCellBorderColorRGB(AFrame, ARGBColor: integer);
    procedure SetCellBorderStyle(AObj: TfrView);
    procedure SetCellFontName(FontName: string);
    procedure SetCellFontSize(FontSize: integer);
    procedure SetCellFontColor(FontColor: Integer);
    procedure SetCellFontStyle(Style: TFontStyles);
    procedure SetCellHAlign(Horiz: Integer);
    procedure SetCellNumFormat(Format: char);
    procedure SetCellHAlignM(Horiz: Integer);
    procedure SetCellVAlign(Vert: Integer);
    procedure SetCellVAlignM(Vert: Integer);
    procedure SetCellOrientation(Grad: Integer);
    procedure SetCellFrame(Frame: integer);
    procedure SetCellFrameInsideV;
    procedure SetCellFrameInsideH;
    procedure SetCellFillColor(AColor: integer);
    procedure SendArrayValue(Arr: variant);
    property Cell[x, y: Integer]: string read GetCell write SetCell;
    function IsOpen: Boolean;
  published
    property Visible: Boolean read IsVisible write SetVisible;
  end;

  TfrPDFExport = class(TfrBasicExpFilter)
  private
    FPDF: TPDFDocument;
    FP: Boolean;
    CurPage: Integer;
    Alpha: Extended;

    FObjectsCount: Integer;
    FObjectCountExported: Integer;

    FObjectsToExport: TList;

    FIsDefObjCountMode: Boolean;

    procedure BeforeExport(var FileName: String; var bContinue: Boolean);
    procedure AfterExport(const FileName: String);
    procedure Cancel;
    procedure ExportDoc;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure OnBeginPage; override;
    procedure OnBeginDoc; override;
    procedure OnEndDoc; override;
    procedure OnData(x, y: Integer; View: TfrView); override;
  end;

implementation

uses FR_Const, FR_Utils, U_ProgressExp, U_Preview, U_Main, U_BaseCommon, U_Common{, U_Types, U_Ukrainization};

{$R *.dfm}

function ComparePoints(Item1, Item2: Pointer): Integer;
begin
  Result := TObjCell(Item1).Value - TObjCell(Item2).Value;
end;

function CompareObjects(Item1, Item2: Pointer): Integer;
var
  r: integer;
begin
  r := TfrView(Item1).y - TfrView(Item2).y;
  if r = 0 then
    r := TfrView(Item1).x - TfrView(Item2).x;
  if r = 0 then
    r :=Length(TfrView(Item1).Memo.Text) - Length(TfrView(Item2).Memo.Text);
  Result := r;
end;

constructor TMyfrOleExl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  frRegisterExportFilter(Self, frLoadStr(frRes + 1840), '*.xls');
  RX := TList.Create;
  RY := TList.Create;
  PageObj := TList.Create;
  ObjectPos := TList.Create;
  Excel := TfrExcel.Create(nil);
  pgList := TStringList.Create;
  pgBreakList := TStringList.Create;
  ShowDialog := True;
  expMerged := True;
  expWrapWords := True;
  expFillColor := True;
  expBorders := True;
  expAlign := True;
  expPageBreaks := True;
  expFontName := True;
  expFontSize := True;
  expFontStyle := True;
  expFontColor := True;
  expPictures := True;
  {
  expScaleX := 0.98;
  expScaleY := 0.98;
  }
  expScaleX := 1.0;
  expScaleY := 1.0;


  //FCanceledExport := false;    //#From Oleg#
  //FLeaveCellsWithTag := false; //#From Oleg#
  //FTagForLeaveCell := #0;      //#From Oleg#
  FTmpDir := '';
  FTmpFiles := TStringList.Create;

  //FOnStartExportPageEvent := nil;
  //FOnProgressExportPageEvent := nil;
  //FOnEndExportPageEvent := nil;
end;

destructor TMyfrOleExl.Destroy;
begin
  ClearLastPage;
  frUnRegisterExportFilter(Self);
  RX.Destroy;
  RY.Destroy;
  PageObj.Destroy;
  ObjectPos.Destroy;
  Excel.Destroy;
  pgList.Destroy;
  pgBreakList.Destroy;

  FTmpFiles.Free;
  inherited;
end;

function TMyfrOleExl.CleanReturns(Str: string): string;
var
  i: integer;
begin
   i := Pos(#13, Str);
   while i > 0 do
   begin
      if i > 0 then Delete(Str, i, 1);
      i := Pos(#13, Str);
   end;
   i := Pos(#1, Str);
   while i > 0 do
   begin
      if i > 0 then Delete(Str, i, 1);
      i := Pos(#1, Str);
   end;
   while Copy(Str, Length(str), 1) = #10 do
      Delete(Str, Length(Str), 1);
   Result := Str;
end;

procedure TMyfrOleExl.ClearLastPage;
var
  i: integer;
begin
  for i := 0 to RX.Count - 1 do TObjCell(RX[i]).Free;
  RX.Clear;
  for i := 0 to RY.Count - 1 do TObjCell(RY[i]).Free;
  RY.Clear;
  for i := 0 to PageObj.Count - 1 do
  begin
    if TfrView(PageObj[i]) is TfrMemoView then
      TfrMemoView(PageObj[i]).Destroy
    else
    if TfrView(PageObj[i]) is TfrPictureView then
      TfrPictureView(PageObj[i]).Destroy;
  end;
  PageObj.Clear;
  for i := 0 to ObjectPos.Count - 1 do TObjPos(ObjectPos[i]).Free;
  ObjectPos.Clear;

end;

procedure TMyfrOleExl.ObjCellAdd(Vector: TList; Value: integer);
var
   ObjCell: TObjCell;
begin
   ObjCell := TObjCell.Create;
   ObjCell.Value := Value;
   Vector.Add(ObjCell);
end;

procedure TMyfrOleExl.ObjPosAdd(Vector: TList; x, y, dx, dy, obj: integer);
var
    ObjPos: TObjPos;
begin
   ObjPos := TObjPos.Create;
   ObjPos.x := x;
   ObjPos.y := y;
   ObjPos.dx := dx;
   ObjPos.dy := dy;
   ObjPos.obj := Obj;
   Vector.Add(ObjPos);
end;

procedure TMyfrOleExl.DeleteMultiplePoint(Vector: TList);
var
  i: integer;
  point, lpoint: TObjCell;
begin
   if Vector.Count > 0 then
   begin
    i := 0;
    lpoint := TObjCell(Vector[i]);
    inc(i);
    while i <= Vector.Count - 1 do
    begin
      point := TObjCell(Vector[i]);
      if (point.Value = lpoint.Value) then
      begin
        point.Free;
        Vector.Delete(i);
      end
      else
      begin
        lpoint := point;
        inc(i);
      end;
    end;
   end;
end;

procedure TMyfrOleExl.OrderObjectByCells;
var
   obj, c, fx, fy, dx, dy, m, mi, curx, cury: integer;
begin
   for obj := 0 to PageObj.Count - 1 do
   begin
     fx := 0; fy := 0;
     dx := 1; dy := 1;
     for c := 0 to RX.Count - 1 do
       if TObjCell(RX[c]).Value = TfrView(PageObj[obj]).x then
       begin
          fx := c;
          m := TfrView(PageObj[obj]).x;
          mi := c + 1;
          curx :=TfrView(PageObj[obj]).x + (TfrView(PageObj[obj]).dx - 1{0}); //TfrView(PageObj[obj]).dx div 10
          while m < curx do
          begin
            m := m + TObjCell(RX[mi]).Value - TObjCell(RX[mi - 1]).Value;
            inc(mi);
          end;
          dx := mi - c - 1;
          break;
       end;
     for c := 0 to RY.Count - 1 do
       if TObjCell(RY[c]).Value = TfrView(PageObj[obj]).y then
       begin
          fy := c;
          m := TfrView(PageObj[obj]).y;
          mi := c + 1;
          cury := TfrView(PageObj[obj]).y + (TfrView(PageObj[obj]).dy - 1{0}); //TfrView(PageObj[obj]).dy div 10
          while m < cury do
          begin
            m := m + TObjCell(RY[mi]).Value - TObjCell(RY[mi - 1]).Value;
            inc(mi);
          end;
          dy := mi - c - 1;
          break;
       end;
     ObjPosAdd(ObjectPos, fx, fy, dx, dy, obj);
   end;
end;

{$WARNINGS OFF}
procedure TMyfrOleExl.ExportPage;
var
  i, j, k, l, x, y, dx, dy : integer;
  x1, y1, dx1, dy1, olddx, olddy : integer;
  dcol, drow, delta, conv : Extended;
  s : string;
  Left, Right, Top, Bottom : Extended;
  Orient, Vert, Horiz: integer;
  m: TRect;
  obj: TfrMemoView;
  PicObj: TfrPictureView;
  ExlArray: Variant;
  TimeBegin, TimeRemain, TimeEstimate: TDateTime;
  Step: integer;
  defaultV, defaultH: integer;

  oldxFN, oldyFN: integer;
  oldFN: string;
  oldxFS, oldyFS: integer;
  oldFS: integer;
  oldxFSt, oldyFSt: integer;
  oldFSt: TFontStyles;
  oldxAH, oldyAH: integer;
  oldAH: integer;
  oldxAV, oldyAV: integer;
  oldAV: integer;
  oldxFC, oldyFC: integer;
  oldFC: integer;
  oldxFR, oldyFR: integer;
  oldFR: integer;
  oldxC, oldyC: integer;
  oldC: integer;
  MyAH: integer;
  Merged: BOOL;
  Tempi: integer;

  ImgFile: String;
  Jpeg: TJPEGImage;
  CanvasRect: TRect;
  Bmp: TBitmap;
  MetaFile: TMetafile;
  // Tolik 04/02/2020 --
  eRows: integer;
  eNewRowHeight: Double;
  enewRange: TRange;
  ePageBreak: word;
  ePageBreakIndex: Integer;
  type
  {TCellCoord}
  TCellCoord = packed record
    Row: Word;
    Column: Byte;
    RelativeFlags: Byte;
  end;
  PCellCoord = ^TCellCoord;

  //

  procedure AlignFR2AlignExcel(Align: integer; var AlignH, AlignV: integer);
  begin
    if (Align and frtaRight) <> 0 then
         if (Align and frtaCenter) <> 0 then AlignH := xlJustify
         else AlignH := xlRight
      else if (Align and frtaCenter) <> 0 then AlignH := xlCenter
      else AlignH := xlLeft;
    if (Align and frtaMiddle) <> 0 then AlignV := xlCenter
      else if (Align and frtaDown) <> 0 then AlignV := xlBottom
      else AlignV := xlTop;
  end;

  procedure SetRegionAttrib(x1, y1, x2, y2: integer; Attr: variant; Attr2:TfontStyles; func: integer);
   var
     dx, dy: integer;
     procedure CallFunc(param: variant; param2: TfontStyles; numb: integer);
     begin
       case numb of
         1 : Excel.SetCellFontStyle(param2);
         2 : Excel.SetCellFontSize(param);
         3 : Excel.SetCellFontName(param);
         4 : Excel.SetCellHAlignM(param);
         5 : Excel.SetCellVAlignM(param);
         6 : Excel.SetCellFontColor(param);
         7 : begin
               Excel.SetCellFrame(param);
               if (dx > 1) and (param > 0) then
                 Excel.SetCellFrameInsideH;
               if (dy > 1) and (param > 0) then
                 Excel.SetCellFrameInsideV;
             end;
         8 : Excel.SetCellFillColor(param);
       end;
     end;
  begin
      if y2 > y1 then
      begin
        dx := RX.Count - x1; dy := 1;
        Excel.SetRange(x1, y1, dx, dy);
        CallFunc(Attr, Attr2, func);
        if y2 - y1 > 1 then
        begin
          dx := RX.Count - 1; dy := y2 - 1;
          Excel.SetRange(1, y1 + 1, dx, dy);
          CallFunc(Attr, Attr2, func);
        end;
        dx := x2 - 1; dy := 1;
        Excel.SetRange(1, y2, dx, dy);
        CallFunc(Attr, Attr2, func);
      end
      else
      begin
        dx := x2 - x1; dy := 1;
        Excel.SetRange(x1, y2, dx, dy);
        CallFunc(Attr, Attr2, func);
      end;
  end;

begin
  TimeBegin := Time;
  Step := 0;
  TimeRemain := 0;
  ImgFile := '';

  if CurReport.EMFPages[CurrentPage - 1].pgor = poLandscape then Orient := 0
    else Orient := 1;
  m := CurReport.EMFPages[CurrentPage - 1].pgMargins;
  Left := m.Left / 90;
  Right := m.Right / 90;
  Top := m.Top / 90;
  Bottom := m.Bottom / 90;
  Excel.SetPageMargin(Left, Right, Top, Bottom, Orient);

  i := 0;
  CurReport.Terminated := false;
  for y := 1 to RY.Count - 1 do
  begin
     drow := expScaleY * (TObjCell(RY[y]).Value - TObjCell(RY[y - 1]).Value) / Ydivider;
     Excel.SetRowSize(y + cury, drow);
     if pgBreakList.Count > i then
     if (pgBreakList[i] = IntToStr(TObjCell(RY[y - 1]).Value)) and expPageBreaks then
     begin
       // Tolik 05/02/2020
       Excel.XF.Workbook.Sheets[0].PageBreaks.Add(y,0); //PM - D0000005830
       Excel.SetRowSize(y + cury, 0);
       inc(i); // Tolik 05/02/2020
     end;
  end;

  for x := 1 to RX.Count - 1 do
  begin
     dcol := expScaleX*(TObjCell(RX[x]).Value - TObjCell(RX[x - 1]).Value) / Xdivider;
     Excel.SetColSize(x, dcol);
  end;

  ExlArray := VarArrayCreate([0,RY.Count - 1, 0,RX.Count - 1], varVariant);

  oldxFN := 1; oldyFN := CurY + 1;
  oldFN := '';
  oldxFC := 1; oldyFC := CurY + 1;
  oldFC := clBlack;
  oldxFS := 1; oldyFS := CurY + 1;
  oldFS := 10;
  oldxFSt := 1; oldyFSt := CurY + 1;
  oldFSt := [];
  oldxAH := 1; oldyAH := CurY + 1;
  oldAH:=xlLeft;
  MyAH := xlLeft;
  oldxAV := 1; oldyAV := CurY + 1;
  oldAV := xlTop;
  oldxFR := 1; oldyFR := CurY + 1;
  oldFR := 0;
  oldxC := 1; oldyC := CurY + 1;
  oldC := clNone;

  //F_ProjMan.F_ProgressExp.Message1.Visible := False;
  //F_ProjMan.F_ProgressExp.esBitBtn1.Visible := True;
  //F_ProjMan.F_ProgressExp.Gauge1.Visible := True;
  //F_ProjMan.F_ProgressExp.Gauge1.MinValue := 0;
  //F_ProjMan.F_ProgressExp.Gauge1.MaxValue := ObjectPos.Count - 1;
  //F_ProjMan.F_ProgressExp.Repaint;
  if Assigned(FOnStartExportPageEvent) then
    FOnStartExportPageEvent(Self, FFileCaption, ObjectPos.Count);
  FCanceledExport := false;

  Screen.Cursor := crDefault; //!!!
  for i := 0 to ObjectPos.Count - 1 do
  begin
    //if F_ProjMan.F_ProgressExp.WasCancel then
    //begin
    //  break; //Exit;
    //end
    //else
    //begin
    //  Application.ProcessMessages;
    //  F_ProjMan.F_ProgressExp.Gauge1.Progress := i;
    //  F_ProjMan.F_ProgressExp.Gauge1.Refresh;
    //end;
    if Assigned(FOnProgressExportPageEvent) then
    begin
      FOnProgressExportPageEvent(Self, FCanceledExport, i, ObjectPos.Count);
      if FCanceledExport then
        break; //Exit;
    end;

    x := TObjPos(ObjectPos[i]).x + 1;
    y := TObjPos(ObjectPos[i]).y + CurY + 1;
    dx := TObjPos(ObjectPos[i]).dx;
    dy := TObjPos(ObjectPos[i]).dy;

    Excel.SetRange(x, y, dx, dy);


    if TfrView(PageObj[TObjPos(ObjectPos[i]).obj]) is TfrMemoView then
    begin
        Obj := TfrMemoView(PageObj[TObjPos(ObjectPos[i]).obj]);

        //Excel.SetRange(x, y, dx, dy);

        if FLeaveCellsWithTag then                 //#From Oleg#
          if Obj.Tag = FTagForLeaveCell then       //#From Oleg#
            Continue; //// CONTINUE ////           //#From Oleg#
        Excel.BorderStyle := bsThin;
        if Obj.FrameWidth > 1 then
          Excel.BorderStyle := bsThick;

        s:=CleanReturns(Obj.Memo.Text);
        l:=pos('.', s);
        if l>0 then
        begin
          s[l]:=',';
{$IFDEF Delphi6}
          if TryStrToFloat(s, conv) then
            Excel.RangeXF.FormatStringIndex := 35;
{$ENDIF}
        end;
        AlignFR2AlignExcel(Obj.Alignment, Horiz, Vert);
        if expBorders then
          Excel.SetCellFrame(Obj.FrameTyp);
        if expFillColor then
          if Obj.FillColor <> clNone then
            Excel.SetCellFillColor(Obj.FillColor);

        // Стиль бордюры //#From Oleg#
        Excel.SetCellBorderStyle(Obj);
        // Цвет бордюры //#From Oleg#
        Excel.SetCellBorderColorRGB(Obj.FrameTyp, Obj.FrameColor);

        if (Obj.Alignment and $4) <>0 then
          Excel.SetCellOrientation(90);
        if expMerged then
          if (dx >= 1) or (dy >= 1) then
          begin
            olddx := dx; olddy := dy;
            for j:=i+1 to ObjectPos.Count - 1 do
            begin
              x1 := TObjPos(ObjectPos[j]).x + 1;
              y1 := TObjPos(ObjectPos[j]).y + CurY + 1;
              if ((y + dy) > y1) and ((x + dx) > x1) and (x <= x1) then
              begin
                if y = y1 then
                begin
                  if (x + dx) > x1 then dx := x1 - x;
                  dy:=1
                end
                else
                  dy := y1 - y;
              end;
              {if j = (i+1) then
                if ( ((y + dy) <> y1) or ((x + dx) <> x1) ) and (x <= x1) then
                begin
                  if y = y1 then
                  begin
                    if (x + dx) <> x1 then
                      dx := Abs(x1 - x);
                    dy := 1;
                  end
                  else
                    dy := y1 - y;
                end;  }
            end;
            Merged := False;
            MyAH := OLDAH;
            if (dx >= 1) or (dy >= 1) then
            begin
              if (dx <> olddx) or (dy <> olddy) then
              begin
                Excel.SetRange(x, y, dx, dy);
                {if expBorders then
                  Excel.SetCellFrame(Obj.FrameTyp);
                if expFillColor then
                  if Obj.FillColor <> clNone then
                    Excel.SetCellFillColor(Obj.FillColor);
                if (Obj.Alignment and $4) <>0 then
                  Excel.SetCellOrientation(90); }
              end;
              Excel.MergeCells;
              if dy > 1 then
              begin
                MyAH := Horiz;
              end;
                Merged := True;
            end;
          end;
       begin
        if (Obj.Font.Style <> OldFSt) and expFontStyle then
        begin
          SetRegionAttrib(OldxFSt, OldyFSt, x, y, 0, OldFSt, 1);
          OldxFSt := x; OldYFSt := y;
          OldFSt := Obj.Font.Style;
        end;
        if (Obj.Font.Size <> OldFS) and expFontSize then
        begin
          SetRegionAttrib(OldxFS, OldyFS, x, y, OldFS, [], 2);
          OldxFS := x; OldYFS := y;
          OldFS := Obj.Font.Size;
        end;
        if (Obj.Font.Name <> OldFN) and expFontName then
        begin
          SetRegionAttrib(OldxFN, OldyFN, x, y, OldFN, [], 3);
          OldxFN := x; OldYFN := y;
          OldFN := Obj.Font.Name;
        end;
        if expAlign then
        begin
          if Horiz <> OldAH then
          begin
            SetRegionAttrib(OldxAH, OldyAH, x, y, OldAH, [], 4);
            OldxAH := x; OldyAH := y;
            OldAH := Horiz;
          end;
          if Vert <> OldAV then
          begin
            SetRegionAttrib(OldxAV, OldyAV, x, y, OldAV, [], 5);
            OldxAV := x; OldyAV := y;
            OldAV := Vert;
          end;
        end;
        if (Obj.Font.Color <> OldFC) and expFontColor then
        begin
          SetRegionAttrib(OldxFC, OldyFC, x, y, OldFC, [], 6);
          OldxFC := x; OldYFC := y;
          OldFC := Obj.Font.Color;
        end;
       end;

       s := Obj.Memo.Text;
       if (Pos('/',s) <> 0) and (Length(s) < 10)then
       begin
         Excel.SetRange(x, y-CurY, dx, dy);
         Excel.SetCellNumFormat('@');
       end;
       if (Pos('-',s) <> 0) and (Length(s) < 10)then
       begin
         Excel.SetRange(x, y-CurY, dx, dy);
         Excel.SetCellNumFormat('@');
       end;
       if (Pos(#1#13#10, s) = Length(s) - 2) then
       begin
         while Pos(#13#10, s) > 1 do
         if s[Pos(#13#10, s) - 1] <> #1 then
         begin
           Tempi := pos(#13#10, s);
           delete(s, Tempi, 2);
           insert(' ', s, Tempi);
         end
         else
         begin
           delete(s, pos(#13, s), 1)
         end;
       end;
       s := CleanReturns(s);
       ExlArray[y-1-CurY, x-1] := s;

       Excel.SetRange(x, y, dx, dy);
       Excel.SetCellHAlignM(Horiz);
       Excel.SetCellVAlignM(Vert);

       try
         if s <> '' then
         begin
           if Excel.RangeXF <> nil then
           begin
             Excel.RangeXF.Value := s;
           end;
         end;
       except
       end;
    end
    else
    if TfrView(PageObj[TObjPos(ObjectPos[i]).obj]) is TfrPictureView then
    begin
       Inc(CntPics);
       PicObj := TfrPictureView(PageObj[TObjPos(ObjectPos[i]).obj]);

       (* //#From Oleg#
{$IFDEF Delphi3}
       PicObj.Picture.SaveToClipboardFormat(PicFormat, THandle(PicData), HPALETTE(PicPalette));
{$ELSE}
       PicObj.Picture.SaveToClipboardFormat(PicFormat, PicData, PicPalette);
{$ENDIF}

       Clipboard.SetAsHandle(PicFormat,THandle(PicData));
{$IFDEF Delphi3}
       Excel.Range.PasteSpecial;
{$ELSE}
//       Excel.Range.PasteSpecial(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
{$ENDIF}
//       Excel.WorkSheet.Pictures[CntPics].Width := PicObj.dx / 1.5;
//       Excel.WorkSheet.Pictures[CntPics].Height := PicObj.dy / 1.5;
                                            *)

        try
          if FTmpDir = '' then
          begin
            FTmpDir := ExtractSCSTempDir; //ExtractFileDir(FileName)+'\'+'~'+FileNameCorrect(ExtractFileNameOnly(FileName));
            //if DirectoryExists(FTmpDir) then
            // RmDir(FTmpDir);
            //CreateDir(FTmpDir);
          end;
          ImgFile := GetNoExistsFileNameForCopy(FTmpDir+'Image.jpg');
          FTmpFiles.Add(ImgFile);

          //Bmp.Assign(PicObj.Picture.Bitmap);
          //Bmp.Canvas. Assign(PicObj.Picture.Bitmap.Canvas);

          {CanvasRect.Top := 0;
          CanvasRect.Left := 0;
          CanvasRect.Right := PicObj.Picture.Bitmap.Width;
          CanvasRect.Bottom := PicObj.Picture.Bitmap.Height;}
          //PicObj.Picture.Bitmap.Canvas.StretchDraw(CanvasRect, Bmp);

          //PicObj.Picture.SaveToFile('c:\excelpict.bmp');
          //PicObj.Picture.Graphic.SaveToFile('c:\excelpict.bmp');
          //PicObj.Picture.Bitmap.SaveToFile('c:\excelpict_.bmp');
          //PicObj.Picture.Graphic.SaveToFile('c:\excelpict__.bmp');

          Jpeg := TJPEGImage.Create;
          Jpeg.Assign(PicObj.Picture.Graphic);
          try
            Jpeg.SaveToFile(ImgFile);
          except
            begin
              Bmp := TBitmap.Create;
              Bmp.Height := PicObj.Picture.Bitmap.Height;
              Bmp.Width := PicObj.Picture.Bitmap.Width;

              CanvasRect := Rect(0, 0, PicObj.Picture.Bitmap.Width, PicObj.Picture.Bitmap.Height);
              Bmp.Canvas.Draw(0, 0, PicObj.Picture.Graphic);

              Jpeg.Assign(Bmp);
              Jpeg.SaveToFile(ImgFile);

              FreeAndNil(Bmp);
            end;
          end;
          FreeAndNil(Jpeg);

          Excel.XF.Workbook.Sheets[0].Images.Add(ImgFile, x-1, y-1);
        except
          on E: Exception do AddExceptionToLogEx('TMyfrOleExl.ExportPage', E.Message);
        end;
    end;

    inc(Step);
    TimeEstimate := TimeBegin + (ObjectPos.Count - 1) * (Time - TimeBegin) / Step;
    TimeRemain := TimeEstimate - Time;

    Application.ProcessMessages;

    if CurReport.Terminated then
      break;

  end;
  //if F_ProjMan.F_ProgressExp.WasCancel then
  //  Exit;
  if FCanceledExport then
    Exit; ///// EXIT /////

  x := x + dx; y := y + dy;
  SetRegionAttrib(OldxFSt, OldyFSt, x, y, 0, OldFSt, 1);     //Font style
  SetRegionAttrib(OldxFS, OldyFS, x, y, OldFS, [], 2);       //Font size
  SetRegionAttrib(OldxFN, OldyFN, x, y, OldFN, [], 3);       //Font name
  SetRegionAttrib(OldxAH, OldyAH, x, y, OldAH, [], 4);       //H Align
  SetRegionAttrib(OldxAV, OldyAV, x, y, OldAV, [], 5);       //V Align
  SetRegionAttrib(OldxFC, OldyFC, x, y, OldFC, [], 6);

  //Tolik 04/02/2020 -- поправить строки, которые не помещаются в высоту ячейки
  eRows := RY.Count;
  for i := 1 to eRows do
  begin
    if Excel.XF.Workbook.Sheets[0].Rows[i].Height > 409 then
    begin
      ePageBreakIndex := -1;
      for j := 0 to Excel.XF.Workbook.Sheets[0].PageBreaks.ItemsCount - 1 do
      begin
        if Excel.XF.Workbook.Sheets[0].PageBreaks.Item[j].Row >= i then
        begin
          ePageBreakIndex := j;
          ePageBreak := Excel.XF.Workbook.Sheets[0].PageBreaks.Item[j].Row;
          break;
        end;
      end;

      eNewRowHeight := Excel.XF.Workbook.Sheets[0].Rows[i].Height - 409;
      Excel.XF.Workbook.Sheets[0].Rows.InsertRows(i, 1);

      Excel.XF.Workbook.Sheets[0].Rows[i].Height := 409;

      Excel.XF.Workbook.Sheets[0].Rows[i + 1].Height := eNewRowHeight + 10;
      //Excel.XF.Workbook.Sheets[0].Rows[i + 1].Height := eNewRowHeight + 10;

      for j := 1 to Rx.Count - 2 do
      begin
        enewRange := Excel.XF.Workbook.Sheets[0].Ranges.Add;
        enewRange.AddRect(i, i + 1, j, j);
        //enewRange.Wrap := True;
        enewRange.MergeCells;
        Excel.SetRange(i,i+1,j,j);
        Excel.SetCellHAlignM(Horiz);
        Excel.SetCellVAlignM(Vert);
      end;
      inc(eRows);
      // перенести разрыв страницы

      if ePageBreakIndex <> -1 then
      begin
        //Excel.XF.Workbook.Sheets[0].PageBreaks.Remove(ePageBreakIndex);
        Excel.XF.Workbook.Sheets[0].PageBreaks.SetItem(ePageBreakIndex, ePageBreak + 1, 0);
      end;

    end;
  end;
  //Tolik 10/02/2020
  //Excel.SetRange(1, CurY + 1, RX.Count - 1, RY.Count - 1);


  Excel.SetRange(1, CurY + 1, RX.Count - 1, eRows - 1);
  //

  CurY := Y - 1;
end;
{$WARNINGS ON}


function TMyfrOleExl.ShowModal: Word;

var
  PageNumbers: string;

  procedure ParsePageNumbers;
  var
    i, j, n1, n2: Integer;
    s: String;
    IsRange: Boolean;
  begin
    s := PageNumbers;
    while Pos(' ', s) <> 0 do
      Delete(s, Pos(' ', s), 1);
    if s = '' then Exit;
    s := s + ',';
    i := 1; j := 1; n1 := 1;
    IsRange := False;
    while i <= Length(s) do
    begin
      if s[i] = ',' then
      begin
        n2 := StrToInt(Copy(s, j, i - j));
        j := i + 1;
        if IsRange then
          while n1 <= n2 do
          begin
            pgList.Add(IntToStr(n1));
            Inc(n1);
          end
        else
          pgList.Add(IntToStr(n2));
        IsRange := False;
      end
      else if s[i] = '-' then
      begin
        IsRange := True;
        n1 := StrToInt(Copy(s, j, i - j));
        j := i + 1;
      end;
      Inc(i);
    end;
  end;

begin
 if ShowDialog then
 begin
  frExportSet := TfrOLEExcelSet.Create(nil);
  frExportSet.CB_Merged.Checked := expMerged;
  frExportSet.CB_WrapWords.Checked := expWrapWords;
  frExportSet.CB_FillColor.Checked := expFillColor;
  frExportSet.CB_Borders.Checked := expBorders;
  frExportSet.CB_Align.Checked := expAlign;
  frExportSet.CB_PageBreaks.Checked := expPageBreaks;
  frExportSet.CB_FontName.Checked := expFontName;
  frExportSet.CB_FontSize.Checked := expFontSize;
  frExportSet.CB_FontStyle.Checked := expFontStyle;
  frExportSet.CB_FontColor.Checked := expFontColor;
  frExportSet.CB_Pictures.Checked := expPictures;
  frExportSet.CB_OpenExcel.Checked := expOpenAfter;
  frExportSet.E_ScaleX.Text := FloatToStr(Int(expScaleX*100));
  frExportSet.E_ScaleY.Text := FloatToStr(Int(expScaleY*100));
  frExportSet.E_TMargin.Text := FloatToStr(expTopMargin);
  frExportSet.E_LMargin.Text := FloatToStr(expLeftMargin);
  Result := frExportSet.ShowModal;
  PageNumbers := frExportSet.E_Range.Text;
  expMerged := frExportSet.CB_Merged.Checked;
  expWrapWords := frExportSet.CB_WrapWords.Checked;
  expFillColor := frExportSet.CB_FillColor.Checked;
  expBorders := frExportSet.CB_Borders.Checked;
  expAlign := frExportSet.CB_Align.Checked;
  expPageBreaks := frExportSet.CB_PageBreaks.Checked;
  expFontName := frExportSet.CB_FontName.Checked;
  expFontSize := frExportSet.CB_FontSize.Checked;
  expFontStyle := frExportSet.CB_FontStyle.Checked;
  expFontColor := frExportSet.CB_FontColor.Checked;
  expPictures := frExportSet.CB_Pictures.Checked;
  expOpenAfter := frExportSet.CB_OpenExcel.Checked;
  expScaleX := StrToInt(frExportSet.E_ScaleX.Text) / 100;
  expScaleY := StrToInt(frExportSet.E_ScaleY.Text) / 100;
  expTopMargin := StrToFloat(frExportSet.E_TMargin.Text);
  expLeftMargin := StrToFloat(frExportSet.E_LMargin.Text);
  frExportSet.Destroy;
 end
 else
   Result := mrOk;
 pgList.Clear;
 pgBreakList.Clear;
 ParsePageNumbers;
end;

procedure TMyfrOleExl.OnBeginDoc;
begin
  OnAfterExport := AfterExport;
  Excel.OpenExcel;
  CurrentPage := 0;
  CurY := 0;
  FirstPage := true;
  ClearLastPage;
  CY := 0;
  lastY := 0;
  CntPics := 0;
end;

procedure TMyfrOleExl.OnBeginPage;
begin
  Inc(CurrentPage);
end;

procedure TMyfrOleExl.OnData(x, y: Integer; View: TfrView);
var
    MemoView : TfrMemoView;
    PicView : TfrPictureView;
    ind, maxy, j, k, dy : integer;
    delta : Extended;
    bit : TBitmap;
    BottomView: TfrView;
    LineDY: Integer;
    rect: TRect;
begin
  ind := 0;
  if (pgList.Find(IntToStr(CurrentPage),ind)) or (pgList.Count = 0) then
  begin
      if View is TfrMemoView then
      begin
        if (TfrMemoView(View).Memo.Count > 0) or (TfrMemoView(View).FrameTyp > 0) then
        begin
          MemoView := TfrMemoView.Create;
          MemoView.Assign(View);
          MemoView.y := MemoView.y + CY;
          PageObj.Add(MemoView);
        end;
      end
      {else
      if View is TfrLineView then
      begin
        PicView := TfrPictureView.Create;
        PicView.x := View.x;
        PicView.y := View.y;
        PicView.dx := View.dx;
        PicView.dy := View.dy;
        bit := TBitmap.Create;
        bit.Height := View.dy+1;
        bit.Width := View.dx+1;

        if bit.Height < View.FrameWidth then
          bit.Height := View.FrameWidth;
        if bit.Width < View.FrameWidth then
          bit.Width := View.FrameWidth;

        View.x := 0;
        View.y := 0;
        View.Draw(bit.Canvas);
        View.x := PicView.x;
        View.y := PicView.y;
        PicView.Picture.Bitmap.Assign(bit);
        bit.Destroy;
        PicView.y := PicView.y + CY;
        PageObj.Add(PicView);
      end}
      else
      begin
        PicView := TfrPictureView.Create;
        if (PicView.Flags and flStretched) = flStretched then
          PicView.Flags := PicView.Flags xor flStretched;
        PicView.FrameWidth := 0;

        PicView.x := View.x;
        PicView.y := View.y;
        PicView.dx := View.dx;
        PicView.dy := View.dy;

        bit := TBitmap.Create;

        bit.Height := View.dy+2;
        bit.Width := View.dx+2;

        //#From Oleg#
          //*** Если объект линия
          if View is TfrLineView then
          begin
            // Добавить высоту на 1-цу если это вертикальнаф линия
            if bit.Height > 1 then
            begin
              //*** Прибавить 10% к высоте лиии
              LineDY := Trunc(bit.Height * (10/100));

              bit.Height := bit.Height + LineDY;
              //PicView.dy := PicView.dy + LineDY;
              View.dy := View.dy + LineDY;
            end;
            //*** Учет ширины линии
            if bit.Height < View.FrameWidth then
              bit.Height := Trunc(View.FrameWidth)+1;
            if bit.Width < View.FrameWidth then
              bit.Width := Trunc(View.FrameWidth)+1;
          end;
        //#From Oleg#

        View.x := 0;
        View.y := 0;
        View.Draw(bit.Canvas);
        View.x := PicView.x;
        View.y := PicView.y;
        // Tolik 10/02/2020 --
        //PicView.Picture.Bitmap.Assign(bit);
        //Ydivider = 1.3
        PicView.Picture.Bitmap.width := view.dx + 2;
        PicView.Picture.Bitmap.height := view.dy + 2;
        rect.Left := 0;
        rect.Right := view.dx + 2;
        rect.Top := 0;
        rect.Bottom := view.dy + 2;
        PicView.Picture.Bitmap.Canvas.StretchDraw(rect, bit);
        //
        bit.Destroy;
        PicView.y := PicView.y + CY;
        //PageObj.Add(PicView);
        PageObj.Insert(0, PicView);
      end;


      //if View is TfrMemoView then //17.02.2009
      begin
        ObjCellAdd(RX, View.x);
        ObjCellAdd(RX, View.x + View.dx);
        ObjCellAdd(RY, View.y + CY);
        ObjCellAdd(RY, View.y + View.dy + CY);

        // Excel capability code
        if (View.y + CY) > lastY then
        begin
          delta := expScaleY * (View.y + CY - LastY) / Ydivider;
          if delta > XLMaxHeight then
          begin
            k := Trunc (delta / XLMaxHeight);
            dy :=  Trunc (XLMaxHeight * Ydivider / expScaleY);
            for j := 1 to k do
              ObjCellAdd(RY, LastY + dy * k);
          end;
        end;


        maxy := View.y + View.dy + CY;
        if maxy > LastY then
          LastY := maxy;
      end;
  end;
end;

procedure TMyfrOleExl.OnEndPage;
var
    ind: integer;
begin
  CY := LastY;
  ind := 0;
  if (pgList.Find(IntToStr(CurrentPage),ind)) or (pgList.Count = 0) then
    pgBreakList.Add(IntToStr(LastY));
end;

procedure TMyfrOleExl.OnEndDoc;
begin
//
end;

procedure TMyfrOleExl.AfterExport(const FileName: string);
var
  i: Integer;
  TempList: TList;
begin
  RX.Sort(@ComparePoints);
  RY.Sort(@ComparePoints);
  DeleteMultiplePoint(RX);
  DeleteMultiplePoint(RY);

  TempList := TList.Create;
  for i := 0 to PageObj.Count - 1 do
  begin
    if TObject(PageObj[i]) is TfrPictureView then
    begin
      TempList.Add(PageObj[i]);
      PageObj[i] := nil;
    end;
  end;
  PageObj.Pack;
  PageObj.Sort(@CompareObjects);

  for i := 0 to TempList.Count - 1 do
    PageObj.Insert(0, TempList[i]);
  FreeAndNil(TempList);

  OrderObjectByCells;

  ExportPage;


  //if F_ProjMan.F_ProgressExp.WasCancel then
  //  begin
  //    Exit;
  //  end
  //else
  //  begin
  //    F_ProjMan.F_Preview.frPreview1.PopupMenu := F_ProjMan.F_Preview.PopupMenu1;
  //  end;
  if Assigned(FOnEndExportPageEvent) then
    FOnEndExportPageEvent(Self, FCanceledExport);
  if FCanceledExport then
    Exit; ///// EXIT /////
  Excel.SetRange(1, 1, 1, 1);

  try
   DeleteFile(FileName);
{$IFDEF Delphi3}
   Excel.WorkBook.SaveAs(FileName,xlNormal);
{$ELSE}
   try
     Excel.XF.SaveAs(FileName);
   except
   end;

{$ENDIF}
  except
  end;

  if DirectoryExists(FTmpDir) then
    ClearTmpFiles;
end;

procedure TMyfrOleExl.ClearTmpFiles;
var
  i: Integer;
begin
  for i := 0 to FTmpFiles.Count - 1 do
    DeleteFile(FTmpFiles[i]);
end;

///////////////////////////////////////////////////
constructor TFrExcel.Create (AOwner : TComponent);
begin
  inherited Create(AOwner);
  IsOpened := false;
  IsVisible := false;
  BorderStyle := bsThin;
end;

destructor TFrExcel.Destroy;
begin
  if IsOpened then
  try
    xf.Destroy;
  except
  end;
  inherited Destroy;
end;

function TfrExcel.Pos2Str(Pos: Integer): String;
var
  i, j: integer;
begin
    if Pos > 26 then
    begin
      i := Pos mod 26; j := Pos div 26;
      if i = 0 then Result := Chr(64 + j - 1)
        else Result := Chr(64 + j);
      if i = 0 then Result := Result + chr(90)
        else result := Result + Chr(64 + i);
    end
    else Result := Chr(64 + Pos);
end;

procedure TFrExcel.SetVisible(DoShow: Boolean);
begin
  if not IsOpened then
    exit;
end;

function TFrExcel.IntToCoord(X, Y: Integer): string;
begin
  Result := Pos2Str(X) + IntToStr(Y);
end;

function TFrExcel.GetCell(x, y: Integer): string;
begin
  result := xf.Workbook.Sheets[0].Cells[y - 1, x - 1].ValueAsString;
end;

procedure TFrExcel.SetCell(x, y: Integer; const Value: string);
begin
  xf.Workbook.Sheets[0].Cells[y - 1, x - 1].Value := Value;
end;

//изменёна ширина столбца
procedure TFrExcel.SetColSize(x: Integer; Size: Extended);
var
  SizeO: Extended;
  SizeInt: integer;
begin
  SizeInt := trunc(Size);
  xf.Workbook.Sheets[0].Columns[x - 1].WidthPx := SizeInt;
end;

// Tolik 04/02/2020 -- здесь убираем проверку, чтобы на выхлопе понять, где
//                     требуется добавить новую строку (согласно огрничения на высоту ячейки в 409 точек)

//изменёна высота столбца
procedure TFrExcel.SetRowSize(y: Integer; Size: Extended);
begin
  //Size := Size*1.07;
  Size := Size*1.075;
  //if size > 409 then
  //  size := 409;
  xf.Workbook.Sheets[0].Rows[y - 1].Height := Size;
end;

{procedure TFrExcel.SetRowSize(y: Integer; Size: Extended);
begin
  Size := Size*1.07;
  if size > 409 then
    size := 409;
  xf.Workbook.Sheets[0].Rows[y - 1].Height := Size;
end;}
//



procedure TFrExcel.MergeCells;
begin
  if RangeXF <> nil then
  begin
    RangeXF.MergeCells;
  end;  
end;

procedure TFrExcel.OpenExcel;
begin
  try
    xf := TXLSFile.Create;
    xf.Workbook.Sheets[0].Name := SheetName;
    IsOpened := True;
  except
    IsOpened := false;
  end;
end;

function TFrExcel.IsOpen: Boolean;
begin
  result := IsOpened;
end;

procedure TFrExcel.SetPageMargin(Left, Right, Top, Bottom: Extended; Orient : Integer);
begin
  try
    // Tolik 03/02/2020 -- эта сука теперь юзает ТОЛЬКО ДЮЙМЫ!!!
    {xf.Workbook.Sheets[0].PageSetup.LeftMargin := Left;
    xf.Workbook.Sheets[0].PageSetup.RightMargin := Right;
    xf.Workbook.Sheets[0].PageSetup.TopMargin := Top;
    xf.Workbook.Sheets[0].PageSetup.BottomMargin := Bottom;}
    xf.Workbook.Sheets[0].PageSetup.LeftMargin := Left/2.54;
    xf.Workbook.Sheets[0].PageSetup.RightMargin := Right/2.54;
    xf.Workbook.Sheets[0].PageSetup.TopMargin := Top/2.54;
    xf.Workbook.Sheets[0].PageSetup.BottomMargin := Bottom/2.54;
    //
    xf.Workbook.Sheets[0].PageSetup.Orientation := TXLSPageOrientation(Orient);
  except
  end;
end;

procedure TFrExcel.SetCellBorderColorRGB(AFrame, ARGBColor: integer);
begin
  if RangeXF <> nil then
  begin
    if (AFrame and frftLeft) <> 0 then
      RangeXF.BorderColorRGB[xlBorderLeft] := ARGBColor;
    if (AFrame and frftRight) <> 0 then
      RangeXF.BorderColorRGB[xlBorderRight] := ARGBColor;
    if (AFrame and frftTop) <> 0 then
      RangeXF.BorderColorRGB[xlBorderTop] := ARGBColor;
    if (AFrame and frftBottom) <> 0 then
      RangeXF.BorderColorRGB[xlBorderBottom] := ARGBColor;
  end;
end;

procedure TFrExcel.SetCellBorderStyle(AObj: TfrView);
var
  BorderStyle: TXLBorderStyle;
begin
  if RangeXF <> nil then
  begin
    BorderStyle := bsThin;
    case AObj.FrameStyle of
      0: // Solid - сплошной
        begin
          BorderStyle := bsThin;  // Сплошной тонкий
          if (AObj.FrameWidth > 1) and (AObj.FrameWidth <= 2) then
            BorderStyle := bsMedium // Сплошной средний
          else
          if AObj.FrameWidth > 2 then
            BorderStyle := bsThick; // Сплошной толстый
        end;
      1: // Dash - тире
        begin
          BorderStyle := bsDashed; // тонкий
          if AObj.FrameWidth > 1 then
            BorderStyle := bsMediumDashed; // толстый
        end;
      2: // Dot - точка
        begin
          BorderStyle := bsDotted; //bsHair; // тонкий
          if AObj.FrameWidth > 1 then
            BorderStyle := bsDotted;
        end;
      3: // DashDot - тире-точка
        begin
          BorderStyle := bsDashDot; // тонкий
          if AObj.FrameWidth > 1 then
            BorderStyle := bsMediumDashDot; // толстый
        end;
      4: // DashDotDot - тире-точка-точка
        begin
          BorderStyle := bsDashDotDot; // тонкий
          if AObj.FrameWidth > 1 then
            BorderStyle := bsMediumDashDotDot; // толстый
        end;
      5: // Double - Двойной
        begin
          BorderStyle := bsDouble;
        end;
    end;

    if (AObj.FrameTyp and frftLeft) <> 0 then
      RangeXF.BorderStyle[xlBorderLeft] := BorderStyle;
    if (AObj.FrameTyp and frftRight) <> 0 then
      RangeXF.BorderStyle[xlBorderRight] := BorderStyle;
    if (AObj.FrameTyp and frftTop) <> 0 then
      RangeXF.BorderStyle[xlBorderTop] := BorderStyle;
    if (AObj.FrameTyp and frftBottom) <> 0 then
      RangeXF.BorderStyle[xlBorderBottom] := BorderStyle;
  end;
end;

procedure TFrExcel.SetCellFontName(FontName: string);
begin
  if RangeXF <> nil then
  begin
    if length(FontName) > 0 then
      RangeXF.FontName := FontName;
  end;
end;

procedure TFrExcel.SetCellFontSize(FontSize: integer);
begin
  if RangeXF <> nil then
  begin
    RangeXF.FontHeight := FontSize;
  end;
end;

procedure TFrExcel.SetCellFontColor(FontColor: integer);
begin
  if RangeXF <> nil then
  begin
    RangeXF.FontColorRGB := FontColor;
  end;
end;

procedure TFrExcel.SetCellFontStyle(Style: TFontStyles);
begin
  if RangeXF <> nil then
  begin
    RangeXF.FontBold := fsBold in Style;
    RangeXF.FontItalic := fsItalic in Style;
    RangeXF.FontUnderline := fsUnderline in Style;;
  end;
end;

procedure TFrExcel.SetCellVAlign(Vert: Integer);
var
  CellVAl: TCellVAlignment;
begin
  if RangeXF <> nil then
  begin
    CellVAl := xlVAlignCenter;
    case Vert of
      -4160: CellVAl := xlVAlignTop;
      -4107: CellVAl := xlVAlignBottom;
      -4108: CellVAl := xlVAlignCenter;
      -4130: CellVAl := xlVAlignJustify;
    end;
    RangeXF.VAlign := CellVAl;
  end;
end;

procedure TFrExcel.SetCellVAlignM(Vert: Integer);
var
  CellVAl: TCellVAlignment;
begin
  if RangeXF <> nil then
  begin
    CellVAl := xlVAlignCenter;
    case Vert of
      -4160: CellVAl := xlVAlignTop;
      -4107: CellVAl := xlVAlignBottom;
      -4108: CellVAl := xlVAlignCenter;
      -4130: CellVAl := xlVAlignJustify;
    end;
    RangeXF.VAlign := CellVAl;
  end;
end;

procedure TFrExcel.SetCellHAlign(Horiz: Integer);
var
  CellHAl: TCellHAlignment;
begin
  if RangeXF <> nil then
  begin
    CellHAl := xlHAlignCenter;
    case Horiz of
      -4152: CellHAl := xlHAlignRight;
      -4131: CellHAl := xlHAlignLeft;
      -4108: CellHAl := xlHAlignCenter ;
      -4130: CellHAl := xlHAlignJustify;
    end;
    RangeXF.HAlign := TCellHAlignment(Horiz);
  end;
end;

procedure TFrExcel.SetCellHAlignM(Horiz: Integer);
var
  CellHAl: TCellHAlignment;
begin
  if RangeXF <> nil then
  begin
    CellHAl := xlHAlignCenter;
    case Horiz of
      -4152: CellHAl := xlHAlignRight;
      -4131: CellHAl := xlHAlignLeft;
      -4108: CellHAl := xlHAlignCenter;
      -4130: CellHAl := xlHAlignJustify;
    end;
    if CellHAl = xlHAlignCenter then
      CellHAl := CellHAl;
    RangeXF.HAlign := CellHAl;
  end;
end;

procedure TFrExcel.SetCellOrientation(Grad: Integer);
begin
  if RangeXF <> nil then
  begin
    RangeXF.Rotation := Grad;
  end;
end;

procedure TFrExcel.SetRange(x, y, dx, dy: Integer);
begin
 if (dx = 0) or (dy = 0) then
   dx := dx;
 RangeXF := nil;
 if (dx > 0) and (dy > 0) then
 begin
   RangeXF := XF.Workbook.Sheets[0].Ranges.Add;
   RangeXF.AddRect(y - 1,  y - 1 + dy - 1, x - 1, x - 1 + dx - 1);
   RangeXF.Wrap := True;
 end;
end;

procedure TfrExcel.SetCellFrame(Frame: integer);
begin
  if RangeXF <> nil then
  begin
    if (Frame and frftLeft) <> 0 then
      RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderLeft);
    if (Frame and frftRight) <> 0 then
      RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderRight);
    if (Frame and frftTop) <> 0 then
      RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderTop);
    if (Frame and frftBottom) <> 0 then
      RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderBottom);
  end;
end;

procedure TfrExcel.SetCellFrameInsideH;
begin
  if RangeXF <> nil then
  begin
    RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderLeft);
    RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderRight);
  end;
end;
procedure TfrExcel.SetCellFrameInsideV;
begin
  if RangeXF <> nil then
  begin
    RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderTop);
    RangeXF.BordersEdge(xlColorBlack, BorderStyle, xlBorderBottom);
  end;
end;

procedure TfrExcel.SetCellFillColor(AColor: integer);
begin
  if RangeXF <> nil then
  begin
    RangeXF.FillPattern := xlPatternSolid;
    //RangeXF.FillPatternBGColorIndex := AColor;
    RangeXF.FillPatternBGColorRGB := AColor;
  end;
end;

procedure TfrExcel.SendArrayValue(Arr: variant);
begin
  if RangeXF <> nil then
  begin
    RangeXF.Value := Arr;
  end;
end;

//////////////////////////////////////////////

procedure TfrOLEExcelSet.Localize;
begin
  Ok.Caption := frLoadStr(SOk);
  Cancel.Caption := frLoadStr(SCancel);
  GroupPageRange.Caption := frLoadStr(frRes + 44);
  Pages.Caption := frLoadStr(frRes + 47);
  Descr.Caption := frLoadStr(frRes + 48);
  Caption := frLoadStr(frRes + 1844);
  GroupPageSettings.Caption := frLoadStr(frRes + 1845);
  Topm.Caption := frLoadStr(frRes + 1846);
  Leftm.Caption := frLoadStr(frRes + 1847);
  ScX.Caption := frLoadStr(frRes + 1848);
  ScY.Caption := frLoadStr(frRes + 1849);
  GroupCellProp.Caption := frLoadStr(frRes + 1850);
  CB_Merged.Caption := frLoadStr(frRes + 1851);
  CB_Align.Caption := frLoadStr(frRes + 1852);
  CB_FillColor.Caption := frLoadStr(frRes + 1853);
  CB_Borders.Caption := frLoadStr(frRes + 1854);
  CB_WrapWords.Caption := frLoadStr(frRes + 1855);
  CB_FontName.Caption := frLoadStr(frRes + 1856);
  CB_FontSize.Caption := frLoadStr(frRes + 1857);
  CB_FontStyle.Caption := frLoadStr(frRes + 1858);
  CB_FontColor.Caption := frLoadStr(frRes + 1859);
  CB_PageBreaks.Caption := frLoadStr(frRes + 1860);
  Better.Caption := frLoadStr(frRes + 1861);
  Faster.Caption := frLoadStr(frRes + 1862);
  CB_Pictures.Caption := frLoadStr(frRes + 1863);
  CB_OpenExcel.Caption := frLoadStr(frRes + 1864);
end;

procedure TfrOLEExcelSet.BetterClick(Sender: TObject);
begin
   CB_Merged.Checked := true;
   CB_WrapWords.Checked := true;
   CB_FillColor.Checked := true;
   CB_Borders.Checked := true;
   CB_Align.Checked := true;
   CB_PageBreaks.Checked := true;
   CB_FontName.Checked := true;
   CB_FontSize.Checked := true;
   CB_FontStyle.Checked := true;
   CB_FontColor.Checked := true;
   CB_Pictures.Checked := true;
end;

procedure TfrOLEExcelSet.FasterClick(Sender: TObject);
begin
   CB_Merged.Checked := true;
   CB_WrapWords.Checked := true;
   CB_FillColor.Checked := false;
   CB_Borders.Checked := false;
   CB_Align.Checked := false;
   CB_PageBreaks.Checked := true;
   CB_FontName.Checked := false;
   CB_FontSize.Checked := false;
   CB_FontStyle.Checked := false;
   CB_FontColor.Checked := false;
   CB_Pictures.Checked := false;
end;

procedure TfrOLEExcelSet.FormCreate(Sender: TObject);
begin
   Localize;
end;

procedure TFrExcel.SetCellNumFormat(Format: char);
var
  Fsi: integer;
begin
  if RangeXF <> nil then
  begin
    Fsi := 0;
    case Format of
      '@': Fsi := 35;
    end;
    RangeXF.FormatStringIndex := Fsi;
  end;
end;

{ TfrBasicExpFilter }

constructor TfrBasicExpFilter.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
    
  FFileCaption := '';

  FCanceledExport := false;
  FLeaveCellsWithTag := false;
  FTagForLeaveCell := #0;      

  FOnStartExportPageEvent := nil;
  FOnProgressExportPageEvent := nil;
  FOnEndExportPageEvent := nil;
end;

{ TfrPDFExport }

procedure TfrPDFExport.AfterExport(const FileName: String);
begin

  //ExportDoc;

  if Assigned(FOnEndExportPageEvent) then
    FOnEndExportPageEvent(Self, FCanceledExport);
  if FCanceledExport then
   Cancel;
end;

procedure TfrPDFExport.BeforeExport(var FileName: String;
  var bContinue: Boolean);
var
  i: Integer;
begin
  FObjectsCount := 0;
  FObjectCountExported := 0;
  FCanceledExport := false;

  // находим количество объектов для экспорта

  for i := 0 to CurReport.Pages.Count - 1 do
    FObjectsCount := FObjectsCount + CurReport.Pages[i].Objects.Count;
  // на самом деле объектов получается примерно в 4.5 раза больше
  FObjectsCount := FObjectsCount * 2; //Trunc(FObjectsCount * 4.53);

  if Assigned(FOnStartExportPageEvent) then
    FOnStartExportPageEvent(Self, FFileCaption, FObjectsCount);
  //if Assigned(FOnStartExportPageEvent) then
  //  FOnStartExportPageEvent(Self, FCaption, CurReport.Pages.Count);
end;

procedure TfrPDFExport.Cancel;
begin
  CurReport.Terminated := True;
end;

procedure TfrPDFExport.ExportDoc;
var
  i: integer;
  CanDraw: Boolean;
  View: TfrView;
begin
  for i := 0 to FObjectsToExport.Count - 1 do
  begin
    View := TfrView(FObjectsToExport[i]);
    if Assigned(FOnProgressExportPageEvent) then
    begin
      FOnProgressExportPageEvent(Self, FCanceledExport, FObjectCountExported, FObjectsCount);
      if FCanceledExport then
      begin
        Cancel;
        Exit; ///// EXIT /////
      end;
    end;

    CanDraw := true;
    if FLeaveCellsWithTag then
      if View.Tag = FTagForLeaveCell then
        CanDraw := true;

    if CanDraw and Assigned(FPDF) then
      View.Draw(FPDF.Canvas);

    FObjectCountExported := FObjectCountExported + 1;
  end;
end;

constructor TfrPDFExport.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  //02.03.2012 FPDF := TPDFDocument.Create(Self);

  if ClassName = 'TfrPDFExport' then
    frRegisterExportFilter(Self, 'Adobe Acrobat Documents (*.pdf)', '*.pdf');

  FIsDefObjCountMode := false;

  FObjectsToExport := TList.Create;

  OnBeforeExport := BeforeExport;
  OnAfterExport := AfterExport;
end;

destructor TfrPDFExport.Destroy;
begin
  FreeAndNil(FObjectsToExport);

  frUnRegisterExportFilter(Self);
  //02.03.2012 FreeAndNil(FPDF);
  inherited;
end;

procedure TfrPDFExport.OnBeginDoc;
//var
//  DC: HDC;
begin
  {inherited;
  if FPDF.Printing then FPDF.Abort;
  FPDF.FileName := FileName;
  FPDF.OutputStream := Stream;
  FPDF.Compression := ctFlate;
  FPDF.NonEmbeddedFont.Add('WingDings');
  FPDF.OnePass := True;
  DC := GetDC(0);
  FPDF.Resolution := GetDeviceCaps(dc, LOGPIXELSX);
  Alpha :=  FPDF.Resolution/91.4;
  ReleaseDC(0, DC);
  FPDF.BeginDoc;
  FP := True;
  CurPage := -1;}

  FPDF := CreatePDFObject(Self, FTitle, FileName, Stream); //02.03.2012

  inherited;
  if FPDF.Printing then FPDF.Abort;

  {//02.03.2012
  FPDF.DocumentInfo.Title := FTitle; //название отчета
  FPDF.DocumentInfo.Subject := '';
  FPDF.DocumentInfo.Producer := cResourceReport_Msg24 +ApplicationName+' '+VersionEXE;
  FPDF.DocumentInfo.Author := ExpertSoft_r;
  FPDF.DocumentInfo.Creator := '';
  FPDF.DocumentInfo.Keywords := '';

  FPDF.FileName := FileName;
  FPDF.OutputStream := Stream;
  FPDF.Compression := ctFlate;
  FPDF.NonEmbeddedFont.Add('WingDings');
  FPDF.OnePass := True;
  DC := GetDC(0);
  FPDF.Resolution := GetDeviceCaps(dc, LOGPIXELSX);
  ReleaseDC(0, DC); }

  Alpha := 1;// FPDF.Resolution/91.4;

  FPDF.BeginDoc;
  FP := True;
  CurPage := -1;
end;

procedure TfrPDFExport.OnBeginPage;
begin
  Inc(CurPage);
  if CurPage <> 0 then
    FPDF.NewPage;
  FPDF.CurrentPage.Width := Round(CurReport.EMFPages[CurPage].PrnInfo.Pgw * Alpha);
  FPDF.CurrentPage.Height := Round(CurReport.EMFPages[CurPage].PrnInfo.Pgh * Alpha);

  {FOnProgressExportPageEvent(Self, FCanceledExport, CurPage + 1, CurReport.EMFPages.Count);
  if FCanceledExport then
  begin
    Cancel;
    Exit; ///// EXIT /////
  end; }
end;

procedure TfrPDFExport.OnData(x, y: Integer; View: TfrView);
//var
//  ax, ay: Extended;
var
  CanDraw: Boolean;
begin
  //FObjectsToExport.Add(View);
  //FObjectsCount := FObjectsCount + 1;

  if FIsDefObjCountMode then
    FObjectsCount := FObjectsCount + 1
  else
  begin
    //  ax := View.ScaleX;
    //  ay := View.ScaleY;
    //  View.ScaleX := View.ScaleX*Alpha;
    //  View.ScaleY := View.ScaleY*Alpha;

    if Assigned(FOnProgressExportPageEvent) then
    begin
      if FObjectsCount < FObjectCountExported then
        FObjectsCount := FObjectCountExported;
      FOnProgressExportPageEvent(Self, FCanceledExport, FObjectCountExported, FObjectsCount);
      if FCanceledExport then
      begin
        Cancel;
        Exit; ///// EXIT /////
      end;
    end;

    CanDraw := true;
    if FLeaveCellsWithTag then
      if View.Tag = FTagForLeaveCell then
        CanDraw := true;

    if CanDraw and Assigned(FPDF) then
      View.Draw(FPDF.Canvas);

    FObjectCountExported := FObjectCountExported + 1;

    //  View.ScaleX := AX;
    //  View.ScaleY := AY;
  end; 
end;

procedure TfrPDFExport.OnEndDoc;
begin
  //ExportDoc;
  try
    FPDF.EndDoc;
  except
    on Exception do
    begin
      FPDF.Abort;
      raise;
    end;
  end;
  FreeAndNil(FPDF); //02.03.2012
end;



end.

