⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uxlsescher.pas

📁 TMS Component Pack Pro v4.2
💻 PAS
📖 第 1 页 / 共 2 页
字号:
unit UXlsEscher;
{$IFDEF LINUX}{$INCLUDE ../FLXCOMPILER.INC}{$ELSE}{$INCLUDE ..\FLXCOMPILER.INC}{$ENDIF}

interface
uses UXlsBaseRecords, UXlsBaseRecordLists, UXlsOtherRecords,
     XlsMessages, UFlxMessages, Classes, SysUtils, UEscherRecords, UXlsSST, UBreakList,
     UEscherOtherRecords;

type

  TXlsEscherRecord = class (TBaseRecord)
  end;

  TDrawingGroupRecord = class (TXlsEscherRecord)
  end;

  TDrawingRecord = class (TXlsEscherRecord)
  end;


  TDrawingSelectionRecord = class (TXlsEscherRecord)
  end;

  TDrawingGroup= class
  private
    FDggContainer: TEscherContainerRecord;
    FRecordCache: TEscherDwgGroupCache;
    function GetRecordCache: PEscherDwgGroupCache;
  public
    property  RecordCache: PEscherDwgGroupCache read GetRecordCache;

    constructor Create;
    procedure Clear;
    destructor Destroy; override;
    procedure LoadFromStream(const DataStream: TStream; const First: TDrawingGroupRecord);
    procedure SaveToStream(const DataStream: TStream);
    function TotalSize: int64;

    procedure AddDwg;
    procedure EnsureDwgGroup;
  end;

  TDrawing=class
  private
    FDgContainer: TEscherContainerRecord;
    FRecordCache: TEscherDwgCache;
    FDrawingGroup: TDrawingGroup;
    function GetDrawingName(index: integer): widestring;
    function GetDrawingRow(index: integer): integer;
    procedure CreateBasicDrawingInfo;

  public
    procedure Clear;
    constructor Create(const aDrawingGroup: TDrawingGroup);
    destructor Destroy; override;

    procedure CopyFrom(const aDrawing: TDrawing);
    procedure LoadFromStream(const DataStream: TStream; const First: TDrawingRecord; const SST: TSST);
    procedure SaveToStream(const DataStream: TStream);
    function TotalSize: int64;

    procedure ArrangeInsertRowsAndCols(const aRowPos, aRowCount, aColPos, aColCount: integer; const SheetInfo: TSheetInfo);
    procedure ArrangeCopySheet(const SheetInfo: TSheetInfo);
    procedure InsertAndCopyRowsAndCols(const FirstRow, LastRow, DestRow, RowCount, FirstCol, LastCol, DestCol, ColCount: integer; const SheetInfo: TSheetInfo);
    procedure DeleteRows(const aRow, aCount: word;const SheetInfo: TSheetInfo);
    procedure DeleteCols(const aCol, aCount: word;const SheetInfo: TSheetInfo);

    function FindObjId(const ObjId: word): TEscherClientDataRecord;

    function DrawingCount: integer;
    procedure AssignDrawing(const Index: integer; const Data: string; const DataType: TXlsImgTypes);
    function GetAnchor(const Index: integer): TClientAnchor;
    procedure SetAnchor(const Index: integer; const aAnchor: TClientAnchor);
    procedure GetDrawingFromStream(const Index: integer; const Data: TStream; var DataType: TXlsImgTypes);
    property DrawingRow[index: integer]: integer read GetDrawingRow;
    property DrawingName[index: integer]: widestring read GetDrawingName;

    procedure DeleteImage(const Index: integer);
    procedure ClearImage(const Index: integer);
    procedure AddImage(Data: string; DataType: TXlsImgTypes; const Properties: TImageProperties;const Anchor: TFlxAnchorType);

    function AddNewComment(const Properties: TImageProperties): TEscherClientDataRecord;
  end;

implementation
uses UXlsBaseClientData, UXlsClientData;
const
  EmptyBmp= #$28#$0#$0#$0#$1#$0+
            #$0#$0#$1#$0#$0#$0#$1#$0#$1#$0#$0#$0#$0#$0#$0#$0#$0#$0#$12#$B#$0+
            #$0#$12#$B#$0#$0#$0#$0#$0#$0#$0#$0#$0#$0#$FF#$FF#$FF#$0#$0#$0+
            #$0#$0#$0#$0#$0#$0#$0#$0;

{ TDrawingGroup }

procedure TDrawingGroup.AddDwg;
begin
  if FRecordCache.Dgg<>nil then inc(FRecordCache.Dgg.FDgg.DwgSaved);
  //PENDING: fix sheets

end;

procedure TDrawingGroup.Clear;
begin
  FreeAndNil(FDggContainer);
end;

constructor TDrawingGroup.Create;
begin
  inherited Create;
end;

destructor TDrawingGroup.Destroy;
begin
  Clear;
  inherited;
end;

procedure TDrawingGroup.EnsureDwgGroup;
const
  DwgCache: TEscherDwgCache= ( MaxObjId:0; Dg: nil; Solver: nil; Patriarch:nil; Anchor: nil; Shape: nil; Obj: nil; Blip: nil);
var
  EscherHeader: TEscherRecordHeader;
  FDgg: TEscherDggRecord;
  BStoreContainer: TEscherBStoreRecord;
  OPTRec:TEscherOPTRecord;
  SplitMenu: TEscherSplitMenuRecord;
begin
  if FDggContainer=nil then  // there is already a DwgGroup
  begin
    //DggContainer
    EscherHeader.Pre:=$F;
    EscherHeader.Id:=MsofbtDggContainer;
    EscherHeader.Size:=0;
    FDggContainer:=TEscherContainerRecord.Create(EscherHeader, RecordCache, @DwgCache ,nil);
    FDggContainer.LoadedDataSize:=EscherHeader.Size;
  end;

  if FDggContainer.FindRec(TEscherDggRecord)=nil then
  begin
    //Dgg
    FDgg:=TEscherDggRecord.CreateFromData(RecordCache, @DwgCache ,FDggContainer);
    FDggContainer.ContainedRecords.Add(FDgg);
  end;

  if FDggContainer.FindRec(TEscherBStoreRecord)=nil then
  begin
    // BStoreContainer
    EscherHeader.Pre:=$2F;
    EscherHeader.Id:=MsofbtBstoreContainer;
    EscherHeader.Size:=0;
    BStoreContainer:=TEscherBStoreRecord.Create(EscherHeader, RecordCache, @DwgCache ,FDggContainer);
    BStoreContainer.LoadedDataSize:=EscherHeader.Size;
    FDggContainer.ContainedRecords.Add(BStoreContainer);
  end;

  if FDggContainer.FindRec(TEscherOPTRecord)=nil then
  begin
    //OPT
    OPTRec:=TEscherOPTRecord.GroupCreateFromData(RecordCache, @DwgCache, FDggContainer);
    FDggContainer.ContainedRecords.Add(OPTRec);
  end;

  if FDggContainer.FindRec(TEscherSplitMenuRecord)=nil then
  begin
    //SplitMenuColors
    SplitMenu:=TEscherSplitMenuRecord.CreateFromData(RecordCache, @DwgCache, FDggContainer);
    FDggContainer.ContainedRecords.Add(SplitMenu);
  end;

end;

function TDrawingGroup.GetRecordCache: PEscherDwgGroupCache;
begin
  Result:=@FRecordCache;
end;

procedure TDrawingGroup.LoadFromStream(const DataStream: TStream; const First: TDrawingGroupRecord);
const
  DwgCache: TEscherDwgCache= ( MaxObjId:0; Dg: nil; Solver: nil; Patriarch:nil; Anchor: nil; Shape: nil; Obj: nil; Blip: nil);
var
  aPos: integer;
  EscherHeader: TEscherRecordHeader;
  RecordHeader: TRecordHeader;
  MyRecord, CurrentRecord: TBaseRecord;
begin
  if FDggContainer<>nil then raise Exception.Create(ErrExcelInvalid);
  aPos:=0;
  MyRecord:= First; CurrentRecord:= First;
  try
    ReadMem(MyRecord, aPos, SizeOf(EscherHeader), @EscherHeader);
    FDggContainer:= TEscherContainerRecord.Create(EscherHeader, RecordCache, @DwgCache ,nil);
    while not FDggContainer.Loaded do
    begin
      if (MyRecord.Continue=nil) and (aPos=MyRecord.DataSize) then
      begin
        if CurrentRecord<> First then FreeAndNil(CurrentRecord);
        if (DataStream.Read(RecordHeader, sizeof(RecordHeader)) <> sizeof(RecordHeader)) then
          raise Exception.Create(ErrExcelInvalid);
        CurrentRecord:=LoadRecord(DataStream, RecordHeader);
        MyRecord:= CurrentRecord;
        aPos:=0;
        if not(MyRecord is TDrawingGroupRecord) then raise Exception.Create(ErrExcelInvalid);
      end;

      FDggContainer.Load(MyRecord, aPos);

    end; //while
  finally
    if CurrentRecord<>First then FreeAndNil(CurrentRecord);
  end; //finally

  First.Free;   //last statment
end;

procedure TDrawingGroup.SaveToStream(const DataStream: TStream);
var
  BreakList: TBreakList;
  NextPos, RealSize, NewDwg: integer;
begin
  if FDggContainer=nil then exit;
  BreakList:= TBreakList.Create(DataStream.Position);
  try
    NextPos:=0;
    RealSize:=0;
    NewDwg:= xlr_MSODRAWINGGROUP;
    FDggContainer.SplitRecords(NextPos, RealSize, NewDwg, BreakList);
    BreakList.Add(0, NextPos);
    FDggContainer.SaveToStream(DataStream, BreakList);
  finally
    FreeAndNil(BreakList);
  end; //finally
end;

function TDrawingGroup.TotalSize: int64;
var
  NextPos, RealSize, NewDwg: integer;
begin
  if FDggContainer=nil then begin Result:=0; exit;end;

  NextPos:=0; RealSize:=0; NewDwg:= xlr_MSODRAWINGGROUP;
  FDggContainer.SplitRecords(NextPos, RealSize, NewDwg, nil);
  Result:=RealSize;
end;

{ TDrawing }

procedure TDrawing.ArrangeCopySheet(const SheetInfo: TSheetInfo);
begin
  if (FRecordCache.Obj<> nil) then
    FRecordCache.Obj.ArrangeCopySheet(SheetInfo);
end;

procedure TDrawing.ArrangeInsertRowsAndCols(const aRowPos, aRowCount, aColPos, aColCount: integer; const SheetInfo: TSheetInfo);
begin
  if (FRecordCache.Anchor<> nil) and (SheetInfo.FormulaSheet= SheetInfo.InsSheet)then
    FRecordCache.Anchor.ArrangeInsertRowsAndCols(aRowPos, aRowCount, aColPos, aColCount, SheetInfo, false);
  if (FRecordCache.Obj<> nil) then
    FRecordCache.Obj.ArrangeInsertRowsAndCols(aRowPos, aRowCount, aColPos, aColCount, SheetInfo, false);
end;

procedure TDrawing.AssignDrawing(const Index: integer; const Data: string;
  const DataType: TXlsImgTypes);
begin
  if Data='' then ClearImage(Index)  //XP crashes with a 0 byte image.
  else FRecordCache.Blip[Index].ReplaceImg(Data, DataType);
end;

procedure TDrawing.DeleteImage(const Index: integer);
begin
  if FRecordcache.Blip=nil then exit;
  if (FRecordCache.Patriarch=nil) then raise Exception.Create(ErrLoadingEscher);
  FRecordCache.Patriarch.ContainedRecords.Remove(FRecordCache.Blip[Index].FindRoot);
end;

procedure TDrawing.ClearImage(const Index: integer);
begin
  FRecordCache.Blip[Index].ReplaceImg(EmptyBmp, xli_Bmp);
end;

procedure TDrawing.Clear;
begin
  FreeAndNil(FDgContainer);
  //Order is important... Cache should be freed after DgContainer
  FreeAndNil(FRecordCache.Anchor);
  FreeAndNil(FRecordCache.Obj);
  FreeAndNil(FRecordCache.Shape);
  FreeAndNil(FRecordCache.Blip);
end;

procedure TDrawing.CopyFrom(const aDrawing: TDrawing);
begin
  Clear;
  FRecordCache.MaxObjId:=0;
  FRecordCache.Dg:=nil; FRecordCache.Patriarch:=nil;

  if aDrawing.FRecordCache.Anchor<>nil then
  begin
    FRecordCache.Anchor:= TEscherAnchorCache.Create;
    FRecordCache.Obj:= TEscherObjCache.Create;
    FRecordCache.Shape:= TEscherShapeCache.Create;
    FRecordCache.Blip:=TEscherOPTCache.Create;
  end;

  if aDrawing.FDgContainer=nil then FreeAndNil(FDgcontainer) else
  begin
    aDrawing.FDgContainer.ClearCopiedTo;
    FDgContainer:=aDrawing.FDgContainer.CopyTo(@FRecordCache, 0,0) as TEscherContainerRecord;
    FRecordCache.Shape.Sort; // only here the values are loaded...
    if FRecordCache.Solver<>nil then FRecordCache.Solver.CheckMax(aDrawing.FRecordCache.Solver.MaxRuleId);

    FDrawingGroup.AddDwg;
  end;
  //MADE: change cache
end;

constructor TDrawing.Create(const aDrawingGroup: TDrawingGroup);
begin
  inherited Create;
  FDrawingGroup:=aDrawingGroup;
  FRecordCache.Destroying:=false;
end;

procedure TDrawing.DeleteRows(const aRow, aCount: word;
  const SheetInfo: TSheetInfo);
var i: integer;
begin
  //MADE: delete rows
  //MADE: Arreglar los continues...
  //MADE: Conectores
  if FRecordCache.Anchor=nil then exit;
  for i:= FRecordCache.Anchor.Count-1 downto 0 do
    if FRecordCache.Anchor[i].AllowDelete(aRow, aRow+aCount-1,0,Max_Columns+1)then
    begin
      if (FRecordCache.Patriarch=nil) then raise Exception.Create(ErrLoadingEscher);
      FRecordCache.Patriarch.ContainedRecords.Remove(FRecordCache.Anchor[i].FindRoot);
    end;

  ArrangeInsertRowsAndCols(aRow, -aCount, 0,0, SheetInfo);
end;

procedure TDrawing.DeleteCols(const aCol, aCount: word;
  const SheetInfo: TSheetInfo);
var i: integer;
begin
  //MADE: delete cols
  //MADE: Arreglar los continues...
  //MADE: Conectores
  if FRecordCache.Anchor=nil then exit;
  for i:= FRecordCache.Anchor.Count-1 downto 0 do
    if FRecordCache.Anchor[i].AllowDelete(0, Max_Rows+1, aCol, aCol+aCount-1)then
    begin
      if (FRecordCache.Patriarch=nil) then raise Exception.Create(ErrLoadingEscher);
      FRecordCache.Patriarch.ContainedRecords.Remove(FRecordCache.Anchor[i].FindRoot);
    end;

  ArrangeInsertRowsAndCols(0,0,aCol, -aCount, SheetInfo);
end;

destructor TDrawing.Destroy;
begin
  FRecordCache.Destroying:=true;
  Clear;
  inherited;
end;

function TDrawing.DrawingCount: integer;
begin
  if FRecordCache.Blip<>nil then Result:=FRecordCache.Blip.Count else Result:=0;
end;

function TDrawing.FindObjId(const ObjId: word): TEscherClientDataRecord;
var
  i: integer;
begin
  for i:=0 to FRecordCache.Obj.Count-1 do if FRecordCache.Obj[i].ObjId=ObjId then
  begin
    Result:=FRecordCache.Obj[i];
    exit;
  end;
  Result:=nil;
end;

function TDrawing.GetAnchor(const Index: integer): TClientAnchor;
begin
  Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  Result:=FRecordCache.Blip[index].GetAnchor;
end;

procedure TDrawing.SetAnchor(const Index: integer; const aAnchor: TClientAnchor);
begin
  Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  FRecordCache.Blip[index].SetAnchor(aAnchor);
end;

procedure TDrawing.GetDrawingFromStream(const Index: integer; const Data: TStream; var DataType: TXlsImgTypes);
begin
  Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  FRecordCache.Blip[index].GetImageFromStream(Data, DataType);
end;

function TDrawing.GetDrawingName(index: integer): widestring;
begin
  Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  Result:=FRecordCache.Blip[index].ShapeName;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -