home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 October / Chip_2002-10_cd1.bin / zkuste / delphi / kolekce / d56 / FLEXCEL.ZIP / XLSAdapter / UXlsEscher.pas < prev    next >
Pascal/Delphi Source File  |  2002-07-03  |  14KB  |  432 lines

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