home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 January / Chip_2003-01_cd1.bin / zkuste / delphi / kolekce / d567 / FLEXCEL.ZIP / XLSAdapter / UXlsEscher.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-10-10  |  14.1 KB  |  457 lines

  1. unit UXlsEscher;
  2.  
  3. interface
  4. uses UXlsBaseRecords, UXlsBaseRecordLists, UXlsOtherRecords,
  5.      XlsMessages, UFlxMessages, Classes, SysUtils, UEscherRecords, UXlsSST, UBreakList,
  6.      UEscherOtherRecords;
  7.  
  8. type
  9.   TXlsEscherRecord = class (TBaseRecord)
  10.   end;
  11.  
  12.   TDrawingGroupRecord = class (TXlsEscherRecord)
  13.   end;
  14.  
  15.   TDrawingRecord = class (TXlsEscherRecord)
  16.   end;
  17.  
  18.  
  19.   TDrawingSelectionRecord = class (TXlsEscherRecord)
  20.   end;
  21.  
  22.   TDrawingGroup= class
  23.   private
  24.     FDggContainer: TEscherContainerRecord;
  25.     FRecordCache: TEscherDwgGroupCache;
  26.     function GetRecordCache: PEscherDwgGroupCache;
  27.   public
  28.     property  RecordCache: PEscherDwgGroupCache read GetRecordCache;
  29.  
  30.     constructor Create;
  31.     procedure Clear;
  32.     destructor Destroy; override;
  33.     procedure LoadFromStream(const DataStream: TStream; const First: TDrawingGroupRecord);
  34.     procedure SaveToStream(const DataStream: TStream);
  35.     function TotalSize: int64;
  36.  
  37.     procedure AddDwg;
  38.   end;
  39.  
  40.   TDrawing=class
  41.   private
  42.     FDgContainer: TEscherContainerRecord;
  43.     FRecordCache: TEscherDwgCache;
  44.     FDrawingGroup: TDrawingGroup;
  45.     function GetDrawingName(index: integer): widestring;
  46.     function GetDrawingRow(index: integer): integer;
  47.  
  48.   public
  49.     procedure Clear;
  50.     constructor Create(const aDrawingGroup: TDrawingGroup);
  51.     destructor Destroy; override;
  52.  
  53.     procedure CopyFrom(const aDrawing: TDrawing);
  54.     procedure LoadFromStream(const DataStream: TStream; const First: TDrawingRecord; const SST: TSST);
  55.     procedure SaveToStream(const DataStream: TStream);
  56.     function TotalSize: int64;
  57.  
  58.     procedure ArrangeInsert(const aPos, aCount:integer; const SheetInfo: TSheetInfo);
  59.     procedure ArrangeCopySheet(const SheetInfo: TSheetInfo);
  60.     procedure InsertAndCopyRows(const FirstRow, LastRow, DestRow, aCount: integer; const SheetInfo: TSheetInfo);
  61.     procedure DeleteRows(const aRow, aCount: word;const SheetInfo: TSheetInfo);
  62.  
  63.     function FindObjId(const ObjId: word): TEscherClientDataRecord;
  64.  
  65.     function DrawingCount: integer;
  66.     procedure AssignDrawing(const Index: integer; const Data: string; const DataType: TXlsImgTypes);
  67.     function GetAnchor(const Index: integer): TClientAnchor;
  68.     procedure GetDrawingFromStream(const Index: integer; const Data: TStream; var DataType: TXlsImgTypes);
  69.     property DrawingRow[index: integer]: integer read GetDrawingRow;
  70.     property DrawingName[index: integer]: widestring read GetDrawingName;
  71.  
  72.   end;
  73.  
  74. implementation
  75. uses UXlsBaseClientData, UXlsClientData;
  76.  
  77. { TDrawingGroup }
  78.  
  79. procedure TDrawingGroup.AddDwg;
  80. begin
  81.   if FRecordCache.Dgg<>nil then inc(FRecordCache.Dgg.FDgg.DwgSaved);
  82.   //PENDING: fix sheets
  83.  
  84. end;
  85.  
  86. procedure TDrawingGroup.Clear;
  87. begin
  88.   FreeAndNil(FDggContainer);
  89. end;
  90.  
  91. constructor TDrawingGroup.Create;
  92. begin
  93.   inherited Create;
  94. end;
  95.  
  96. destructor TDrawingGroup.Destroy;
  97. begin
  98.   Clear;
  99.   inherited;
  100. end;
  101.  
  102. function TDrawingGroup.GetRecordCache: PEscherDwgGroupCache;
  103. begin
  104.   Result:=@FRecordCache;
  105. end;
  106.  
  107. procedure TDrawingGroup.LoadFromStream(const DataStream: TStream; const First: TDrawingGroupRecord);
  108. const
  109.   DwgCache: TEscherDwgCache= ( MaxObjId:0; Dg: nil; Solver: nil; Patriarch:nil; Anchor: nil; Shape: nil; Obj: nil; Blip: nil);
  110. var
  111.   aPos: integer;
  112.   EscherHeader: TEscherRecordHeader;
  113.   RecordHeader: TRecordHeader;
  114.   MyRecord, CurrentRecord: TBaseRecord;
  115. begin
  116.   if FDggContainer<>nil then raise Exception.Create(ErrExcelInvalid);
  117.   aPos:=0;
  118.   MyRecord:= First; CurrentRecord:= First;
  119.   try
  120.     ReadMem(MyRecord, aPos, SizeOf(EscherHeader), @EscherHeader);
  121.     FDggContainer:= TEscherContainerRecord.Create(EscherHeader, RecordCache, @DwgCache ,nil);
  122.     while not FDggContainer.Loaded do
  123.     begin
  124.       if (MyRecord.Continue=nil) and (aPos=MyRecord.DataSize) then
  125.       begin
  126.         if CurrentRecord<> First then FreeAndNil(CurrentRecord);
  127.         if (DataStream.Read(RecordHeader, sizeof(RecordHeader)) <> sizeof(RecordHeader)) then
  128.           raise Exception.Create(ErrExcelInvalid);
  129.         CurrentRecord:=LoadRecord(DataStream, RecordHeader);
  130.         MyRecord:= CurrentRecord;
  131.         aPos:=0;
  132.         if not(MyRecord is TDrawingGroupRecord) then raise Exception.Create(ErrExcelInvalid);
  133.       end;
  134.  
  135.       FDggContainer.Load(MyRecord, aPos);
  136.  
  137.     end; //while
  138.   finally
  139.     if CurrentRecord<>First then FreeAndNil(CurrentRecord);
  140.   end; //finally
  141.  
  142.   First.Free;   //last statment
  143. end;
  144.  
  145. procedure TDrawingGroup.SaveToStream(const DataStream: TStream);
  146. var
  147.   BreakList: TBreakList;
  148.   NextPos, RealSize, NewDwg: integer;
  149. begin
  150.   if FDggContainer=nil then exit;
  151.   BreakList:= TBreakList.Create(DataStream.Position);
  152.   try
  153.     NextPos:=0;
  154.     RealSize:=0;
  155.     NewDwg:= xlr_MSODRAWINGGROUP;
  156.     FDggContainer.SplitRecords(NextPos, RealSize, NewDwg, BreakList);
  157.     BreakList.Add(0, NextPos);
  158.     FDggContainer.SaveToStream(DataStream, BreakList);
  159.   finally
  160.     FreeAndNil(BreakList);
  161.   end; //finally
  162. end;
  163.  
  164. function TDrawingGroup.TotalSize: int64;
  165. var
  166.   NextPos, RealSize, NewDwg: integer;
  167. begin
  168.   if FDggContainer=nil then begin Result:=0; exit;end;
  169.  
  170.   NextPos:=0; RealSize:=0; NewDwg:= xlr_MSODRAWINGGROUP;
  171.   FDggContainer.SplitRecords(NextPos, RealSize, NewDwg, nil);
  172.   Result:=RealSize;
  173. end;
  174.  
  175. { TDrawing }
  176.  
  177. procedure TDrawing.ArrangeCopySheet(const SheetInfo: TSheetInfo);
  178. begin
  179.   if (FRecordCache.Obj<> nil) then
  180.     FRecordCache.Obj.ArrangeCopySheet(SheetInfo);
  181. end;
  182.  
  183. procedure TDrawing.ArrangeInsert(const aPos, aCount: integer; const SheetInfo: TSheetInfo);
  184. begin
  185.   if (FRecordCache.Anchor<> nil) and (SheetInfo.FormulaSheet= SheetInfo.InsSheet)then
  186.     FRecordCache.Anchor.ArrangeInsert(aPos, aCount, SheetInfo, false);
  187.   if (FRecordCache.Obj<> nil) then
  188.     FRecordCache.Obj.ArrangeInsert(aPos, aCount, SheetInfo, false);
  189. end;
  190.  
  191. procedure TDrawing.AssignDrawing(const Index: integer; const Data: string;
  192.   const DataType: TXlsImgTypes);
  193. begin
  194.   FRecordCache.Blip[Index].ReplaceImg(Data, DataType);
  195. end;
  196.  
  197. procedure TDrawing.Clear;
  198. begin
  199.   FreeAndNil(FDgContainer);
  200.   //Order is important... Cache should be freed after DgContainer
  201.   FreeAndNil(FRecordCache.Anchor);
  202.   FreeAndNil(FRecordCache.Obj);
  203.   FreeAndNil(FRecordCache.Shape);
  204.   FreeAndNil(FRecordCache.Blip);
  205. end;
  206.  
  207. procedure TDrawing.CopyFrom(const aDrawing: TDrawing);
  208. begin
  209.   Clear;
  210.   FRecordCache.MaxObjId:=0;
  211.   FRecordCache.Dg:=nil; FRecordCache.Patriarch:=nil;
  212.  
  213.   if aDrawing.FRecordCache.Anchor<>nil then
  214.   begin
  215.     FRecordCache.Anchor:= TEscherAnchorCache.Create;
  216.     FRecordCache.Obj:= TEscherObjCache.Create;
  217.     FRecordCache.Shape:= TEscherShapeCache.Create;
  218.     FRecordCache.Blip:=TEscherOPTCache.Create;
  219.   end;
  220.  
  221.   if aDrawing.FDgContainer=nil then FreeAndNil(FDgcontainer) else
  222.   begin
  223.     aDrawing.FDgContainer.ClearCopiedTo;
  224.     FDgContainer:=aDrawing.FDgContainer.CopyTo(@FRecordCache, 0) as TEscherContainerRecord;
  225.     FRecordCache.Shape.Sort; // only here the values are loaded...
  226.     if FRecordCache.Solver<>nil then FRecordCache.Solver.CheckMax(aDrawing.FRecordCache.Solver.MaxRuleId);
  227.  
  228.     FDrawingGroup.AddDwg;
  229.   end;
  230.   //MADE: change cache
  231. end;
  232.  
  233. constructor TDrawing.Create(const aDrawingGroup: TDrawingGroup);
  234. begin
  235.   inherited Create;
  236.   FDrawingGroup:=aDrawingGroup;
  237.   FRecordCache.Destroying:=false;
  238. end;
  239.  
  240. procedure TDrawing.DeleteRows(const aRow, aCount: word;
  241.   const SheetInfo: TSheetInfo);
  242. var i: integer;
  243. begin
  244.   //MADE: delete rows
  245.   //MADE: Arreglar los continues...
  246.   //MADE: Conectores
  247.   if FRecordcache.Anchor=nil then exit;
  248.   for i:= FRecordCache.Anchor.Count-1 downto 0 do
  249.     if FRecordCache.Anchor[i].AllowDelete(aRow, aRow+aCount-1)then
  250.     begin
  251.       if (FRecordCache.Patriarch=nil) then raise Exception.Create(ErrLoadingEscher);
  252.       FRecordCache.Patriarch.ContainedRecords.Remove(FRecordCache.Anchor[i].FindRoot);
  253.     end;
  254.  
  255.   ArrangeInsert(aRow, -aCount, SheetInfo);
  256. end;
  257.  
  258. destructor TDrawing.Destroy;
  259. begin
  260.   FRecordCache.Destroying:=true;
  261.   Clear;
  262.   inherited;
  263. end;
  264.  
  265. function TDrawing.DrawingCount: integer;
  266. begin
  267.   if FRecordCache.Blip<>nil then Result:=FRecordCache.Blip.Count else Result:=0;
  268. end;
  269.  
  270. function TDrawing.FindObjId(const ObjId: word): TEscherClientDataRecord;
  271. var
  272.   i: integer;
  273. begin
  274.   for i:=0 to FRecordCache.Obj.Count-1 do if FRecordCache.Obj[i].ObjId=ObjId then
  275.   begin
  276.     Result:=FRecordCache.Obj[i];
  277.     exit;
  278.   end;
  279.   Result:=nil;
  280. end;
  281.  
  282. function TDrawing.GetAnchor(const Index: integer): TClientAnchor;
  283. begin
  284.   Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  285.   Result:=FRecordCache.Blip[index].GetAnchor;
  286. end;
  287.  
  288. procedure TDrawing.GetDrawingFromStream(const Index: integer; const Data: TStream; var DataType: TXlsImgTypes);
  289. begin
  290.   Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  291.   FRecordCache.Blip[index].GetImageFromStream(Data, DataType);
  292. end;
  293.  
  294. function TDrawing.GetDrawingName(index: integer): widestring;
  295. begin
  296.   Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  297.   Result:=FRecordCache.Blip[index].ShapeName;
  298. end;
  299.  
  300. function TDrawing.GetDrawingRow(index: integer): integer;
  301. begin
  302.   Assert(Index<FRecordCache.Blip.Count,'Index out of range');
  303.   Result:=FRecordCache.Blip[index].Row;
  304. end;
  305.  
  306. procedure TDrawing.InsertAndCopyRows(const FirstRow, LastRow, DestRow,
  307.   aCount: integer; const SheetInfo: TSheetInfo);
  308. var
  309.   i,k, myDestRow, myFirstRow, myLastRow: integer;
  310. begin
  311.   if (FDgContainer=nil) or (FRecordCache.Anchor= nil) then exit;  //no drawings on this sheet
  312.  
  313.   if DestRow>FirstRow then
  314.   begin
  315.     myFirstRow:=FirstRow; myLastRow:=LastRow;
  316.   end else
  317.   begin
  318.     myFirstRow:=FirstRow+aCount*(LastRow-FirstRow+1);
  319.     myLastRow:=LastRow+aCount*(LastRow-FirstRow+1);
  320.   end;
  321.  
  322.   //Insert cells
  323.   ArrangeInsert(DestRow, aCount*(LastRow-FirstRow+1), SheetInfo);
  324.  
  325.   //Copy the images
  326.   myDestRow:=DestRow;
  327.   for k:= 0 to aCount-1 do
  328.   begin
  329.     FDgContainer.ClearCopiedTo;
  330.     for i:= 0 to FRecordCache.Anchor.Count-1 do
  331.       if FRecordCache.Anchor[i].AllowCopy(myFirstRow, myLastRow)then
  332.       begin
  333.          FRecordCache.Anchor[i].CopyDwg(myDestRow-myFirstRow);
  334.       end;
  335.     inc(myDestRow, (LastRow-FirstRow+1));
  336.     if FRecordCache.Solver<>nil then FRecordCache.Solver.ArrangeCopyRows;
  337.   end;
  338.  
  339. end;
  340.  
  341. procedure TDrawing.LoadFromStream(const DataStream: TStream;
  342.   const First: TDrawingRecord; const SST: TSST);
  343. var
  344.   aPos, CdPos: integer;
  345.   EscherHeader: TEscherRecordHeader;
  346.   RecordHeader: TRecordHeader;
  347.   MyRecord, CurrentRecord, R, CdRecord: TBaseRecord;
  348.   FClientData: TBaseClientData;
  349.   ClientType: ClassOfTBaseClientData;
  350. begin
  351.   Assert (FDrawingGroup<>nil,'DrawingGroup can''t be nil');
  352.   if FDgContainer<>nil then raise Exception.Create(ErrExcelInvalid);
  353.  
  354.   FRecordCache.MaxObjId:=0;
  355.   FRecordCache.Dg:=nil; FRecordCache.Patriarch:=nil; FRecordCache.Solver:=nil;
  356.   FRecordCache.Anchor:= TEscherAnchorCache.Create;
  357.   FRecordCache.Obj:= TEscherObjCache.Create;
  358.   FRecordCache.Shape:= TEscherShapeCache.Create;
  359.   FRecordCache.Blip:= TEscherOPTCache.Create;
  360.  
  361.   aPos:=0;
  362.   MyRecord:= First; CurrentRecord:= First;
  363.   try
  364.     ReadMem(MyRecord, aPos, SizeOf(EscherHeader), @EscherHeader);
  365.     FDgContainer:= TEscherContainerRecord.Create(EscherHeader, FDrawingGroup.RecordCache, @FRecordCache ,nil);
  366.     while (not FDgContainer.Loaded) or FDgContainer.WaitingClientData(ClientType) do
  367.     begin
  368.       if not FDgContainer.WaitingClientData(ClientType) then
  369.       begin
  370.         if (MyRecord.Continue=nil) and (aPos=MyRecord.DataSize) then
  371.         begin
  372.           if CurrentRecord<> First then FreeAndNil(CurrentRecord);
  373.           if (DataStream.Read(RecordHeader, sizeof(RecordHeader)) <> sizeof(RecordHeader)) then
  374.             raise Exception.Create(ErrExcelInvalid);
  375.           CurrentRecord:=LoadRecord(DataStream, RecordHeader);
  376.           MyRecord:= CurrentRecord;
  377.           aPos:=0;
  378.           if not(MyRecord is TDrawingRecord) then raise Exception.Create(ErrExcelInvalid);
  379.         end;
  380.         FDgContainer.Load(MyRecord, aPos);
  381.       end else
  382.       begin
  383.         if not ((MyRecord.Continue=nil) and (aPos=MyRecord.DataSize)) then raise Exception.Create(ErrExcelInvalid);
  384.         if (DataStream.Read(RecordHeader, sizeof(RecordHeader)) <> sizeof(RecordHeader)) then
  385.           raise Exception.Create(ErrExcelInvalid);
  386.  
  387.          R:=LoadRecord(DataStream, RecordHeader);
  388.          try
  389.            if (R is ClientType.ObjRecord) then
  390.            begin
  391.              FClientData:= ClientType.Create;
  392.              try
  393.                FClientData.LoadFromStream(DataStream, R , SST);
  394.                FDgContainer.AssignClientData(FClientData);
  395.                if FClientData.RemainingData<>nil then
  396.                begin
  397.                  CdRecord:=FClientData.RemainingData; //we dont have to free this
  398.                  CdPos:=0;
  399.                  FDgContainer.Load(CdRecord, CdPos);
  400.                end;
  401.              except
  402.                FreeAndNil(FClientData);
  403.                raise;
  404.              end; //except
  405.            end else raise Exception.Create(ErrInvalidDrawing);
  406.          except
  407.            FreeAndNil(R);
  408.            raise;
  409.          end; //Except
  410.       end;
  411.  
  412.     end; //while
  413.   finally
  414.     if CurrentRecord<>First then FreeAndNil(CurrentRecord);
  415.   end; //finally
  416.  
  417.   FRecordCache.Shape.Sort; // only here the values are loaded...
  418.   if FRecordCache.Solver <>nil then FRecordCache.Solver.FixPointers;
  419.  
  420.  
  421.   //PENDING: Wmf, emf
  422.  
  423.   First.Free;   //last statment
  424. end;
  425.  
  426. procedure TDrawing.SaveToStream(const DataStream: TStream);
  427. var
  428.   BreakList: TBreakList;
  429.   NextPos, RealSize, NewDwg: integer;
  430. begin
  431.   if FDgContainer=nil then exit;
  432.   BreakList:= TBreakList.Create(DataStream.Position);
  433.   try
  434.     NextPos:=0;
  435.     RealSize:=0;
  436.     NewDwg:= xlr_MSODRAWING;
  437.     FDgContainer.SplitRecords(NextPos, RealSize, NewDwg, BreakList);
  438.     BreakList.Add(0, NextPos);
  439.     FDgContainer.SaveToStream(DataStream, BreakList);
  440.   finally
  441.     FreeAndNil(BreakList);
  442.   end; //finally
  443. end;
  444.  
  445. function TDrawing.TotalSize: int64;
  446. var
  447.   NextPos, RealSize, NewDwg: integer;
  448. begin
  449.   if FDgContainer=nil then begin Result:=0; exit;end;
  450.  
  451.   NextPos:=0; RealSize:=0; NewDwg:= xlr_MSODRAWINGGROUP;
  452.   FDgContainer.SplitRecords(NextPos, RealSize, NewDwg, nil);
  453.   Result:=RealSize;
  454. end;
  455.  
  456. end.
  457.