uxlsrowcolentries.pas

来自「DELPHI界面增强控件,非常好,里面有显示GIF的图片控件,更美观的下拉框控件」· PAS 代码 · 共 754 行 · 第 1/2 页

PAS
754
字号
unit UXlsRowColEntries;
{$IFDEF LINUX}{$INCLUDE ../FLXCONFIG.INC}{$ELSE}{$INCLUDE ..\FLXCONFIG.INC}{$ENDIF}
interface
uses Classes, SysUtils, UXlsBaseRecords, UXlsBaseRecordLists, UXlsOtherRecords,
     XlsMessages, UXlsRangeRecords, UXlsBaseList, UXlsCellRecords, UXlsFormula,
     {$IFDEF ConditionalExpressions}{$if CompilerVersion >= 14} variants,{$IFEND}{$ENDIF} //Delphi 6 or above
     UXlsSST, UFlxMessages, UXlsColInfo, UXlsReferences, UXlsWorkbookGlobals;

type
  TListClass= class of TBaseRowColRecordList;

  TBaseRowColList = class(TBaseList) //records are TBaseRowColRecordList
    {$INCLUDE TBaseRowColListHdr.inc}
  protected
    ListClass: TListClass;
  public
    procedure AddRecord(const aRecord: TBaseRowColRecord; const aRow: integer);

    procedure CopyFrom(const aList: TBaseRowColList);

    procedure SaveToStream(const DataStream: TStream);
    procedure SaveRangeToStream(const DataStream: TStream; const CellRange: TXlsCellRange);
    function TotalSize: int64;
    function TotalRangeSize(const CellRange: TXlsCellRange): int64;

    procedure InsertAndCopyRows(const FirstRow, LastRow, DestRow, aCount: integer; const SheetInfo: TSheetInfo; const OnlyFormulas: boolean);
    procedure DeleteRows(const aRow, aCount: word; const SheetInfo: TSheetInfo);
    procedure ArrangeInsert(const InsPos, InsCount: integer; const SheetInfo: TSheetInfo);

    constructor Create(const aListClass: TListClass);
  end;

  TCellList = class (TBaseRowColList)//records are TCellRecordList
  private
    FGlobals: TWorkbookGlobals;
    FRowRecordList: TRowRecordList;
    FColInfoList: TColInfoList;

    function GetValue(Row, Col: integer): TXlsCellValue;
    procedure SetValue(Row, Col: integer; const Value: TXlsCellValue);
    procedure FixFormulaTokens(const Formula: TFormulaRecord; const ShrFmlas: TShrFmlaRecordList);
    function GetFormula(Row, Col: integer): widestring;
    procedure SetFormula(Row, Col: integer; const Value: widestring);
    {$INCLUDE TCellListHdr.inc}
  public
    constructor Create(const aGlobals: TWorkbookGlobals; const aRowRecordList: TRowRecordList; const aColInfoList: TColInfoList);
    property Value[Row,Col:integer]:TXlsCellValue  read GetValue write SetValue;
    property Formula[Row,Col: integer]: widestring read GetFormula write SetFormula;
    function ArrayFormula(const Row, Col: integer): PArrayOfByte;
    function TableFormula(const Row, Col: integer): PArrayOfByte;
    procedure FixFormulas(const ShrFmlas: TShrFmlaRecordList);

    function GetSheetName(const SheetNumber: integer): widestring;
  end;

  TCells = class
  private
    FRowList: TRowRecordList;
    FCellList: TCellList;
    procedure WriteDimensions(const DataStream: TStream; const CellRange: TXlsCellRange);
    function DimensionsSize: integer;
    procedure CalcUsedRange(var CellRange: TXlsCellRange);

  public
    constructor Create(const aGlobals: TWorkbookGlobals; const aColInfoList: TColInfoList);
    destructor Destroy; override;

    procedure Clear;
    procedure CopyFrom(const aList: TCells);

    procedure SaveToStream(const DataStream: TStream);
    procedure SaveRangeToStream(const DataStream: TStream; const CellRange: TXlsCellRange);
    function TotalSize: int64;
    function TotalRangeSize(const CellRange: TXlsCellRange): int64;

    procedure InsertAndCopyRows(const FirstRow, LastRow, DestRow, aCount: integer; const SheetInfo: TSheetInfo; const OnlyFormulas: boolean);
    procedure DeleteRows(const aRow, aCount: word; const SheetInfo: TSheetInfo);
    procedure ArrangeInsert(const InsPos, InsCount: integer; const SheetInfo: TSheetInfo);

    procedure AddRow(const aRecord: TRowRecord);
    procedure AddCell(const aRecord: TCellRecord;  const aRow: integer);
    procedure AddMultipleCells(const aRecord: TMultipleValueRecord);

    property CellList: TCellList read FCellList;
    property RowList: TRowRecordList read FRowList;
  end;


  TRangeList = class(TBaseList) //records are TRangeEntry
    {$INCLUDE TRangeListHdr.inc}
    procedure CopyFrom(const aRangeList: TRangeList);

    procedure SaveToStream(const DataStream: TStream);
    procedure SaveRangeToStream(const DataStream: TStream; const CellRange: TXlsCellRange);
    function TotalSize: int64;
    function TotalRangeSize(const CellRange: TXlsCellRange): int64;

    procedure InsertAndCopyRows(const FirstRow, LastRow, DestRow, aCount: integer; const SheetInfo: TSheetInfo);
    procedure DeleteRows(const aRow, aCount: word; const SheetInfo: TSheetInfo);

  end;

implementation
{$IFNDEF TMSASG}
uses UXlsFormulaParser, UXlsEncodeFormula;
{$ENDIF}

{$INCLUDE TBaseRowColListImp.inc}
{$INCLUDE TRangeListImp.inc}
{$INCLUDE TCellListImp.inc}
{ TBaseRowColList }


procedure TBaseRowColList.AddRecord(const aRecord: TBaseRowColRecord; const aRow: integer);
var
  i:integer;
begin
  for i:= Count to aRow do Add(ListClass.Create);
  Items[aRow].Add(aRecord);
end;

procedure TBaseRowColList.ArrangeInsert(const InsPos, InsCount: integer; const SheetInfo: TSheetInfo);
var
  i:integer;
begin
  for i:=0 to Count-1 do Items[i].ArrangeInsert(InsPos, InsCount, SheetInfo);
end;

procedure TBaseRowColList.CopyFrom(const aList: TBaseRowColList);
var
  i: integer;
  Tr: TBaseRowColRecordList;
begin
  for i:=0 to aList.Count - 1 do
  begin
    Tr:= ListClass.Create;
    Tr.CopyFrom(aList[i]);
    Add(Tr);
  end;
end;

constructor TBaseRowColList.Create(const aListClass: TListClass);
begin
  inherited Create(true);
  ListClass:=aListClass;
end;

procedure TBaseRowColList.DeleteRows(const aRow, aCount: word; const SheetInfo: TSheetInfo);
var
  i, Max: integer;
begin
  Max:=aRow+aCount ; if Max>Count then Max:= Count;
  for i:= Max-1 downto aRow do Delete(i);
  //Delete the cells. we have to look at all the formulas, not only those below arow
  ArrangeInsert(aRow, -aCount, SheetInfo);

end;

procedure TBaseRowColList.InsertAndCopyRows(const FirstRow, LastRow, DestRow,
  aCount: integer; const SheetInfo: TSheetInfo; const OnlyFormulas: boolean);
var
  i, k, z, a, CopyOffs, MyDestRow: integer;
  aRecordList: TBaseRowColRecordList;
begin
  // Insert the cells. we have to look at all the formulas, not only those below destrow
  ArrangeInsert(DestRow, aCount*(LastRow-FirstRow+1), SheetInfo);

  //Copy the cells
  MyDestRow:=DestRow;
  CopyOffs:=0;
  for k:=1 to aCount do
    for i:=FirstRow to LastRow do
    begin
      aRecordList:= ListClass.Create;
      try
        if i+CopyOffs<Count then
        begin
          if OnlyFormulas then
          begin
            for a:=0 to Items[i+CopyOffs].Count-1 do
              if (Items[i+CopyOffs][a] is TFormulaRecord) then
                aRecordList.Add(Items[i+CopyOffs][a].CopyTo as TBaseRowColRecord);
          end else aRecordList.CopyFrom(Items[i+CopyOffs]);

          aRecordList.ArrangeCopyRows(MyDestRow);
        end;
        for z:= Count to MyDestRow-1 do Add(ListClass.Create);
        Insert(MyDestRow, aRecordList);
        aRecordList:=nil;
      finally
        FreeAndNil(aRecordList);
      end; //finally
      Inc(MyDestRow);
      if FirstRow>=DestRow then Inc(CopyOffs);
    end;

end;

procedure TBaseRowColList.SaveRangeToStream(const DataStream: TStream; const CellRange: TXlsCellRange);
var
  i:integer;
begin
  for i:=0 to Count-1 do Items[i].SaveRangeToStream(DataStream, CellRange);
end;

procedure TBaseRowColList.SaveToStream(const DataStream: TStream);
var
  i:integer;
begin
  for i:=0 to Count-1 do Items[i].SaveToStream(DataStream);
end;

function TBaseRowColList.TotalRangeSize(const CellRange: TXlsCellRange): int64;
var
  i: integer;
begin
  Result:=0;
  for i:=CellRange.Top to CellRange.Bottom do Result:=Result+Items[i].TotalRangeSize(CellRange);
end;

function TBaseRowColList.TotalSize: int64;
var
  i:integer;
begin
  Result:=0;
  for i:=0 to Count-1 do Result:=Result+Items[i].TotalSize;
end;

{ TCellList }

constructor TCellList.Create(const aGlobals: TWorkbookGlobals; const aRowRecordList: TRowRecordList; const aColInfoList: TColInfoList);
begin
  inherited Create(TCellRecordList);
  FGlobals:= aGlobals;
  FRowRecordList:=aRowRecordList;
  FColInfoList:=aColInfoList;
end;

function TCellList.GetValue(Row, Col: integer): TXlsCellValue;
var
  Index: integer;
begin
  if (Row<0) or (Row>Max_Rows) then raise Exception.CreateFmt(ErrInvalidRow,[Row]);
  if (Col>Max_Columns)or (Col<0) then raise Exception.CreateFmt(ErrInvalidCol,[Col]);
  if Row>=Count then begin; Result.Value:=Unassigned; Result.XF:=-1; Result.IsFormula:=false; exit; end;
  if Items[Row].Find(Col,Index) then
  begin
    Result.Value:=Items[Row][Index].Value;
    Result.XF:=Items[Row][Index].XF;
    Result.IsFormula:=Items[Row][Index] is TFormulaRecord;
  end else
  begin
    Result.Value:=Unassigned;
    Result.XF:=-1;
    Result.IsFormula:=false;
  end;
end;

procedure TCellList.SetValue(Row, Col: integer; const Value: TXlsCellValue);
var
  Index, k: integer;
  XF, DefaultXF: integer;
  Found: boolean;
  Cell: TCellRecord;
  ValueType: integer;
begin
  if (Row<0) or (Row>Max_Rows) then raise Exception.CreateFmt(ErrInvalidRow,[Row]);
  if (Col>Max_Columns)or (Col<0) then raise Exception.CreateFmt(ErrInvalidCol,[Col]);

  FRowRecordList.AddRow(Row);

  if FRowRecordList[Row].IsFormatted then DefaultXF:=FRowRecordList[Row].XF
  else if FColInfoList.Find(Col, Index) then DefaultXF:=FColInfoList[Index].XF
  else DefaultXF:=15;

  Cell:=nil;
  Found:=(Row<Count) and Items[Row].Find(Col,Index);
  XF:=DefaultXF;
  if Found then XF:=Items[Row][Index].XF;
  if Value.XF>=0 then XF:=Value.XF;


  ValueType:= VarType(Value.Value);

  {$IFDEF ConditionalExpressions}{$if CompilerVersion >= 14}
  //Check for Custom Variants
  if (ValueType>=$010F) and (ValueType<=$0FFF) then
  begin
    ValueType:=VarDouble; //should be VarType(OleVariant(Value.Value)), but this converts numbers to strings
  end;
  {$IFEND}{$ENDIF} //Delphi 6 or above

  case ValueType of
    varEmpty,
    varNull      : if (XF<>DefaultXF) then Cell:= TBlankRecord.CreateFromData(Row,Col,XF);

    varByte,
    varSmallint,
    varInteger,
    varSingle,
    varDouble,
    {$IFDEF ConditionalExpressions}{$if CompilerVersion >= 14}
      varShortInt, VarWord, VarLongWord, varInt64,
    {$IFEND}{$ENDIF} //Delphi 6 or above
    varCurrency : if IsRK(Value.Value) then Cell:= TRKRecord.CreateFromData(Row,Col,XF)
                                 else Cell:= TNumberRecord.CreateFromData(Row,Col,XF);

    varDate     : Cell:= TLabelSSTRecord.CreateFromData(Row,Col,XF,FGlobals.SST);

    varOleStr,
    varStrArg,
    varString   : if (Value.Value='') then
                  begin
                    if (XF<>DefaultXF) then Cell:= TBlankRecord.CreateFromData(Row,Col,XF);
                  end
                  else Cell:= TLabelSSTRecord.CreateFromData(Row,Col,XF,FGlobals.SST);

    varBoolean	: Cell:= TBoolErrRecord.CreateFromData(Row,Col,XF);
  end; //case

  if Found then Items[Row].Delete(Index);


  if Found and (Cell=nil) then  //We are deleting a cell
  begin
    if (Row>=Count) or (Items[Row]=nil)or(Items[Row].Count=0)then //Row emptied
      if (not FRowRecordList[Row].IsModified)  then     //Row always exists... it is added at the top
        FRowRecordList[Row]:=nil  //this frees the object
      else
      begin
        FRowRecordList[Row].MinCol:= 0;
        FRowRecordList[Row].MaxCol:= 0;
      end
    else
    begin
      FRowRecordList[Row].MinCol:= Items[Row][0].Column;
      FRowRecordList[Row].MaxCol:= Items[Row][Items[Row].Count-1].Column+1;
    end;
  end;

  //Remove all empty Rows at the end.
  k:=FRowRecordList.Count-1;
  while ((k>Row) or (Cell=nil)) and
        (k>=0) and (not FRowRecordList.HasRow(k) or (not FRowRecordList[k].IsModified)) and
        ((k>=Count) or (Items[k]=nil) or (Items[k].Count=0)) do
  begin
    FRowRecordList.Delete(k);
    if k<Count then Delete(k);
    dec(k);
  end;

  if Cell=nil then exit;

  if Col+1> FRowRecordList[Row].MaxCol then FRowRecordList[Row].MaxCol:=Col+1;
  if Col< FRowRecordList[Row].MinCol then FRowRecordList[Row].MinCol:=Col;
  Cell.Value:=Value.Value;
  if Row>=Count then AddRecord(Cell, Row) else Items[Row].Insert(Index, Cell);
end;

procedure TCellList.FixFormulaTokens(const Formula: TFormulaRecord; const ShrFmlas: TShrFmlaRecordList);
var
  Key: Cardinal;
  Index: integer;
begin
  if not Formula.IsExp(Key) then exit;
  if ShrFmlas.Find(Key, Index) then
    Formula.MixShared(ShrFmlas[Index].Data, ShrFmlas[Index].DataSize)
  else //Array formula
  begin
    //nothing, it's ok
    //raise Exception.Create(ErrShrFmlaNotFound);
  end;
end;

procedure TCellList.FixFormulas(const ShrFmlas: TShrFmlaRecordList);
var
  i, k: integer;

⌨️ 快捷键说明

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