fpspreadsheet: Rearrange units to better avoid circular unit references. General idea: no unit of the package must "use" fpspreadsheet.pas in the interface section.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6444 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-05-22 22:21:15 +00:00
parent 3c79851a8c
commit d5e5df7485
21 changed files with 2276 additions and 1831 deletions

View File

@ -6,7 +6,7 @@ unit fpsCell;
interface
uses
Classes, SysUtils, fpstypes, fpspreadsheet;
Classes, SysUtils, fpstypes;
type
TCellHelper = record helper for TCell
@ -46,8 +46,7 @@ type
procedure SetWordwrap(const AValue: Boolean);
protected
function GetWorkbook: TsWorkbook; inline;
function GetWorksheet: TsWorksheet; inline;
function GetWorkbook: TsBasicWorkbook; inline;
public
property BackgroundColor: TsColor
@ -83,74 +82,77 @@ type
read GetVertAlignment write SetVertAlignment;
property Wordwrap: Boolean
read GetWordwrap write SetWordwrap;
property Workbook: TsWorkbook read GetWorkbook;
property Workbook: TsBasicWorkbook read GetWorkbook;
end;
implementation
uses
fpspreadsheet;
function TCellHelper.GetBackgroundColor: TsColor;
begin
Result := GetWorksheet.ReadBackgroundColor(@self);
Result := (Worksheet as TsWorksheet).ReadBackgroundColor(@self);
end;
function TCellHelper.GetBiDiMode: TsBiDiMode;
begin
Result := GetWorksheet.ReadBiDiMode(@self);
Result := (Worksheet as TsWorksheet).ReadBiDiMode(@self);
end;
function TCellHelper.GetBorder: TsCellBorders;
begin
Result := GetWorksheet.ReadCellBorders(@self);
Result := (Worksheet as TsWorksheet).ReadCellBorders(@self);
end;
function TCellHelper.GetBorderStyle(const ABorder: TsCellBorder): TsCellBorderStyle;
begin
Result := GetWorksheet.ReadCellBorderStyle(@self, ABorder);
Result := (Worksheet as TsWorksheet).ReadCellBorderStyle(@self, ABorder);
end;
function TCellHelper.GetBorderStyles: TsCellBorderStyles;
begin
Result := GetWorksheet.ReadCellBorderStyles(@self);
Result := (Worksheet as TsWorksheet).ReadCellBorderStyles(@self);
end;
function TCellHelper.GetCellFormat: TsCellFormat;
begin
Result := GetWorkbook.GetCellFormat(FormatIndex);
Result := (GetWorkbook as TsWorkbook).GetCellFormat(FormatIndex);
end;
function TCellHelper.GetComment: String;
begin
Result := GetWorksheet.ReadComment(@self);
Result := (Worksheet as TsWorksheet).ReadComment(@self);
end;
function TCellHelper.GetFont: TsFont;
begin
Result := GetWorksheet.ReadCellFont(@self);
Result := (Worksheet as TsWorksheet).ReadCellFont(@self);
end;
function TCellHelper.GetFontIndex: Integer;
var
fmt: PsCellFormat;
begin
fmt := Workbook.GetPointerToCellFormat(FormatIndex);
fmt := (Workbook as TsWorkbook).GetPointerToCellFormat(FormatIndex);
Result := fmt^.FontIndex;
end;
function TCellHelper.GetHorAlignment: TsHorAlignment;
begin
Result := GetWorksheet.ReadHorAlignment(@Self);
Result := (Worksheet as TsWorksheet).ReadHorAlignment(@Self);
end;
function TCellHelper.GetHyperlink: TsHyperlink;
begin
Result := GetWorksheet.ReadHyperlink(@self);
Result := (Worksheet as TsWorksheet).ReadHyperlink(@self);
end;
function TCellHelper.GetNumberFormat: TsNumberFormat;
var
fmt: PsCellFormat;
begin
fmt := Workbook.GetPointerToCellFormat(FormatIndex);
fmt := (Workbook as TsWorkbook).GetPointerToCellFormat(FormatIndex);
Result := fmt^.NumberFormat;
end;
@ -158,127 +160,122 @@ function TCellHelper.GetNumberFormatStr: String;
var
fmt: PsCellFormat;
begin
fmt := Workbook.GetPointerToCellFormat(FormatIndex);
fmt := (Workbook as TsWorkbook).GetPointerToCellFormat(FormatIndex);
Result := fmt^.NumberFormatStr;
end;
function TCellHelper.GetTextRotation: TsTextRotation;
begin
Result := GetWorksheet.ReadTextRotation(@Self);
Result := (Worksheet as TsWorksheet).ReadTextRotation(@Self);
end;
function TCellHelper.GetUsedFormattingFields: TsUsedFormattingFields;
begin
Result := GetWorksheet.ReadUsedFormatting(@Self);
Result := (Worksheet as TsWorksheet).ReadUsedFormatting(@Self);
end;
function TCellHelper.GetVertAlignment: TsVertAlignment;
begin
Result := GetWorksheet.ReadVertAlignment(@self);
Result := (Worksheet as TsWorksheet).ReadVertAlignment(@self);
end;
function TCellHelper.GetWordwrap: Boolean;
begin
Result := GetWorksheet.ReadWordwrap(@self);
Result := (Worksheet as TsWorksheet).ReadWordwrap(@self);
end;
function TCellHelper.GetWorkbook: TsWorkbook;
function TCellHelper.GetWorkbook: TsBasicWorkbook;
begin
Result := GetWorksheet.Workbook;
end;
function TCellHelper.GetWorksheet: TsWorksheet;
begin
Result := TsWorksheet(Worksheet);
Result := (Worksheet as TsWorksheet).Workbook;
end;
procedure TCellHelper.SetBackgroundColor(const AValue: TsColor);
begin
GetWorksheet.WriteBackgroundColor(@self, AValue);
(Worksheet as TsWorksheet).WriteBackgroundColor(@self, AValue);
end;
procedure TCellHelper.SetBiDiMode(const AValue: TsBiDiMode);
begin
GetWorksheet.WriteBiDiMode(@self, AValue);
(Worksheet as TsWorksheet).WriteBiDiMode(@self, AValue);
end;
procedure TCellHelper.SetBorder(const AValue: TsCellBorders);
begin
GetWorksheet.WriteBorders(@self, AValue);
(Worksheet as TsWorksheet).WriteBorders(@self, AValue);
end;
procedure TCellHelper.SetBorderStyle(const ABorder: TsCellBorder;
const AValue: TsCellBorderStyle);
begin
GetWorksheet.WriteBorderStyle(@self, ABorder, AValue);
(Worksheet as TsWorksheet).WriteBorderStyle(@self, ABorder, AValue);
end;
procedure TCellHelper.SetBorderStyles(const AValue: TsCellBorderStyles);
begin
GetWorksheet.WriteBorderStyles(@self, AValue);
(Worksheet as TsWorksheet).WriteBorderStyles(@self, AValue);
end;
procedure TCellHelper.SetCellFormat(const AValue: TsCellFormat);
begin
GetWorksheet.WriteCellFormat(@self, AValue);
(Worksheet as TsWorksheet).WriteCellFormat(@self, AValue);
end;
procedure TCellHelper.SetComment(const AValue: String);
begin
GetWorksheet.WriteComment(@self, AValue);
(Worksheet as TsWorksheet).WriteComment(@self, AValue);
end;
procedure TCellHelper.SetFontIndex(const AValue: Integer);
begin
GetWorksheet.WriteFont(@self, AValue);
(Worksheet as TsWorksheet).WriteFont(@self, AValue);
end;
procedure TCellHelper.SetHorAlignment(const AValue: TsHorAlignment);
begin
GetWorksheet.WriteHorAlignment(@self, AValue);
(Worksheet as TsWorksheet).WriteHorAlignment(@self, AValue);
end;
procedure TCellHelper.SetHyperlink(const AValue: TsHyperlink);
begin
GetWorksheet.WriteHyperlink(@self, AValue.Target, AValue.Tooltip);
(Worksheet as TsWorksheet).WriteHyperlink(@self, AValue.Target, AValue.Tooltip);
end;
procedure TCellHelper.SetNumberFormat(const AValue: TsNumberFormat);
var
fmt: TsCellFormat;
begin
fmt := Workbook.GetCellFormat(FormatIndex);
fmt := (Workbook as TsWorkbook).GetCellFormat(FormatIndex);
fmt.NumberFormat := AValue;
GetWorksheet.WriteCellFormat(@self, fmt);
(Worksheet as TsWorksheet).WriteCellFormat(@self, fmt);
end;
procedure TCellHelper.SetNumberFormatStr(const AValue: String);
var
fmt: TsCellFormat;
begin
fmt := Workbook.GetCellFormat(FormatIndex);
fmt := (Workbook as TsWorkbook).GetCellFormat(FormatIndex);
fmt.NumberFormatStr := AValue;
GetWorksheet.WriteCellFormat(@self, fmt);
(Worksheet as TsWorksheet).WriteCellFormat(@self, fmt);
end;
procedure TCellHelper.SetTextRotation(const AValue: TsTextRotation);
begin
GetWorksheet.WriteTextRotation(@self, AValue);
(Worksheet as TsWorksheet).WriteTextRotation(@self, AValue);
end;
procedure TCellHelper.SetUsedFormattingFields(const AValue: TsUsedFormattingFields);
begin
GetWorksheet.WriteUsedFormatting(@self, AValue);
(Worksheet as TsWorksheet).WriteUsedFormatting(@self, AValue);
end;
procedure TCellHelper.SetVertAlignment(const AValue: TsVertAlignment);
begin
GetWorksheet.WriteVertAlignment(@self, AValue);
(Worksheet as TsWorksheet).WriteVertAlignment(@self, AValue);
end;
procedure TCellHelper.SetWordwrap(const AValue: Boolean);
begin
GetWorksheet.WriteWordwrap(@self, AValue);
(Worksheet as TsWorksheet).WriteWordwrap(@self, AValue);
end;

View File

@ -76,12 +76,12 @@ type
TsCells = class(TsRowColAVLTree)
private
FWorksheet: Pointer; // Must be cast to TsWorksheet
FWorksheet: TsBasicWorksheet; // Must be cast to TsWorksheet
protected
procedure DisposeData(var AData: Pointer); override;
function NewData: Pointer; override;
public
constructor Create(AWorksheet: Pointer; AOwnsData: Boolean = true);
constructor Create(AWorksheet: TsBasicWorksheet; AOwnsData: Boolean = true);
function AddCell(ARow, ACol: Cardinal): PCell;
procedure DeleteCell(ARow, ACol: Cardinal);
function FindCell(ARow, ACol: Cardinal): PCell;
@ -689,7 +689,8 @@ end;
{ TsCells: an AVLTree to store spreadsheet cells }
{==============================================================================}
constructor TsCells.Create(AWorksheet: Pointer; AOwnsData: Boolean = true);
constructor TsCells.Create(AWorksheet: TsBasicWorksheet;
AOwnsData: Boolean = true);
begin
inherited Create(AOwnsData);
FWorksheet := AWorksheet;

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils,
fpstypes, fpspreadsheet, fpsReaderWriter, fpsCsvDocument;
fpstypes, fpsReaderWriter, fpsCsvDocument;
type
TsCSVReader = class(TsCustomSpreadReader)
@ -21,7 +21,7 @@ type
procedure ReadLabel(AStream: TStream); override;
procedure ReadNumber(AStream: TStream); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
procedure ReadFromFile(AFileName: String; APassword: String = '';
AParams: TsStreamParams = []); override;
procedure ReadFromStream(AStream: TStream; APassword: String = '';
@ -48,10 +48,10 @@ type
const AValue: string; ACell: PCell); override;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: double; ACell: PCell); override;
procedure WriteSheet(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteSheet(AStream: TStream; AWorksheet: TsBasicWorksheet);
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
procedure WriteToStream(AStream: TStream; AParams: TsStreamParams = []); override;
procedure WriteToStrings(AStrings: TStrings; AParams: TsStreamParams = []); override;
end;
@ -95,7 +95,7 @@ implementation
uses
DateUtils, LConvEncoding, Math,
fpsUtils, fpsNumFormat;
fpsUtils, fpspreadsheet, fpsNumFormat;
const
DEFAULT_ENCODING = 'utf8'; //'utf8bom';
@ -115,7 +115,7 @@ end;
{ TsCSVReader }
{------------------------------------------------------------------------------}
constructor TsCSVReader.Create(AWorkbook: TsWorkbook);
constructor TsCSVReader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
FWorksheetName := 'Sheet1'; // will be replaced by filename
@ -148,29 +148,32 @@ procedure TsCSVReader.ReadCellValue(ARow, ACol: Cardinal; AText: String);
var
cell: PCell;
boolValue: Boolean;
sheet: TsWorksheet;
begin
// Empty strings are blank cells -- nothing to do
if AText = '' then
exit;
cell := FWorksheet.AddCell(ARow, ACol);
sheet := FWorksheet as TsWorksheet;
cell := sheet.AddCell(ARow, ACol);
// Do not try to interpret the strings. --> everything is a LABEL cell.
if not CSVParams.DetectContentType then
begin
FWorksheet.WriteText(cell, AText);
sheet.WriteText(cell, AText);
exit;
end;
// Check for a BOOLEAN cell
if IsBoolValue(AText, CSVParams.TrueText, CSVParams.FalseText, boolValue) then
begin
FWorksheet.WriteBoolValue(cell, boolValue);
sheet.WriteBoolValue(cell, boolValue);
exit;
end;
// All other cases are handled by WriteCellValusAsString
FWorksheet.WriteCellValueAsString(cell, AText, FFormatSettings);
sheet.WriteCellValueAsString(cell, AText, FFormatSettings);
end;
procedure TsCSVReader.ReadFormula(AStream: TStream);
@ -205,7 +208,7 @@ begin
encoding := DEFAULT_ENCODING;
// Create worksheet
FWorksheet := FWorkbook.AddWorksheet(FWorksheetName, true);
FWorksheet := (FWorkbook as TsWorkbook).AddWorksheet(FWorksheetName, true);
// Create csv parser, read file and store in worksheet
Parser := TCSVParser.Create;
@ -255,7 +258,7 @@ end;
{ TsCSVWriter }
{------------------------------------------------------------------------------}
constructor TsCSVWriter.Create(AWorkbook: TsWorkbook);
constructor TsCSVWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
FFormatSettings := CSVParams.FormatSettings;
@ -298,7 +301,7 @@ var
begin
Unused(AStream);
Unused(ARow, ACol, AValue);
s := FWorksheet.ReadAsText(ACell);
s := (FWorksheet as TsWorksheet).ReadAsText(ACell);
s := ConvertEncoding(s, EncodingUTF8, FEncoding);
FCSVBuilder.AppendCell(s);
end;
@ -349,20 +352,22 @@ begin
if CSVParams.NumberFormat <> '' then
s := Format(CSVParams.NumberFormat, [AValue], FFormatSettings)
else
s := FWorksheet.ReadAsText(ACell, FFormatSettings);
s := (FWorksheet as TsWorksheet).ReadAsText(ACell, FFormatSettings);
s := ConvertEncoding(s, EncodingUTF8, FEncoding);
FCSVBuilder.AppendCell(s);
end;
procedure TsCSVWriter.WriteSheet(AStream: TStream; AWorksheet: TsWorksheet);
procedure TsCSVWriter.WriteSheet(AStream: TStream; AWorksheet: TsBasicWorksheet);
var
r, c: Cardinal;
firstRow, lastRow: Cardinal;
firstCol, lastCol: Cardinal;
cell: PCell;
n: Integer;
sheet: TsWorksheet;
begin
FWorksheet := AWorksheet;
sheet := FWorksheet as TsWorksheet;
FCSVBuilder := TCSVBuilder.Create;
try
@ -371,29 +376,29 @@ begin
FCSVBuilder.QuoteChar := CSVParams.QuoteChar;
FCSVBuilder.SetOutput(AStream);
n := FWorksheet.GetCellCount;
n := sheet.GetCellCount;
if FClipboardMode and (n = 1) then
begin
cell := FWorksheet.Cells.GetFirstCell;
cell := sheet.Cells.GetFirstCell;
WriteCellToStream(AStream, cell);
end else
begin
if FClipboardMode then
begin
firstRow := FWorksheet.GetFirstRowIndex;
firstCol := FWorksheet.GetFirstColIndex;
firstRow := sheet.GetFirstRowIndex;
firstCol := sheet.GetFirstColIndex;
end else
begin
firstRow := 0;
firstCol := 0;
end;
lastRow := FWorksheet.GetLastOccupiedRowIndex;
lastCol := FWorksheet.GetLastOccupiedColIndex;
lastRow := sheet.GetLastOccupiedRowIndex;
lastCol := sheet.GetLastOccupiedColIndex;
for r := firstRow to lastRow do
begin
for c := firstCol to lastCol do
begin
cell := FWorksheet.FindCell(r, c);
cell := sheet.FindCell(r, c);
if cell = nil then
FCSVBuilder.AppendCell('')
else
@ -411,12 +416,15 @@ procedure TsCSVWriter.WriteToStream(AStream: TStream;
AParams: TsStreamParams = []);
var
n: Integer;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
FClipboardMode := (spClipboard in AParams);
if (CSVParams.SheetIndex >= 0) and (CSVParams.SheetIndex < FWorkbook.GetWorksheetCount)
if (CSVParams.SheetIndex >= 0) and (CSVParams.SheetIndex < book.GetWorksheetCount)
then n := CSVParams.SheetIndex
else n := 0;
WriteSheet(AStream, FWorkbook.GetWorksheetByIndex(n));
WriteSheet(AStream, book.GetWorksheetByIndex(n));
end;
procedure TsCSVWriter.WriteToStrings(AStrings: TStrings;

View File

@ -51,7 +51,7 @@ unit fpsExprParser;
interface
uses
Classes, SysUtils, contnrs, fpstypes, fpspreadsheet, fpsrpn;
Classes, SysUtils, contnrs, fpstypes, fpsrpn;
type
{ Tokens }
@ -86,7 +86,7 @@ type
TsResultTypes = set of TsResultType;
TsExpressionResult = record
Worksheet : TsWorksheet; // Worksheet containing the calculated cell
Worksheet : TsBasicWorksheet; // Worksheet containing the calculated cell
ResString : String;
case ResultType : TsResultType of
rtEmpty : ();
@ -586,7 +586,7 @@ type
{ TsCellExprNode }
TsCellExprNode = class(TsExprNode)
private
FWorksheet: TsWorksheet;
FWorksheet: TsBasicWorksheet;
FRow, FCol: Cardinal;
FFlags: TsRelFlags;
FCell: PCell;
@ -595,20 +595,20 @@ type
protected
function GetCol: Cardinal;
function GetRow: Cardinal;
function GetSheet: TsWorksheet;
function GetSheet: TsBasicWorksheet;
function GetSheetIndex: Integer;
function GetSheetName: String;
function GetWorkbook: TsWorkbook;
function GetWorkbook: TsBasicWorkbook;
procedure GetNodeValue(out AResult: TsExpressionResult); override;
public
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
constructor Create(AParser: TsExpressionParser; AWorksheet: TsBasicWorksheet;
ASheetName: String; ARow, ACol: Cardinal; AFlags: TsRelFlags);
function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: string; override;
procedure Check; override;
function Has3DLink: Boolean; override;
function NodeType: TsResultType; override;
property Worksheet: TsWorksheet read FWorksheet;
property Worksheet: TsBasicWorksheet read FWorksheet;
end;
{ TsCellRangeExprNode }
@ -616,7 +616,7 @@ type
TsCellRangeExprNode = class(TsExprNode)
private
FWorksheet: TsWorksheet;
FWorksheet: TsBasicWorksheet;
FRow: array[TsCellRangeIndex] of Cardinal;
FCol: array[TsCellRangeIndex] of Cardinal;
FSheetIndex: array[TsCellRangeIndex] of Integer;
@ -626,17 +626,17 @@ type
function GetCol(AIndex: TsCellRangeIndex): Cardinal;
function GetRow(AIndex: TsCellRangeIndex): Cardinal;
procedure GetNodeValue(out Result: TsExpressionResult); override;
function GetWorkbook: TsWorkbook;
function GetWorkbook: TsBasicWorkbook;
public
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
constructor Create(AParser: TsExpressionParser; AWorksheet: TsBasicWorksheet;
ASheet1, ASheet2: String; ARange: TsCellRange; AFlags: TsRelFlags);
function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override;
procedure Check; override;
function Has3DLink: Boolean; override;
function NodeType: TsResultType; override;
property Workbook: TsWorkbook read GetWorkbook;
property Worksheet: TsWorksheet read FWorksheet;
property Workbook: TsBasicWorkbook read GetWorkbook;
property Worksheet: TsBasicWorksheet read FWorksheet;
end;
{ TsExpressionScanner }
@ -700,7 +700,7 @@ type
FIdentifiers: TsExprIdentifierDefs;
FHashList: TFPHashObjectlist;
FDirty: Boolean;
FWorksheet: TsWorksheet;
FWorksheet: TsBasicWorksheet;
FDialect: TsFormulaDialect;
FSourceCell: PCell;
FDestCell: PCell;
@ -748,7 +748,7 @@ type
property Dirty: Boolean read FDirty;
public
constructor Create(AWorksheet: TsWorksheet); virtual;
constructor Create(AWorksheet: TsBasicWorksheet); virtual;
destructor Destroy; override;
function IdentifierByName(AName: ShortString): TsExprIdentifierDef; virtual;
procedure Clear;
@ -771,7 +771,7 @@ type
property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula;
property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers;
property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns;
property Worksheet: TsWorksheet read FWorksheet;
property Worksheet: TsBasicWorksheet read FWorksheet;
property Dialect: TsFormulaDialect read FDialect write SetDialect;
property Contains3DRef: boolean read FContains3DRef;
@ -779,7 +779,7 @@ type
TsSpreadsheetParser = class(TsExpressionParser)
public
constructor Create(AWorksheet: TsWorksheet); override;
constructor Create(AWorksheet: TsBasicWorksheet); override;
end;
@ -865,7 +865,8 @@ const
implementation
uses
typinfo, math, lazutf8, dateutils, fpsutils, fpsfunc, fpsStrings;
typinfo, math, lazutf8, dateutils,
fpsutils, fpsfunc, fpsStrings, fpspreadsheet;
const
cNull = #0;
@ -1372,7 +1373,7 @@ end;
{ TsExpressionParser }
{------------------------------------------------------------------------------}
constructor TsExpressionParser.Create(AWorksheet: TsWorksheet);
constructor TsExpressionParser.Create(AWorksheet: TsBasicWorksheet);
begin
inherited Create;
FDialect := fdExcelA1;
@ -2038,7 +2039,7 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
else
begin
flags := AFormula[AIndex].RelFlags;
sn := FWorksheet.Workbook.GetWorksheetByIndex(idx).Name;
sn := (FWorksheet as TsWorksheet).Workbook.GetWorksheetByIndex(idx).Name;
ANode := TsCellExprNode.Create(Self, FWorksheet, sn, r, c, flags);
end;
dec(AIndex);
@ -2053,9 +2054,9 @@ procedure TsExpressionParser.SetRPNFormula(const AFormula: TsRPNFormula);
if fek = fekCellRange then
ANode := TsCellRangeExprNode.Create(self, FWorksheet, '', '', rng, flags)
else begin
sn := FWorksheet.Workbook.GetWorksheetByIndex(AFormula[AIndex].Sheet).Name;
sn := (FWorksheet as TsWorksheet).Workbook.GetWorksheetByIndex(AFormula[AIndex].Sheet).Name;
if AFormula[AIndex].Sheet2 <> -1 then
sn2 := FWorksheet.Workbook.GetWorksheetByIndex(AFormula[AIndex].Sheet2).Name
sn2 := (FWorksheet as TsWorksheet).Workbook.GetWorksheetByIndex(AFormula[AIndex].Sheet2).Name
else
sn2 := '';
ANode := TsCellRangeExprNode.Create(self, FWorksheet, sn,sn2, rng, flags);
@ -2185,7 +2186,7 @@ end;
{ TsSpreadsheetParser }
{------------------------------------------------------------------------------}
constructor TsSpreadsheetParser.Create(AWorksheet: TsWorksheet);
constructor TsSpreadsheetParser.Create(AWorksheet: TsBasicWorksheet);
begin
inherited Create(AWorksheet);
BuiltIns := AllBuiltIns;
@ -3763,7 +3764,7 @@ end;
{ TsCellExprNode }
constructor TsCellExprNode.Create(AParser: TsExpressionParser;
AWorksheet: TsWorksheet; ASheetName: String; ARow, ACol: Cardinal;
AWorksheet: TsBasicWorksheet; ASheetName: String; ARow, ACol: Cardinal;
AFlags: TsRelFlags);
begin
FParser := AParser;
@ -3772,7 +3773,7 @@ begin
FRow := ARow;
FCol := ACol;
FFlags := AFlags;
FCell := GetSheet.FindCell(FRow, FCol);
FCell := (GetSheet as TsWorksheet).FindCell(FRow, FCol);
if Has3DLink then FParser.FContains3DRef := true;
end;
@ -3847,14 +3848,14 @@ var
cell: PCell;
begin
if Parser.CopyMode then
cell := FWorksheet.FindCell(GetRow, GetCol)
cell := (FWorksheet as TsWorksheet).FindCell(GetRow, GetCol)
else
cell := FCell;
if (cell <> nil) and HasFormula(cell) then
case FWorksheet.GetCalcState(cell) of
case (FWorksheet as TsWorksheet).GetCalcState(cell) of
csNotCalculated:
FWorksheet.CalcFormula(cell);
(FWorksheet as TsWorksheet).CalcFormula(cell);
csCalculating:
raise ECalcEngine.CreateFmt(rsCircularReference, [GetCellString(cell^.Row, cell^.Col)]);
end;
@ -3873,20 +3874,23 @@ begin
Result := FRow - FParser.FSourceCell^.Row + FParser.FDestCell^.Row;
end;
function TsCellExprNode.GetSheet: TsWorksheet;
function TsCellExprNode.GetSheet: TsBasicWorksheet;
begin
if FSheetName = '' then
Result := FWorksheet
else
Result := GetWorkbook.GetWorksheetByName(FSheetName);
Result := (GetWorkbook as TsWorkbook).GetWorksheetByName(FSheetName);
end;
function TsCellExprNode.GetSheetIndex: Integer;
var
book: TsWorkbook;
begin
book := GetWorkbook as TsWorkbook;
if FSheetName = '' then
Result := GetWorkbook.GetWorksheetIndex(FWorksheet)
Result := book.GetWorksheetIndex(FWorksheet)
else
Result := GetWorkbook.GetWorksheetIndex(FSheetName);
Result := book.GetWorksheetIndex(FSheetName);
end;
function TsCellExprNode.GetSheetName: String;
@ -3897,9 +3901,9 @@ begin
Result := FSheetName;
end;
function TsCellExprNode.GetWorkbook: TsWorkbook;
function TsCellExprNode.GetWorkbook: TsBasicWorkbook;
begin
Result := FWorksheet.Workbook;
Result := (FWorksheet as TsWorksheet).Workbook;
end;
function TsCellExprNode.Has3DLink: Boolean;
@ -3917,8 +3921,10 @@ end;
{ TsCellRangeExprNode }
constructor TsCellRangeExprNode.Create(AParser: TsExpressionParser;
AWorksheet: TsWorksheet; ASheet1, ASheet2: String; ARange: TsCellRange;
AWorksheet: TsBasicWorksheet; ASheet1, ASheet2: String; ARange: TsCellRange;
AFlags: TsRelFlags);
var
book: TsWorkbook;
begin
if (ASheet1 = '') and (ASheet2 <> '') then
raise Exception.Create('Invalid parameters in cell range');
@ -3926,13 +3932,14 @@ begin
FParser := AParser;
FWorksheet := AWorksheet;
FFlags := [];
book := TsWorkbook(GetWorkbook);
F3dRange := ((ASheet1 <> '') and (ASheet2 <> '') { and (ASheet1 <> ASheet2)}) or
((ASheet1 <> '') and (ASheet2 = ''));
FSheetIndex[1] := GetWorkbook.GetWorksheetIndex(ASheet1);
FSheetIndex[1] := book.GetWorksheetIndex(ASheet1);
if ASheet2 <> '' then
FSheetIndex[2] := GetWorkbook.GetWorksheetIndex(ASheet2)
FSheetIndex[2] := book.GetWorksheetIndex(ASheet2)
else
FSheetIndex[2] := FSheetIndex[1];
EnsureOrder(FSheetIndex[1], FSheetIndex[2]);
@ -3997,11 +4004,11 @@ begin
if FSheetIndex[1] = -1 then
s1 := FWorksheet.Name
else
s1 := Workbook.GetWorksheetByIndex(FSheetIndex[1]).Name;
s1 := (Workbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex[1]).Name;
if FSheetIndex[2] = -1 then
s2 := FWorksheet.Name
else
s2 := Workbook.GetWorksheetByIndex(FSheetIndex[2]).Name;
s2 := (Workbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex[2]).Name;
r1 := GetRow(1);
c1 := GetCol(1);
r2 := GetRow(2);
@ -4068,12 +4075,12 @@ begin
end;
if not F3dRange then begin
s[1] := Workbook.GetWorksheetIndex(FWorksheet);
s[1] := (Workbook as TsWorkbook).GetWorksheetIndex(FWorksheet);
s[2] := s[1];
end;
for ss := s[1] to s[2] do begin
sheet := Workbook.GetWorksheetByIndex(ss);
sheet := (Workbook as TsWorkbook).GetWorksheetByIndex(ss);
for rr := r[1] to r[2] do
for cc := c[1] to c[2] do
begin
@ -4106,9 +4113,9 @@ begin
Result := FRow[AIndex] - FParser.FSourceCell^.Row + FParser.FDestCell^.Row;
end;
function TsCellRangeExprNode.GetWorkbook: TsWorkbook;
function TsCellRangeExprNode.GetWorkbook: TsBasicWorkbook;
begin
Result := FWorksheet.Workbook;
Result := (FWorksheet as TsWorksheet).Workbook;
end;
function TsCellRangeExprNode.Has3DLink: Boolean;
@ -4144,7 +4151,7 @@ end;
function ArgToCell(Arg: TsExpressionResult): PCell;
begin
if Arg.ResultType = rtCell then
Result := Arg.Worksheet.FindCell(Arg.ResRow, Arg.ResCol)
Result := (Arg.Worksheet as TsWorksheet).FindCell(Arg.ResRow, Arg.ResCol)
else
Result := nil;
end;
@ -4196,14 +4203,18 @@ begin
cell := ArgToCell(Arg);
if Assigned(cell) then
case cell^.ContentType of
cctNumber : Result := cell^.NumberValue;
cctDateTime : Result := cell^.DateTimeValue;
cctBool : if cell^.BoolValue then result := 1.0;
cctUTF8String: begin
fs := Arg.Worksheet.Workbook.FormatSettings;
s := cell^.UTF8StringValue;
TryStrToFloat(s, result, fs);
end;
cctNumber:
Result := cell^.NumberValue;
cctDateTime:
Result := cell^.DateTimeValue;
cctBool:
if cell^.BoolValue then result := 1.0;
cctUTF8String:
begin
fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings;
s := cell^.UTF8StringValue;
TryStrToFloat(s, result, fs);
end;
end;
end;
end;
@ -4222,7 +4233,7 @@ begin
rtBoolean : if Arg.ResBoolean then Result := 1.0;
rtString,
rtHyperlink : begin
fs := Arg.Worksheet.Workbook.FormatSettings;
fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings;
TryStrToDateTime(ArgToString(Arg), Result, fs);
end;
rtCell : begin
@ -4265,7 +4276,7 @@ begin
cctNumber : Result := Format('%g', [cell^.NumberValue]);
cctBool : if cell^.BoolValue then Result := '1' else Result := '0';
cctDateTime : begin
fs := Arg.Worksheet.Workbook.FormatSettings;
fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings;
dt := cell^.DateTimeValue;
if frac(dt) = 0.0 then
Result := FormatDateTime(fs.LongTimeFormat, dt, fs)
@ -4301,7 +4312,7 @@ begin
idx2 := arg.ResCellRange.Sheet2;
for idx := idx1 to idx2 do
begin
sheet := arg.Worksheet.Workbook.GetWorksheetByIndex(idx);
sheet := (arg.Worksheet as TsWorksheet).Workbook.GetWorksheetByIndex(idx);
for r := arg.ResCellRange.Row1 to arg.ResCellRange.Row2 do
for c := arg.ResCellRange.Col1 to arg.ResCellRange.Col2 do
begin
@ -4393,7 +4404,7 @@ begin
rtFloat : Result := (frac(AValue.ResFloat) = 0);
rtEmpty : Result := true;
rtCell : begin
cell := AValue.Worksheet.FindCell(AValue.ResRow, AValue.ResCol);
cell := (AValue.Worksheet as TsWorksheet).FindCell(AValue.ResRow, AValue.ResCol);
if Assigned(cell) then
case cell^.ContentType of
cctNumber:
@ -4415,7 +4426,7 @@ begin
case AValue.ResultType of
rtString: Result := true;
rtCell : begin
cell := AValue.Worksheet.FindCell(AValue.ResRow, AValue.ResCol);
cell := (AValue.Worksheet as TsWorksheet).FindCell(AValue.ResRow, AValue.ResCol);
Result := (cell <> nil) and (cell^.ContentType = cctUTF8String);
end;
end;

View File

@ -9,7 +9,7 @@ unit fpsfunc;
interface
uses
Classes, SysUtils, fpstypes, fpspreadsheet;
Classes, SysUtils, fpstypes;
procedure RegisterStdBuiltins(AManager: TComponent);
@ -18,7 +18,7 @@ implementation
uses
Math, lazutf8, StrUtils, DateUtils,
xlsconst, {%H-}fpsPatches, fpsUtils, fpsnumformat, fpsexprparser;
xlsconst, {%H-}fpsPatches, fpsUtils, fpsnumformat, fpsexprparser, fpspreadsheet;
{------------------------------------------------------------------------------}
@ -1035,7 +1035,7 @@ begin
for r := arg.ResCellRange.Row1 to arg.ResCellRange.Row2 do
for c := arg.ResCellRange.Col1 to arg.ResCellRange.Col2 do
begin
cell := arg.Worksheet.FindCell(r, c);
cell := (arg.Worksheet as TsWorksheet).FindCell(r, c);
if (cell <> nil) then
case cell^.ContentType of
cctNumber, cctDateTime, cctBool : inc(n);
@ -1076,7 +1076,7 @@ begin
rtCellRange:
for r := Args[0].ResCellRange.Row1 to Args[0].ResCellRange.Row2 do
for c := Args[0].ResCellRange.Col1 to Args[0].ResCellRange.Col2 do begin
cell := Args[0].Worksheet.FindCell(r, c);
cell := (Args[0].Worksheet as TsWorksheet).FindCell(r, c);
if cell = nil then
inc(n)
else
@ -1185,7 +1185,7 @@ begin
// Get format settings for string-to-float or -to-datetime conversion
if (Args[0].ResultType in [rtCell, rtCellRange]) then
fs := Args[0].Worksheet.FormatSettings
fs := (Args[0].Worksheet as TsWorksheet).FormatSettings
else
begin
Result := ErrorResult(errArgError);
@ -1325,8 +1325,8 @@ begin
if AFlag > 0 then
begin
if Length(Args) = 2 then
addcell := Args[0].Worksheet.FindCell(r + dr, c + dc) else
addCell := Args[2].Worksheet.FindCell(r + dr, c + dc);
addcell := (Args[0].Worksheet as TsWorksheet).FindCell(r + dr, c + dc) else
addCell := (Args[2].Worksheet as TsWorksheet).FindCell(r + dr, c + dc);
if addcell <> nil then
case addcell^.Contenttype of
cctNumber : addnumber := addcell^.NumberValue;
@ -1335,7 +1335,7 @@ begin
end;
end;
cell := Args[0].Worksheet.FindCell(r, c);
cell := (Args[0].Worksheet as TsWorksheet).FindCell(r, c);
case compareType of
ctNumber:
if cell <> nil then
@ -1610,7 +1610,7 @@ begin
begin
r1 := Args[1].ResCellRange.Row1;
c1 := Args[1].ResCellRange.Col1;
cell := Args[1].Worksheet.FindCell(r1, c1);
cell := (Args[1].Worksheet as TsWorksheet).FindCell(r1, c1);
end;
else
Result := ErrorResult(errWrongType);
@ -1652,8 +1652,8 @@ begin
end else
if stype = 'filename' then
Result := Stringresult(
ExtractFilePath(Args[1].Worksheet.Workbook.FileName) + '[' +
ExtractFileName(Args[1].Worksheet.Workbook.FileName) + ']' +
ExtractFilePath((Args[1].Worksheet as TsWorksheet).Workbook.FileName) + '[' +
ExtractFileName((Args[1].Worksheet as TsWorksheet).Workbook.FileName) + ']' +
Args[1].Worksheet.Name
)
else
@ -1710,7 +1710,7 @@ begin
Result := StringResult('v');
end else
if stype = 'width' then
Result := FloatResult(Args[1].Worksheet.GetColWidth(c1, suChars))
Result := FloatResult((Args[1].Worksheet as TsWorksheet).GetColWidth(c1, suChars))
else
Result := ErrorResult(errWrongType);
end;

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, fasthtmlparser,
fpstypes, fpspreadsheet, fpsClasses, fpsReaderWriter, fpsHTMLUtils;
fpstypes, fpsClasses, fpsReaderWriter, fpsHTMLUtils;
type
TsHTMLReader = class(TsCustomSpreadReader)
@ -55,7 +55,7 @@ type
procedure AddRichTextParam(AFont: TsFont; AHyperlinkIndex: Integer = -1);
procedure FixRichTextParams(var AParams: TsRichTextParams);
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
procedure ReadFromStream(AStream: TStream; APassword: String = '';
AParams: TsStreamParams = []); override;
@ -86,7 +86,7 @@ type
function IsHyperlinkTarget(ACell: PCell; out ABookmark: String): Boolean;
procedure WriteBody(AStream: TStream);
procedure WriteStyles(AStream: TStream);
procedure WriteWorksheet(AStream: TStream; ASheet: TsWorksheet);
procedure WriteWorksheet(AStream: TStream; ASheet: TsBasicWorksheet);
protected
procedure InternalWriteToStream(AStream: TStream);
@ -106,7 +106,7 @@ type
const AValue: double; ACell: PCell); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
procedure WriteToStream(AStream: TStream; AParams: TsStreamParams = []); override;
procedure WriteToStrings(AStrings: TStrings; AParams: TsStreamParams = []); override;
@ -143,7 +143,7 @@ implementation
uses
LConvEncoding, LazUTF8, URIParser, StrUtils, Math,
fpsUtils, fpsXMLCommon, fpsNumFormat;
fpsUtils, fpspreadsheet, fpsXMLCommon, fpsNumFormat;
const
MIN_FONTSIZE = 6;
@ -162,7 +162,7 @@ const
{ TsHTMLReader }
{==============================================================================}
constructor TsHTMLReader.Create(AWorkbook: TsWorkbook);
constructor TsHTMLReader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
FEncoding := EncodingUTF8;
@ -203,13 +203,16 @@ var
currSym: String;
warning: String;
fntIndex: Integer;
sheet: TsWorksheet;
begin
// Empty strings are blank cells -- nothing to do
if (AText = '') then
exit;
sheet := FWorksheet as TsWorksheet;
// Create cell
cell := FWorksheet.AddCell(ARow, ACol);
cell := sheet.AddCell(ARow, ACol);
// Format, rich-text formatting parameters
// Reject non-used runs; adapt font index to the workbook.
@ -223,10 +226,10 @@ begin
end else
begin
// Get cell font and use it in the cell format
fntIndex := FWorkbook.FindFont(FCellFont.FontName, FCellFont.Size,
fntIndex := (FWorkbook as TsWorkbook).FindFont(FCellFont.FontName, FCellFont.Size,
FCellFont.Style, FCellFont.Color, FCellFont.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(FCellFont.FontName, FCellFont.Size,
fntIndex := (FWorkbook as TsWorkbook).AddFont(FCellFont.FontName, FCellFont.Size,
FCellFont.Style, FCellFont.Color, FCellFont.Position);
FCurrCellFormat.FontIndex := fntIndex;
end;
@ -234,25 +237,25 @@ begin
Include(FCurrCellFormat.UsedFormattingFields, uffFont) else
Exclude(FCurrCellFormat.UsedFormattingFields, uffFont);
// Store the cell format in the workbook
cell^.FormatIndex := FWorkbook.AddCellFormat(FCurrCellFormat);
cell^.FormatIndex := (FWorkbook as TsWorkbook).AddCellFormat(FCurrCellFormat);
// Merged cells
if (FColSpan > 0) or (FRowSpan > 0) then begin
FWorksheet.MergeCells(ARow, ACol, ARow + FRowSpan, ACol + FColSpan);
sheet.MergeCells(ARow, ACol, ARow + FRowSpan, ACol + FColSpan);
FRowSpan := 0;
FColSpan := 0;
end;
// Hyperlink
if FHRef <> '' then begin
FWorksheet.WriteHyperlink(cell, FHRef);
sheet.WriteHyperlink(cell, FHRef);
FHRef := '';
end;
// Case: Do not try to interpret the strings. --> everything is a LABEL cell.
if not HTMLParams.DetectContentType then
begin
FWorksheet.WriteText(cell, AText, FCurrRichTextParams);
sheet.WriteText(cell, AText, FCurrRichTextParams);
exit;
end;
@ -261,9 +264,9 @@ begin
dblValue, nf, decs, currSym, warning) then
begin
if currSym <> '' then
FWorksheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym)
sheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym)
else
FWorksheet.WriteNumber(cell, dblValue, nf, decs);
sheet.WriteNumber(cell, dblValue, nf, decs);
if warning <> '' then
FWorkbook.AddErrorMsg('Cell %s: %s', [GetCellString(ARow, ACol), warning]);
exit;
@ -273,19 +276,19 @@ begin
// No idea how to apply the date/time formatsettings here...
if IsDateTimevalue(AText, FFormatSettings, dtValue, nf) then
begin
FWorksheet.WriteDateTime(cell, dtValue, nf);
sheet.WriteDateTime(cell, dtValue, nf);
exit;
end;
// Check for a BOOLEAN cell
if IsBoolValue(AText, HTMLParams.TrueText, HTMLParams.FalseText, boolValue) then
begin
FWorksheet.WriteBoolValue(cell, boolValue);
sheet.WriteBoolValue(cell, boolValue);
exit;
end;
// What is left is handled as a TEXT cell
FWorksheet.WriteText(cell, AText, FCurrRichTextParams);
sheet.WriteText(cell, AText, FCurrRichTextParams);
end;
{ Stores a font in the internal font list. Does not allow duplicates. }
@ -378,9 +381,9 @@ begin
for i:=0 to High(FCurrRichTextParams) do
begin
fnt := TsFont(FFontList[FCurrRichTextParams[i].FontIndex]);
fntIndex := FWorkbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := (FWorkbook as TsWorkbook).FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := (FWorkbook as TsWorkbook).AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
FCurrRichTextParams[i].FontIndex := fntIndex;
end;
end;
@ -485,6 +488,7 @@ end;
procedure TsHTMLReader.ProcessEndTags(NoCaseTag, ActualTag: String);
var
fntIndex: Integer;
sheet: TsWorksheet;
begin
Unused(ActualTag);
if not FInTable then exit;
@ -501,9 +505,11 @@ begin
if not FInCell then exit;
sheet := FWorksheet as TsWorksheet;
if (NoCaseTag = '</TD>') or (NoCaseTag = '</TH>') then
begin
while FWorksheet.IsMerged(FWorksheet.FindCell(FCurrRow, FCurrCol)) do
while sheet.IsMerged(sheet.FindCell(FCurrRow, FCurrCol)) do
inc(FCurrCol);
AddCell(FCurrRow, FCurrCol, FCellText);
FInCell := false;
@ -807,7 +813,7 @@ begin
if idx = -1 then
idx := FAttrList.IndexOfName('size');
if idx > -1 then begin
defFntSize := FWorkbook.GetDefaultFont.Size;
defFntSize := (FWorkbook as TsWorkbook).GetDefaultFont.Size;
s := FAttrList[idx].Value;
case s of
'medium', '3' : AFont.Size := defFntSize;
@ -1022,7 +1028,7 @@ procedure TsHTMLReader.InitFont(AFont: TsFont);
var
fnt: TsFont;
begin
fnt := FWorkbook.GetDefaultFont;
fnt := (FWorkbook as TsWorkbook).GetDefaultFont;
AFont.FontName := fnt.FontName;
AFont.Size := fnt.Size;
AFont.Style := fnt.Style;
@ -1056,10 +1062,10 @@ begin
try
list.LoadFromStream(AStream);
ReadFromStrings(list, AParams);
if FWorkbook.GetWorksheetCount = 0 then
if (FWorkbook as TsWorkbook).GetWorksheetCount = 0 then
begin
FWorkbook.AddErrorMsg('Requested table not found, or no tables in html file');
FWorkbook.AddWorksheet('Dummy');
TsWorkbook(FWorkbook).AddWorksheet('Dummy');
end;
finally
list.Free;
@ -1106,14 +1112,14 @@ begin
inc(FTableCounter);
if (HTMLParams.TableIndex >= 0) and (FTableCounter <> HTMLParams.TableIndex) then
exit;
FWorksheet := FWorkbook.AddWorksheet(Format('Table #%d', [FTableCounter+1]));
FWorksheet := TsWorkbook(FWorkbook).AddWorksheet(Format('Table #%d', [FTableCounter+1]));
FInTable := true;
FCurrRow := -1;
FCurrCol := -1;
FFontStack.Push(AddFont(FCurrFont));
FAttrList.Parse(ActualTag);
ReadFont(FCurrFont);
FWorkbook.ReplaceFont(DEFAULT_FONTINDEX, FCurrFont.FontName, FCurrFont.Size,
TsWorkbook(FWorkbook).ReplaceFont(DEFAULT_FONTINDEX, FCurrFont.FontName, FCurrFont.Size,
FCurrFont.Style, FCurrFont.Color, FCurrFont.Position);
FCellFont.CopyOf(FCurrFont);
exit;
@ -1179,7 +1185,7 @@ end;
{==============================================================================}
{ TsHTMLWriter }
{==============================================================================}
constructor TsHTMLWriter.Create(AWorkbook: TsWorkbook);
constructor TsHTMLWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
FPointSeparatorSettings := DefaultFormatSettings;
@ -1311,17 +1317,20 @@ var
col: PCol;
w: Single;
rLast: Cardinal;
sheet: TsWorksheet;
begin
sheet := FWorksheet as TsWorksheet;
if AColIndex < 0 then // Row header column
begin
rLast := FWorksheet.GetLastRowIndex;
w := FWorkbook.ConvertUnits(Length(IntToStr(rLast)) + 2, suChars, suPoints);
rLast := sheet.GetLastRowIndex;
w := (FWorkbook as TsWorkbook).ConvertUnits(Length(IntToStr(rLast)) + 2, suChars, suPoints);
end else
begin
w := FWorksheet.ReadDefaultColWidth(suPoints);
col := FWorksheet.FindCol(AColIndex);
w := sheet.ReadDefaultColWidth(suPoints);
col := sheet.FindCol(AColIndex);
if (col <> nil) and (col^.Width > 0) then
w := FWorkbook.ConvertUnits(col^.Width, FWorkbook.Units, suPoints);
w := (FWorkbook as TsWorkbook).ConvertUnits(col^.Width, FWorkbook.Units, suPoints);
end;
Result:= Format(' width="%.1fpt"', [w], FPointSeparatorSettings);
end;
@ -1342,7 +1351,7 @@ function TsHTMLWriter.GetFontAsStyle(AFontIndex: Integer): String;
var
font: TsFont;
begin
font := FWorkbook.GetFont(AFontIndex);
font := (FWorkbook as TsWorkbook).GetFont(AFontIndex);
Result := Format('font-family:''%s'';font-size:%.1fpt;color:%s;', [
font.FontName, font.Size, ColorToHTMLColorStr(font.Color)], FPointSeparatorSettings);
if fssBold in font.Style then
@ -1381,7 +1390,7 @@ var
r1, r2, c1, c2: Cardinal;
begin
Result := '';
FWorksheet.FindMergedRange(AMergeBase, r1, c1, r2, c2);
(FWorksheet as TsWorksheet).FindMergedRange(AMergeBase, r1, c1, r2, c2);
if c1 <> c2 then
Result := Result + ' colspan="' + IntToStr(c2-c1+1) + '"';
if r1 <> r2 then
@ -1393,11 +1402,11 @@ var
h: Single;
row: PRow;
begin
h := FWorksheet.ReadDefaultRowHeight(suPoints);
row := FWorksheet.FindRow(ARowIndex);
h := (FWorksheet as TsWorksheet).ReadDefaultRowHeight(suPoints);
row := (FWorksheet as TsWorksheet).FindRow(ARowIndex);
if row <> nil then begin
if row^.RowHeightType = rhtCustom then
h := abs(FWorkbook.ConvertUnits(row^.Height, FWorkbook.Units, suPoints));
h := abs((FWorkbook as TsWorkbook).ConvertUnits(row^.Height, FWorkbook.Units, suPoints));
end;
Result := Format(' height="%.1fpt"', [h], FPointSeparatorSettings);
end;
@ -1441,7 +1450,7 @@ end;
procedure TsHTMLWriter.InternalWriteToStream(AStream: TStream);
begin
FWorkbook.UpdateCaches;
(FWorkbook as TsWorkbook).UpdateCaches;
AppendToStream(AStream,
'<!DOCTYPE html>');
@ -1472,9 +1481,9 @@ begin
if ACell = nil then
exit;
for i:=0 to FWorkbook.GetWorksheetCount-1 do
for i:=0 to (FWorkbook as TsWorkbook).GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet := (FWorkbook as TsWorkbook).GetWorksheetByIndex(i);
for hyperlink in sheet.Hyperlinks do
begin
SplitHyperlink(hyperlink^.Target, target, ABookmark);
@ -1503,20 +1512,23 @@ end;
procedure TsHTMLWriter.WriteBody(AStream: TStream);
var
i: Integer;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
AppendToStream(AStream,
'<body>');
if FWindowsClipboardMode or (HTMLParams.SheetIndex < 0) then // active sheet
begin
if FWorkbook.ActiveWorksheet = nil then
FWorkbook.SelectWorksheet(FWorkbook.GetWorksheetByIndex(0));
WriteWorksheet(AStream, FWorkbook.ActiveWorksheet)
if book.ActiveWorksheet = nil then
book.SelectWorksheet(book.GetWorksheetByIndex(0));
WriteWorksheet(AStream, book.ActiveWorksheet)
end else
if HTMLParams.SheetIndex = MaxInt then // all sheets
for i:=0 to FWorkbook.GetWorksheetCount-1 do
WriteWorksheet(AStream, FWorkbook.GetWorksheetByIndex(i))
for i:=0 to book.GetWorksheetCount-1 do
WriteWorksheet(AStream, book.GetWorksheetByIndex(i))
else // specific sheet
WriteWorksheet(AStream, FWorkbook.GetWorksheetbyIndex(HTMLParams.SheetIndex));
WriteWorksheet(AStream, book.GetWorksheetbyIndex(HTMLParams.SheetIndex));
AppendToStream(AStream,
'</body>');
end;
@ -1538,7 +1550,7 @@ var
s: String;
begin
Unused(AValue, ACol, ARow);
s := FWorksheet.ReadAsText(ACell);
s := (FWorksheet as TsWorksheet).ReadAsText(ACell);
AppendToStream(AStream,
'<div>' + s + '</div>');
end;
@ -1549,7 +1561,7 @@ var
s: String;
begin
Unused(AValue, ACol, ARow);
s := FWOrksheet.ReadAsText(ACell);
s := (FWorksheet as TsWorksheet).ReadAsText(ACell);
AppendToStream(AStream,
'<div>' + s + '</div>');
end;
@ -1593,13 +1605,13 @@ begin
exit;
style := '';
cellfnt := FWorksheet.ReadCellFont(ACell);
cellfnt := (FWorksheet as TsWorksheet).ReadCellFont(ACell);
// Hyperlink
target := '';
if FWorksheet.HasHyperlink(ACell) then
begin
hyperlink := FWorksheet.FindHyperlink(ACell);
hyperlink := (FWorksheet as TsWorksheet).FindHyperlink(ACell);
SplitHyperlink(hyperlink^.Target, target, bookmark);
n := Length(hyperlink^.Target);
@ -1657,7 +1669,7 @@ begin
begin
// formatted section
rtParam := ACell^.RichTextParams[i];
fnt := FWorkbook.GetFont(rtParam.FontIndex);
fnt := (FWorkbook as TsWorkbook).GetFont(rtParam.FontIndex);
style := GetFontAsStyle(rtParam.FontIndex);
if style <> '' then
style := ' style="' + style +'"';
@ -1684,7 +1696,7 @@ var
s: String;
begin
Unused(ARow, ACol, AValue);
s := FWorksheet.ReadAsText(ACell, FWorkbook.FormatSettings);
s := (FWorksheet as TsWorksheet).ReadAsText(ACell, FWorkbook.FormatSettings);
AppendToStream(AStream,
'<div>' + s + '</div>');
end;
@ -1697,8 +1709,8 @@ var
begin
AppendToStream(AStream,
'<style>' + LineEnding);
for i:=0 to FWorkbook.GetNumCellFormats-1 do begin
fmt := FWorkbook.GetPointerToCellFormat(i);
for i:=0 to (FWorkbook as TsWorkbook).GetNumCellFormats-1 do begin
fmt := (FWorkbook as TsWorkbook).GetPointerToCellFormat(i);
fmtStr := CellFormatAsString(fmt);
if fmtStr <> '' then
fmtStr := Format(' td.style%d {%s}' + LineEnding, [i+1, fmtStr]);
@ -1741,7 +1753,7 @@ begin
end;
end;
procedure TsHTMLWriter.WriteWorksheet(AStream: TStream; ASheet: TsWorksheet);
procedure TsHTMLWriter.WriteWorksheet(AStream: TStream; ASheet: TsBasicWorksheet);
var
r, rFirst, rLast: LongInt;
c, cFirst, cLast: LongInt;
@ -1751,18 +1763,19 @@ var
style, s: String;
fixedLayout: Boolean;
fmt: PsCellFormat;
sheet: TsWorksheet absolute ASheet;
begin
FWorksheet := ASheet;
rFirst := FWorksheet.GetFirstRowIndex;
cFirst := FWorksheet.GetFirstColIndex;
rLast := FWorksheet.GetLastOccupiedRowIndex;
cLast := FWorksheet.GetLastOccupiedColIndex;
rFirst := sheet.GetFirstRowIndex;
cFirst := sheet.GetFirstColIndex;
rLast := sheet.GetLastOccupiedRowIndex;
cLast := sheet.GetLastOccupiedColIndex;
fixedLayout := false;
for c:=cFirst to cLast do
begin
col := FWorksheet.GetCol(c);
col := sheet.GetCol(c);
if col <> nil then
begin
fixedLayout := true;
@ -1812,7 +1825,7 @@ begin
style := ' style="' + style + '"';
if fixedLayout then
style := style + GetColWidthAsAttr(c);
col := FWorksheet.FindCol(c);
col := sheet.FindCol(c);
if (col <> nil) and (col^.FormatIndex > 0) then
style := style + Format(' class="style%d"', [col^.FormatIndex+1]);
@ -1822,7 +1835,7 @@ begin
end;
for r := rFirst to rLast do begin
row := FWorksheet.FindRow(r);
row := sheet.FindRow(r);
AppendToStream(AStream,
'<tr>' + LineEnding);
@ -1840,8 +1853,8 @@ begin
for c := cFirst to cLast do begin
// Pointer to current cell in loop
cell := FWorksheet.FindCell(r, c);
col := FWorksheet.FindCol(c);
cell := sheet.FindCell(r, c);
col := sheet.FindCol(c);
// Cell formatting via predefined styles ("class")
style := '';
@ -1849,17 +1862,17 @@ begin
if cell <> nil then
begin
style := Format(' class="style%d"', [cell^.FormatIndex+1]);
fmt := FWorkbook.GetPointerToCellFormat(cell^.FormatIndex);
fmt := (FWorkbook as TsWorkbook).GetPointerToCellFormat(cell^.FormatIndex);
end else
if (row <> nil) and (row^.FormatIndex > 0) then
begin
style := Format(' class="style%d"', [row^.FormatIndex+1]);
fmt := FWorkbook.GetPointerToCellFormat(row^.FormatIndex);
fmt := (FWorkbook as TsWorkbook).GetPointerToCellFormat(row^.FormatIndex);
end else
if (col <> nil) and (col^.FormatIndex > 0) then
begin
style := Format(' class="style%d"', [col^.FormatIndex+1]);
fmt := FWorkbook.GetPointerToCellFormat(col^.FormatIndex);
fmt := (FWorkbook as TsWorkbook).GetPointerToCellFormat(col^.FormatIndex);
end;
// Overriding differences between html and fps formatting
@ -1888,9 +1901,9 @@ begin
end;
// Merged cells
if FWorksheet.IsMerged(cell) then
if sheet.IsMerged(cell) then
begin
if FWorksheet.IsMergeBase(cell) then
if sheet.IsMergeBase(cell) then
style := style + GetMergedRangeAsStyle(cell)
else
Continue;

View File

@ -5,7 +5,7 @@ unit fpsHTMLUtils;
interface
uses
Classes, SysUtils, contnrs, fpstypes, fpspreadsheet;
Classes, SysUtils, contnrs, fpstypes;
type
TsHTMLEntity = record
@ -39,11 +39,11 @@ type
TsTagCase = (tcLowercase, tcUppercase, tcProperCase);
procedure HTMLToRichText(AWorkbook: TsWorkbook; AFont: TsFont;
procedure HTMLToRichText(AWorkbook: TsBasicWorkbook; AFont: TsFont;
const AHTMLText: String; out APlainText: String;
out ARichTextParams: TsRichTextParams);
procedure RichTextToHTML(AWorkbook: TsWorkbook; AFont: TsFont;
procedure RichTextToHTML(AWorkbook: TsBasicWorkbook; AFont: TsFont;
const APlainText: String; const ARichTextParams: TsRichTextParams;
out AHTMLText: String; APrefix:String = ''; ATagCase: TsTagCase = tcLowercase);
@ -52,7 +52,7 @@ implementation
uses
math, lazUtf8, fasthtmlparser,
fpsUtils, fpsClasses;
fpsUtils, fpsClasses, fpspreadsheet;
const
// http://unicode.e-workers.de/entities.php
@ -940,7 +940,7 @@ end;
@@param ARichtTextParams Rich-text parameters corresponding to the embedded
html tags
-------------------------------------------------------------------------------}
procedure HTMLToRichText(AWorkbook: TsWorkbook; AFont: TsFont;
procedure HTMLToRichText(AWorkbook: TsBasicWorkbook; AFont: TsFont;
const AHTMLText: String; out APlainText: String;
out ARichTextParams: TsRichTextParams);
var
@ -949,7 +949,7 @@ var
len: Integer;
nrtp: Integer;
begin
analyzer := TsHTMLAnalyzer.Create(AWorkbook, AFont, AHTMLText + '<end>');
analyzer := TsHTMLAnalyzer.Create(AWorkbook as TsWorkbook, AFont, AHTMLText + '<end>');
try
analyzer.PreserveSpaces := true;
analyzer.Exec;
@ -1187,7 +1187,7 @@ end;
Constructs a html-coded string from a plain text string and
rich-text parameters
-------------------------------------------------------------------------------}
procedure RichTextToHTML(AWorkbook: TsWorkbook; AFont: TsFont;
procedure RichTextToHTML(AWorkbook: TsBasicWorkbook; AFont: TsFont;
const APlainText: String; const ARichTextParams: TsRichTextParams;
out AHTMLText: String; APrefix: String = ''; ATagCase: TsTagCase = tcLowercase);
var
@ -1197,7 +1197,7 @@ begin
AHTMLText := APlainText
else
begin
composer := TsHTMLComposer.Create(AWorkbook, AFont, APrefix, ATagCase);
composer := TsHTMLComposer.Create(AWorkbook as TsWorkbook, AFont, APrefix, ATagCase);
try
AHTMLText := composer.Exec(APlainText, ARichTextParams);
finally

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ unit fpsPalette;
interface
uses
Classes, SysUtils, fpstypes, fpspreadsheet;
Classes, SysUtils, fpstypes;
type
@ -34,8 +34,8 @@ type
procedure AddExcelColors;
function AddUniqueColor(AColor: TsColor; ABigEndian: Boolean = false): Integer;
procedure Clear;
procedure CollectFromWorkbook(AWorkbook: TsWorkbook);
function ColorUsedInWorkbook(APaletteIndex: Integer; AWorkbook: TsWorkbook): Boolean;
procedure CollectFromWorkbook(AWorkbook: TsBasicWorkbook);
function ColorUsedInWorkbook(APaletteIndex: Integer; AWorkbook: TsBasicWorkbook): Boolean;
function FindClosestColorIndex(AColor: TsColor; AMaxPaletteCount: Integer = -1): Integer;
function FindColor(AColor: TsColor; AMaxPaletteCount: Integer = -1;
AStartIndex: Integer = 0): Integer;
@ -51,7 +51,7 @@ type
implementation
uses
fpsutils;
fpsutils, fpspreadsheet;
{@@ ----------------------------------------------------------------------------
If a palette is coded as big-endian (e.g. by copying the rgb values from
@ -223,18 +223,19 @@ end;
{@@ ----------------------------------------------------------------------------
Collects the colors used in the specified workbook
-------------------------------------------------------------------------------}
procedure TsPalette.CollectFromWorkbook(AWorkbook: TsWorkbook);
procedure TsPalette.CollectFromWorkbook(AWorkbook: TsBasicWorkbook);
var
i: Integer;
book: TsWorkbook absolute AWorkbook;
sheet: TsWorksheet;
cell: PCell;
fmt: TsCellFormat;
fnt: TsFont;
cb: TsCellBorder;
begin
for i:=0 to AWorkbook.GetWorksheetCount-1 do
for i:=0 to book.GetWorksheetCount-1 do
begin
sheet := AWorkbook.GetWorksheetByIndex(i);
sheet := book.GetWorksheetByIndex(i);
for cell in sheet.Cells do begin
fmt := sheet.ReadCellFormat(cell);
if (uffBackground in fmt.UsedFormattingFields) then
@ -244,7 +245,7 @@ begin
end;
if (uffFont in fmt.UsedFormattingFields) then
begin
fnt := AWorkbook.GetFont(fmt.FontIndex);
fnt := book.GetFont(fmt.FontIndex);
AddUniqueColor(fnt.Color);
end;
if (uffBorder in fmt.UsedFormattingFields) then
@ -264,8 +265,9 @@ end;
@result True if the color is used by at least one cell, false if not.
-------------------------------------------------------------------------------}
function TsPalette.ColorUsedInWorkbook(APaletteIndex: Integer;
AWorkbook: TsWorkbook): Boolean;
AWorkbook: TsBasicWorkbook): Boolean;
var
book: TsWorkbook absolute AWorkbook;
sheet: TsWorksheet;
cell: PCell;
i: Integer;
@ -279,12 +281,12 @@ begin
exit(false);
Result := true;
for i:=0 to AWorkbook.GetWorksheetCount-1 do
for i:=0 to book.GetWorksheetCount-1 do
begin
sheet := AWorkbook.GetWorksheetByIndex(i);
sheet := book.GetWorksheetByIndex(i);
for cell in sheet.Cells do
begin
fmt := AWorkbook.GetPointerToCellFormat(cell^.FormatIndex);
fmt := book.GetPointerToCellFormat(cell^.FormatIndex);
if (uffBackground in fmt^.UsedFormattingFields) then
begin
if fmt^.Background.BgColor = color then exit;
@ -296,7 +298,7 @@ begin
exit;
if (uffFont in fmt^.UsedFormattingFields) then
begin
fnt := AWorkbook.GetFont(fmt^.FontIndex);
fnt := book.GetFont(fmt^.FontIndex);
if fnt.Color = color then
exit;
end;

View File

@ -30,23 +30,6 @@ type
TsWorksheet = class;
TsWorkbook = class;
{@@ Worksheet user interface options:
@param soShowGridLines Show or hide the grid lines in the spreadsheet
@param soShowHeaders Show or hide the column or row headers of the
spreadsheet
@param soHasFrozenPanes If set a number of rows and columns of the
spreadsheet is fixed and does not scroll. The number
is defined by LeftPaneWidth and TopPaneHeight.
@param soHidden Worksheet is hidden.
@param soProtected Worksheet is protected
@param soPanesProtection Panes are locked due to workbook protection }
TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes, soHidden,
soProtected, soPanesProtection);
{@@ Set of user interface options
@ see TsSheetOption }
TsSheetOptions = set of TsSheetOption;
{ TsWorksheet }
@ -77,10 +60,9 @@ type
{@@ The worksheet contains a list of cells and provides a variety of methods
to read or write data to the cells, or to change their formatting. }
TsWorksheet = class
TsWorksheet = class(TsBasicWorksheet)
private
FWorkbook: TsWorkbook;
FName: String; // Name of the worksheet (displayed at the tab)
FCells: TsCells;
FComments: TsComments;
FMergedCells: TsMergedCells;
@ -94,7 +76,6 @@ type
FSelection: TsCellRangeArray;
FLeftPaneWidth: Integer;
FTopPaneHeight: Integer;
FOptions: TsSheetOptions;
FFirstRowIndex: Cardinal;
FFirstColIndex: Cardinal;
FLastRowIndex: Cardinal;
@ -105,7 +86,6 @@ type
FBiDiMode: TsBiDiMode;
FCryptoInfo: TsCryptoInfo;
FPageLayout: TsPageLayout;
FProtection: TsWorksheetProtections;
FVirtualColCount: Cardinal;
FVirtualRowCount: Cardinal;
FZoomFactor: Double;
@ -125,7 +105,6 @@ type
procedure SetBiDiMode(AValue: TsBiDiMode);
procedure SetDefaultColWidth(AValue: Single);
procedure SetDefaultRowHeight(AValue: Single);
procedure SetName(const AName: String);
procedure SetVirtualColCount(AValue: Cardinal);
procedure SetVirtualRowCount(AValue: Cardinal);
procedure SetZoomFactor(AValue: Double);
@ -152,6 +131,9 @@ type
AFromIndex, AToIndex: Cardinal);
procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
// inherited setters/getters
procedure SetName(const AName: String); override;
public
{ Base methods }
constructor Create;
@ -523,7 +505,6 @@ type
// Hyperlinks
function FindHyperlink(ACell: PCell): PsHyperlink;
function HasHyperlink(ACell: PCell): Boolean;
function ReadHyperlink(ACell: PCell): TsHyperlink;
procedure RemoveHyperlink(ACell: PCell);
function ValidHyperlink(AValue: String; out AErrMsg: String): Boolean;
@ -567,7 +548,6 @@ type
{ Protection }
procedure Protect(AEnable: Boolean);
function IsProtected: Boolean;
{ Notification of changed cells, rows or columns }
procedure ChangedCell(ARow, ACol: Cardinal);
@ -592,13 +572,8 @@ type
property Hyperlinks: TsHyperlinks read FHyperlinks;
{@@ FormatSettings for localization of some formatting strings }
property FormatSettings: TFormatSettings read GetFormatSettings;
{@@ Name of the sheet. In the popular spreadsheet applications this is
displayed at the tab of the sheet. }
property Name: string read FName write SetName;
{@@ Parameters to be used for printing by the Office applications }
property PageLayout: TsPageLayout read FPageLayout write FPageLayout;
{@@ Worksheet protection options }
property Protection: TsWorksheetProtections read FProtection write FProtection;
{@@ List of all row records of the worksheet having a non-standard row height }
property Rows: TIndexedAVLTree read FRows;
{@@ Workbook to which the worksheet belongs }
@ -619,9 +594,6 @@ type
// These are properties to interface to TsWorksheetGrid
property BiDiMode: TsBiDiMode read FBiDiMode write SetBiDiMode;
{@@ Parameters controlling visibility of grid lines and row/column headers,
usage of frozen panes etc. }
property Options: TsSheetOptions read FOptions write FOptions;
{@@ Column index of the selected cell of this worksheet }
property ActiveCellCol: Cardinal read FActiveCellCol;
{@@ Row index of the selected cell of this worksheet }
@ -656,43 +628,6 @@ type
property OnZoom: TsNotifyEvent read FOnZoom write FOnZoom;
end;
{@@
Option flags for the workbook
@param boVirtualMode If in virtual mode date are not taken from cells
when a spreadsheet is written to file, but are
provided by means of the event OnWriteCellData.
Similarly, when data are read they are not added
as cells but passed the the event OnReadCellData;
@param boBufStream When this option is set a buffered stream is used
for writing (a memory stream swapping to disk) or
reading (a file stream pre-reading chunks of data
to memory)
@param boFileStream Uses file streams and temporary files during
reading and writing. Lowest memory consumptions,
but slow.
@param boAutoCalc Automatically recalculate formulas whenever a
cell value changes.
@param boCalcBeforeSaving Calculates formulas before saving the file.
Otherwise there are no results when the file is
loaded back by fpspreadsheet.
@param boReadFormulas Allows to turn off reading of rpn formulas; this
is a precaution since formulas not correctly
implemented by fpspreadsheet could crash the
reading operation.
@param boWriteZoomfactor Instructs the writer to write the current zoom
factors of the worksheets to file.
@param boAbortReadOnFormulaError Aborts reading if a formula error is
encountered
@param boIgnoreFormulas Formulas are not checked and not calculated.
Cannot be used for biff formats. }
TsWorkbookOption = (boVirtualMode, boBufStream, boFileStream,
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor,
boAbortReadOnFormulaError, boIgnoreFormulas);
{@@ Set of option flags for the workbook }
TsWorkbookOptions = set of TsWorkbookOption;
{@@ Event fired when reading a file in virtual mode. Read data are provided in
the "ADataCell" (which is not added to the worksheet in virtual mode). }
TsWorkbookReadCellDataEvent = procedure(Sender: TObject; ARow, ACol: Cardinal;
@ -707,40 +642,32 @@ type
{@@ FSome action has an effect on existing formulas which must be corrected. }
TsFormulaCorrection = (fcWorksheetRenamed);
{ TsWorkbook }
{ TsWorkbook }
{@@ The workbook contains the worksheets and provides methods for reading from
and writing to file. }
TsWorkbook = class
TsWorkbook = class(TsBasicWorkbook)
private
{ Internal data }
FWorksheets: TFPList;
FFormatID: TsSpreadFormatID;
FBuiltinFontCount: Integer;
FReadWriteFlag: TsReadWriteFlag;
FCalculationLock: Integer;
FOptions: TsWorkbookOptions;
FActiveWorksheet: TsWorksheet;
FOnOpenWorkbook: TNotifyEvent;
FOnReadCellData: TsWorkbookReadCellDataEvent;
FOnChangeWorksheet: TsWorksheetEvent;
FOnRenameWorksheet: TsWorksheetEvent;
FOnAddWorksheet: TsWorksheetEvent;
FOnRemoveWorksheet: TsRemoveWorksheetEvent;
FOnRemovingWorksheet: TsWorksheetEvent;
FOnSelectWorksheet: TsWorksheetEvent;
FFileName: String;
FOnReadCellData: TsWorkbookReadCellDataEvent;
FLockCount: Integer;
FLog: TStringList;
FSearchEngine: TObject;
FUnits: TsSizeUnits;
FProtection: TsWorkbookProtections;
FCryptoInfo: TsCryptoInfo;
{FrevisionsCrypto: TsCryptoInfo;} // Commented out because it needs revision handling
{ Setter/Getter }
function GetErrorMsg: String;
{ Callback procedures }
procedure RemoveWorksheetsCallback(data, arg: pointer);
@ -764,11 +691,6 @@ type
// procedure ReCalc;
public
{@@ A copy of SysUtil's DefaultFormatSettings (converted to UTF8) to provide
some kind of localization to some formatting strings.
Can be modified before loading/writing files }
FormatSettings: TFormatSettings;
{ Base methods }
constructor Create;
destructor Destroy; override;
@ -809,7 +731,7 @@ type
function GetWorksheetByIndex(AIndex: Integer): TsWorksheet;
function GetWorksheetByName(AName: String): TsWorksheet;
function GetWorksheetCount: Integer;
function GetWorksheetIndex(AWorksheet: TsWorksheet): Integer; overload;
function GetWorksheetIndex(AWorksheet: TsBasicWorksheet): Integer; overload;
function GetWorksheetIndex(const AWorksheetName: String): Integer; overload;
procedure RemoveAllWorksheets;
procedure RemoveAllEmptyWorksheets;
@ -886,33 +808,16 @@ type
procedure UpdateCaches;
procedure GetLastRowColIndex(out ALastRow, ALastCol: Cardinal);
{ Protection }
function IsProtected: Boolean;
{ Notification }
procedure ChangedWorksheet(AWorksheet: TsWorksheet);
procedure DisableNotifications;
procedure EnableNotifications;
function NotificationsEnabled: Boolean;
{ Error messages }
procedure AddErrorMsg(const AMsg: String); overload;
procedure AddErrorMsg(const AMsg: String; const Args: array of const); overload;
procedure ClearErrorList;
{@@ Identifies the "active" worksheet (only for visual controls)}
property ActiveWorksheet: TsWorksheet read FActiveWorksheet write SelectWorksheet;
property CryptoInfo: TsCryptoInfo read FCryptoInfo write FCryptoInfo;
{@@ Retrieves error messages collected during reading/writing }
property ErrorMsg: String read GetErrorMsg;
{@@ Filename of the saved workbook }
property FileName: String read FFileName;
{@@ Identifies the file format which was detected when reading the file }
property FileFormatID: TsSpreadFormatID read FFormatID;
property Options: TsWorkbookOptions read FOptions write FOptions;
{property RevisionsCrypto: TsCryptoInfo read FRevisionsCrypto write FRevisionsCrypto;}
property Protection: TsWorkbookProtections read FProtection write FProtection;
property Units: TsSizeUnits read FUnits;
{@@ This event fires whenever a new worksheet is added }
property OnAddWorksheet: TsWorksheetEvent read FOnAddWorksheet write FOnAddWorksheet;
@ -1217,7 +1122,6 @@ begin
FActiveCellRow := UNASSIGNED_ROW_COL_INDEX;
FActiveCellCol := UNASSIGNED_ROW_COL_INDEX;
FProtection := DEFAULT_SHEET_PROTECTION;
InitCryptoInfo(FCryptoInfo);
FOptions := [soShowGridLines, soShowHeaders];
@ -1336,8 +1240,7 @@ begin
end;
rtBoolean : WriteBoolValue(ACell, res.ResBoolean);
rtCell : begin
// cell := GetCell(res.ResRow, res.ResCol);
cell := res.Worksheet.FindCell(res.ResRow, res.ResCol);
cell := (res.Worksheet as TsWorksheet).FindCell(res.ResRow, res.ResCol);
if cell <> nil then
case cell^.ContentType of
cctNumber : WriteNumber(ACell, cell^.NumberValue);
@ -1603,14 +1506,6 @@ begin
Result := nil;
end;
{@@ ----------------------------------------------------------------------------
Checks whether the specified cell contains a hyperlink
-------------------------------------------------------------------------------}
function TsWorksheet.HasHyperlink(ACell: PCell): Boolean;
begin
Result := (ACell <> nil) and (cfHyperlink in ACell^.Flags);
end;
{@@ ----------------------------------------------------------------------------
Reads the hyperlink information of a specified cell.
@ -4201,14 +4096,6 @@ begin
FWorkbook.ChangedWorksheet(self);
end;
{@@ ----------------------------------------------------------------------------
Returns whether the worksheet is protected
-------------------------------------------------------------------------------}
function TsWorksheet.IsProtected: Boolean;
begin
Result := soProtected in FOptions;
end;
{@@ ----------------------------------------------------------------------------
Setter for the worksheet name property. Checks if the name is valid, and
@ -4221,9 +4108,11 @@ begin
if (FWorkbook <> nil) then //and FWorkbook.ValidWorksheetName(AName) then
begin
FName := AName;
FWorkbook.FixFormulas(fcWorksheetRenamed, self, 0);
if (FWorkbook.FLockCount = 0) and Assigned(FWorkbook.FOnRenameWorksheet) then
FWorkbook.FOnRenameWorksheet(FWorkbook, self);
if FWorkbook.FReadWriteFlag = rwfNormal then begin
FWorkbook.FixFormulas(fcWorksheetRenamed, self, 0);
if (FWorkbook.FLockCount = 0) and Assigned(FWorkbook.FOnRenameWorksheet) then
FWorkbook.FOnRenameWorksheet(FWorkbook, self);
end;
end;
end;
@ -8111,10 +8000,10 @@ begin
InitFonts;
// Clear error log
FLog.Clear;
ClearErrorList;
// Abort if virtual mode is active without an event handler
if (boVirtualMode in FOptions) and not Assigned(FOnReadCellData) then
if (boVirtualMode in FOptions) and not Assigned(OnReadCellData) then
raise EFPSpreadsheet.Create('[TsWorkbook.PrepareBeforeReading] Event handler "OnReadCellData" required for virtual mode.');
end;
@ -8129,7 +8018,7 @@ var
virtModeOK: Boolean;
begin
// Clear error log
FLog.Clear;
ClearErrorList;
// Updates fist/last column/row index
UpdateCaches;
@ -8280,13 +8169,6 @@ var
begin
inherited Create;
FWorksheets := TFPList.Create;
FLog := TStringList.Create;
FFormatID := sfidUnknown;
FUnits := suMillimeters; // Units for column width and row height
FormatSettings := UTF8FormatSettings;
// FormatSettings.ShortDateFormat := MakeShortDateFormat(FormatSettings.ShortDateFormat);
// FormatSettings.LongDateFormat := MakeLongDateFormat(FormatSettings.ShortDateFormat);
FFontList := TFPList.Create;
SetDefaultFont(DEFAULT_FONTNAME, DEFAULT_FONTSIZE);
@ -8302,7 +8184,6 @@ begin
// Protection
InitCryptoInfo(FCryptoInfo);
FProtection := [];
end;
{@@ ----------------------------------------------------------------------------
@ -8324,7 +8205,6 @@ begin
RemoveAllEmbeddedObj;
FEmbeddedObjList.Free;
FLog.Free;
FreeAndNil(FSearchEngine);
inherited Destroy;
@ -8454,14 +8334,6 @@ begin
end;
end;
{@@ ----------------------------------------------------------------------------
Returns whether the workbook is protected
-------------------------------------------------------------------------------}
function TsWorkbook.IsProtected: Boolean;
begin
Result := (FProtection <> []);
end;
{@@ ----------------------------------------------------------------------------
Reads the document from a file. It is assumed to have the given file format.
@ -9044,7 +8916,7 @@ end;
{@@ ----------------------------------------------------------------------------
Returns the index of a worksheet in the worksheet list
-------------------------------------------------------------------------------}
function TsWorkbook.GetWorksheetIndex(AWorksheet: TsWorksheet): Integer;
function TsWorkbook.GetWorksheetIndex(AWorksheet: TsBasicWorksheet): Integer;
begin
Result := FWorksheets.IndexOf(AWorksheet);
end;
@ -9609,7 +9481,7 @@ begin
AddFont(AFontName, ASize, [], scBlack)
else
for i:=0 to FBuiltinFontCount-1 do
if (i <> 4) and (i < FFontList.Count) then
if (i <> 4) and (i < FFontList.Count) then // wp: why if font #4 relevant here ????
with TsFont(FFontList[i]) do
begin
FontName := AFontName;
@ -9663,21 +9535,8 @@ end;
@return String with font name, font size etc.
-------------------------------------------------------------------------------}
function TsWorkbook.GetFontAsString(AIndex: Integer): String;
var
fnt: TsFont;
begin
fnt := GetFont(AIndex);
if fnt <> nil then begin
Result := Format('%s; size %.1g; %s', [
fnt.FontName, fnt.Size, GetColorName(fnt.Color)]);
if (fssBold in fnt.Style) then Result := Result + '; bold';
if (fssItalic in fnt.Style) then Result := Result + '; italic';
if (fssUnderline in fnt.Style) then Result := Result + '; underline';
if (fssStrikeout in fnt.Style) then result := Result + '; strikeout';
if fnt.Position = fpSubscript then Result := Result + '; subscript';
if fnt.Position = fpSuperscript then Result := Result + '; superscript';
end else
Result := '';
Result := fpsUtils.GetFontAsString(GetFont(AIndex));
end;
{@@ ----------------------------------------------------------------------------
@ -10200,42 +10059,6 @@ begin
FEmbeddedObjList.Clear;
end;
{@@ ----------------------------------------------------------------------------
Adds a (simple) error message to an internal list
@param AMsg Error text to be stored in the list
-------------------------------------------------------------------------------}
procedure TsWorkbook.AddErrorMsg(const AMsg: String);
begin
FLog.Add(AMsg);
end;
{@@ ----------------------------------------------------------------------------
Adds an error message composed by means of format codes to an internal list
@param AMsg Error text to be stored in the list
@param Args Array of arguments to be used by the Format() function
-------------------------------------------------------------------------------}
procedure TsWorkbook.AddErrorMsg(const AMsg: String; const Args: Array of const);
begin
FLog.Add(Format(AMsg, Args));
end;
{@@ ----------------------------------------------------------------------------
Clears the internal error message list
-------------------------------------------------------------------------------}
procedure TsWorkbook.ClearErrorList;
begin
FLog.Clear;
end;
{@@ ----------------------------------------------------------------------------
Getter to retrieve the error messages collected during reading/writing
-------------------------------------------------------------------------------}
function TsWorkbook.GetErrorMsg: String;
begin
Result := FLog.Text;
end;
(*
{@@ ----------------------------------------------------------------------------
Converts a fpspreadsheet color into into a string RRGGBB.

View File

@ -23,7 +23,7 @@ interface
uses
Classes, Sysutils,
fpsTypes, fpsClasses, fpSpreadsheet;
fpsTypes, fpsClasses;
type
@ -31,16 +31,16 @@ type
TsBasicSpreadReaderWriter = class
protected
{@@ Instance of the workbook which is currently being read or written. }
FWorkbook: TsWorkbook;
FWorkbook: TsBasicWorkbook;
{@@ Instance of the worksheet which is currently being read or written. }
FWorksheet: TsWorksheet;
FWorksheet: TsBasicWorksheet;
{@@ Limitations for the specific data file format }
FLimitations: TsSpreadsheetFormatLimitations;
public
constructor Create(AWorkbook: TsWorkbook); virtual; // to allow descendents to override it
constructor Create(AWorkbook: TsBasicWorkbook); virtual; // to allow descendents to override it
function Limitations: TsSpreadsheetFormatLimitations;
{@@ Instance of the workbook which is currently being read/written. }
property Workbook: TsWorkbook read FWorkbook;
property Workbook: TsBasicWorkbook read FWorkbook;
end;
{ TsBasicSpreadReader }
@ -93,9 +93,9 @@ type
{ Helper methods }
procedure AddBuiltinNumFormats; virtual;
{@@ Removes column records if all of them have the same column width }
procedure FixCols(AWorksheet: TsWorksheet);
procedure FixCols(AWorksheet: TsBasicWorksheet);
{@@ Removes row records if all of them have the same row height }
procedure FixRows(AWorksheet: TsWorksheet);
procedure FixRows(AWorksheet: TsBasicWorksheet);
{ Record reading methods }
{@@ Abstract method for reading a blank cell. Must be overridden by descendent classes. }
@ -110,7 +110,7 @@ type
procedure ReadNumber(AStream: TStream); virtual; abstract;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
{ General writing methods }
@ -148,7 +148,7 @@ type
function FindNumFormatInList(ANumFormatStr: String): Integer;
// function FixColor(AColor: TsColor): TsColor; virtual;
procedure FixFormat(ACell: PCell); virtual;
procedure GetSheetDimensions(AWorksheet: TsWorksheet;
procedure GetSheetDimensions(AWorksheet: TsBasicWorksheet;
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
procedure ListAllNumFormats; virtual;
@ -174,7 +174,7 @@ type
const AValue: double; ACell: PCell); virtual; abstract;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
{ General writing methods }
@ -219,7 +219,7 @@ implementation
uses
Math, LazUTF8,
fpsStrings, fpsUtils, fpsNumFormat, fpsStreams;
fpsStrings, fpsUtils, fpsNumFormat, fpsStreams, fpspreadsheet;
{------------------------------------------------------------------------------}
@ -234,7 +234,7 @@ uses
file is written. This parameter is passed from the workbook
which creates the reader/writer.
-------------------------------------------------------------------------------}
constructor TsBasicSpreadReaderWriter.Create(AWorkbook: TsWorkbook);
constructor TsBasicSpreadReaderWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
@ -264,24 +264,27 @@ end;
-------------------------------------------------------------------------------}
procedure TsBasicSpreadWriter.CheckLimitations;
var
workbook: TsWorkbook;
lastCol, lastRow: Cardinal;
i: Integer;
sheet: TsWorksheet;
begin
Workbook.GetLastRowColIndex(lastRow, lastCol);
workbook := FWorkbook as TsWorkbook;
workbook.GetLastRowColIndex(lastRow, lastCol);
// Check row count
if lastRow >= FLimitations.MaxRowCount then
Workbook.AddErrorMsg(rsMaxRowsExceeded, [lastRow+1, FLimitations.MaxRowCount]);
workbook.AddErrorMsg(rsMaxRowsExceeded, [lastRow+1, FLimitations.MaxRowCount]);
// Check column count
if lastCol >= FLimitations.MaxColCount then
Workbook.AddErrorMsg(rsMaxColsExceeded, [lastCol+1, FLimitations.MaxColCount]);
workbook.AddErrorMsg(rsMaxColsExceeded, [lastCol+1, FLimitations.MaxColCount]);
// Check worksheet names
for i:=0 to Workbook.GetWorksheetCount-1 do
for i:=0 to workbook.GetWorksheetCount-1 do
begin
sheet := Workbook.GetWorksheetByIndex(i);
sheet := workbook.GetWorksheetByIndex(i);
if UTF8Length(sheet.Name) > FLimitations.MaxSheetNameLength then
// Worksheet name is too long.
// We abort saving here because it is not safe to chop the sheet name
@ -306,7 +309,7 @@ end;
This parameter is passed from the workbook which creates
the reader.
-------------------------------------------------------------------------------}
constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook);
constructor TsCustomSpreadReader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
// Font list
@ -316,7 +319,7 @@ begin
AddBuiltinNumFormats;
// Virtual mode
FIsVirtualMode := (boVirtualMode in FWorkbook.Options) and
Assigned(FWorkbook.OnReadCellData);
Assigned((FWorkbook as TsWorkbook).OnReadCellData);
end;
{@@ ----------------------------------------------------------------------------
@ -353,10 +356,11 @@ end;
@param AWorksheet The columns in this worksheet are processed.
-------------------------------------------------------------------------------}
procedure TsCustomSpreadReader.FixCols(AWorkSheet: TsWorksheet);
procedure TsCustomSpreadReader.FixCols(AWorkSheet: TsBasicWorksheet);
const
EPS = 1E-3;
var
sheet: TsWorksheet absolute AWorksheet;
c: LongInt;
w: Single;
lCol: PCol;
@ -365,30 +369,30 @@ begin
// If the count of columns is equal to the max colcount of the file format
// then it is likely that dummy columns have been added -> delete all empty
// columns (starting at the right) until the first non-empty column is found
if AWorksheet.Cols.Count = SizeInt(FLimitations.MaxColCount) then
if sheet.Cols.Count = SizeInt(FLimitations.MaxColCount) then
begin
c := AWorksheet.Cols.Count - 1;
lCol := PCol(AWorksheet.Cols[c]);
c := sheet.Cols.Count - 1;
lCol := PCol(sheet.Cols[c]);
w := lCol.Width;
while c >= 0 do begin
lCol := PCol(AWorksheet.Cols[c]);
lCol := PCol(sheet.Cols[c]);
if not SameValue(lCol^.Width, w, EPS) then
break;
if AWorksheet.FindNextCellInCol(0, c) <> nil then
if sheet.FindNextCellInCol(0, c) <> nil then
break;
AWorksheet.RemoveCol(c);
sheet.RemoveCol(c);
dec(c);
end;
end;
if AWorksheet.Cols.Count < 2 then
if sheet.Cols.Count < 2 then
exit;
// Check whether all columns have the same column width
sameWidth := true;
w := PCol(AWorksheet.Cols[0])^.Width;
for c := 1 to AWorksheet.Cols.Count-1 do begin
lCol := PCol(AWorksheet.Cols[c]);
w := PCol(sheet.Cols[0])^.Width;
for c := 1 to sheet.Cols.Count-1 do begin
lCol := PCol(sheet.Cols[c]);
if not SameValue(lCol^.Width, w, EPS) then
begin
sameWidth := false;
@ -399,12 +403,12 @@ begin
if sameWidth then begin
// At this point we know that all columns have the same width. We pass this
// to the DefaultColWidth ...
AWorksheet.WriteDefaultColWidth(w, FWorkbook.Units);
sheet.WriteDefaultColWidth(w, FWorkbook.Units);
// ...and delete all column records with non-default format
for c := AWorksheet.Cols.Count-1 downto 0 do begin
lCol := PCol(AWorksheet.Cols[c]);
if lCol^.FormatIndex = 0 then AWorksheet.RemoveCol(c);
for c := sheet.Cols.Count-1 downto 0 do begin
lCol := PCol(sheet.Cols[c]);
if lCol^.FormatIndex = 0 then sheet.RemoveCol(c);
end;
end;
end;
@ -414,21 +418,22 @@ end;
row records if they do. Such unnecessary row records are often written
when an Office application converts a file to another format.
-------------------------------------------------------------------------------}
procedure TsCustomSpreadReader.FixRows(AWorkSheet: TsWorksheet);
procedure TsCustomSpreadReader.FixRows(AWorkSheet: TsBasicWorksheet);
const
EPS = 1E-3;
var
sheet: TsWorksheet absolute AWorksheet;
r, rLast: Cardinal;
h: Single;
lRow: PRow;
begin
if AWorksheet.Rows.Count <= 1 then
if sheet.Rows.Count <= 1 then
exit;
// Check whether all rows have the same height
h := PRow(AWorksheet.Rows[0])^.Height;
for r := 1 to AWorksheet.Rows.Count-1 do begin
lRow := PRow(AWorksheet.Rows[r]);
h := PRow(sheet.Rows[0])^.Height;
for r := 1 to sheet.Rows.Count-1 do begin
lRow := PRow(sheet.Rows[r]);
if not SameValue(lRow^.Height, h, EPS) then
exit;
end;
@ -436,21 +441,21 @@ begin
// If there are more rows than row records and the common row height is not
// the default row height (i.e. the row height of the non-record rows) then
// the row heights are different
rLast := AWorksheet.GetLastRowIndex;
if (AWorksheet.Rows.Count > 0) and
(rLast <> PRow(AWorksheet.Rows[AWorksheet.Rows.Count-1]).Row) and
not SameValue(h, AWorksheet.ReadDefaultRowHeight(FWorkbook.Units), EPS)
rLast := sheet.GetLastRowIndex;
if (sheet.Rows.Count > 0) and
(rLast <> PRow(sheet.Rows[sheet.Rows.Count-1]).Row) and
not SameValue(h, sheet.ReadDefaultRowHeight(FWorkbook.Units), EPS)
then
exit;
// At this point we know that all rows have the same height. We pass this
// to the DefaultRowHeight ...
AWorksheet.WriteDefaultRowHeight(h, FWorkbook.Units);
sheet.WriteDefaultRowHeight(h, FWorkbook.Units);
// ... and delete all row records with default format.
for r := AWorksheet.Rows.Count-1 downto 0 do begin
lRow := PRow(AWorksheet.Rows[r]);
if lRow^.FormatIndex = 0 then AWorksheet.RemoveRow(r);
for r := sheet.Rows.Count-1 downto 0 do begin
lRow := PRow(sheet.Rows[r]);
if lRow^.FormatIndex = 0 then sheet.RemoveRow(r);
end;
end;
@ -549,7 +554,7 @@ end;
@param AWorkbook Workbook from with the file is written. This parameter is
passed from the workbook which creates the writer.
-------------------------------------------------------------------------------}
constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
constructor TsCustomSpreadWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
// Number formats
@ -616,26 +621,32 @@ end;
@param AFirstCol Index of first column to be written
@param ALastCol Index of last column to be written
-------------------------------------------------------------------------------}
procedure TsCustomSpreadWriter.GetSheetDimensions(AWorksheet: TsWorksheet;
procedure TsCustomSpreadWriter.GetSheetDimensions(AWorksheet: TsBasicWorksheet;
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal);
var
book: TsWorkbook;
sheet: TsWorksheet;
begin
if (boVirtualMode in AWorksheet.Workbook.Options) then
book := FWorkbook as TsWorkbook;
sheet := AWorksheet as TsWorksheet;
if (boVirtualMode in sheet.Workbook.Options) then
begin
AFirstRow := 0;
AFirstCol := 0;
ALastRow := LongInt(AWorksheet.VirtualRowCount)-1;
ALastCol := LongInt(AWorksheet.VirtualColCount)-1;
ALastRow := LongInt(sheet.VirtualRowCount)-1;
ALastCol := LongInt(sheet.VirtualColCount)-1;
end else
begin
Workbook.UpdateCaches;
AFirstRow := AWorksheet.GetFirstRowIndex;
book.UpdateCaches;
AFirstRow := sheet.GetFirstRowIndex;
if AFirstRow = Cardinal(-1) then
AFirstRow := 0; // this happens if the sheet is empty and does not contain row records
AFirstCol := AWorksheet.GetFirstColIndex;
AFirstCol := sheet.GetFirstColIndex;
if AFirstCol = Cardinal(-1) then
AFirstCol := 0; // this happens if the sheet is empty and does not contain col records
ALastRow := AWorksheet.GetLastRowIndex;
ALastCol := AWorksheet.GetLastColIndex;
ALastRow := sheet.GetLastRowIndex;
ALastCol := sheet.GetLastColIndex;
end;
if AFirstCol >= Limitations.MaxColCount then
AFirstCol := Limitations.MaxColCount-1;
@ -657,9 +668,9 @@ var
numFmt: TsNumFormatParams;
numFmtStr: String;
begin
for i:=0 to Workbook.GetNumberFormatCount - 1 do
for i:=0 to TsWorkbook(Workbook).GetNumberFormatCount - 1 do
begin
numFmt := Workbook.GetNumberFormat(i);
numFmt := TsWorkbook(Workbook).GetNumberFormat(i);
if numFmt <> nil then
begin
numFmtStr := numFmt.NumFormatStr;
@ -699,7 +710,7 @@ begin
WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
end;
if FWorksheet.ReadComment(ACell) <> '' then
if TsWorksheet(FWorksheet).ReadComment(ACell) <> '' then
WriteComment(AStream, ACell);
end;

View File

@ -23,6 +23,10 @@ type
{$ENDIF}
type
{ Forward declarations }
TsBasicWorksheet = class;
TsBasicWorkbook = class;
{@@ Built-in file formats of fpspreadsheet }
TsSpreadsheetFormat = (sfExcel2, sfExcel5, sfExcel8, sfExcelXML, sfOOXML,
sfOpenDocument, sfCSV, sfHTML, sfWikiTable_Pipes, sfWikiTable_WikiMedia,
@ -732,7 +736,7 @@ type
{ Location of the cell }
Row: Cardinal; // zero-based
Col: Cardinal; // zero-based
Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference)
Worksheet: TsBasicWorksheet; // Must be cast to TsWorksheet when used (avoids circular unit reference)
{ Status flags }
Flags: TsCellFlags;
{ Index of format record in the workbook's CellFormatList }
@ -874,6 +878,124 @@ type
TsStreamParam = (spClipboard, spWindowsClipboardHTML);
TsStreamParams = set of TsStreamParam;
{@@ Worksheet user interface options:
@param soShowGridLines Show or hide the grid lines in the spreadsheet
@param soShowHeaders Show or hide the column or row headers of the
spreadsheet
@param soHasFrozenPanes If set a number of rows and columns of the
spreadsheet is fixed and does not scroll. The number
is defined by LeftPaneWidth and TopPaneHeight.
@param soHidden Worksheet is hidden.
@param soProtected Worksheet is protected
@param soPanesProtection Panes are locked due to workbook protection }
TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes, soHidden,
soProtected, soPanesProtection);
{@@ Set of user interface options
@ see TsSheetOption }
TsSheetOptions = set of TsSheetOption;
{@@ Option flags for the workbook
@param boVirtualMode If in virtual mode date are not taken from cells
when a spreadsheet is written to file, but are
provided by means of the event OnWriteCellData.
Similarly, when data are read they are not added
as cells but passed the the event OnReadCellData;
@param boBufStream When this option is set a buffered stream is used
for writing (a memory stream swapping to disk) or
reading (a file stream pre-reading chunks of data
to memory)
@param boFileStream Uses file streams and temporary files during
reading and writing. Lowest memory consumptions,
but slow.
@param boAutoCalc Automatically recalculate formulas whenever a
cell value changes.
@param boCalcBeforeSaving Calculates formulas before saving the file.
Otherwise there are no results when the file is
loaded back by fpspreadsheet.
@param boReadFormulas Allows to turn off reading of rpn formulas; this
is a precaution since formulas not correctly
implemented by fpspreadsheet could crash the
reading operation.
@param boWriteZoomfactor Instructs the writer to write the current zoom
factors of the worksheets to file.
@param boAbortReadOnFormulaError Aborts reading if a formula error is
encountered
@param boIgnoreFormulas Formulas are not checked and not calculated.
Cannot be used for biff formats. }
TsWorkbookOption = (boVirtualMode, boBufStream, boFileStream,
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor,
boAbortReadOnFormulaError, boIgnoreFormulas);
{@@ Set of option flags for the workbook }
TsWorkbookOptions = set of TsWorkbookOption;
{@@ Basic worksheet class to avoid circular unit references. It has only those
properties and methods which do not require any other unit than fpstypes. }
TsBasicWorksheet = class
protected
FName: String; // Name of the worksheet (displayed at the tab)
FOptions: TsSheetOptions;
FProtection: TsWorksheetProtections;
procedure SetName(const AName: String); virtual; abstract;
public
constructor Create;
function HasHyperlink(ACell: PCell): Boolean;
function IsProtected: Boolean;
{@@ Name of the sheet. In the popular spreadsheet applications this is
displayed in the tab of the sheet. }
property Name: string read FName write SetName;
{@@ Parameters controlling visibility of grid lines and row/column headers,
usage of frozen panes etc. }
property Options: TsSheetOptions read FOptions write FOptions;
{@@ Worksheet protection options }
property Protection: TsWorksheetProtections read FProtection write FProtection;
end;
{@@ Basic worksheet class to avoid circular unit references. It contains only
those properties and methods which do not require any other unit than
fpstypes. }
TsBasicWorkbook = class
private
FLog: TStringList;
function GetErrorMsg: String;
protected
FFileName: String;
FFormatID: TsSpreadFormatID;
FOptions: TsWorkbookOptions;
FProtection: TsWorkbookProtections;
FUnits: TsSizeUnits;
public
{@@ A copy of SysUtil's DefaultFormatSettings (converted to UTF8) to provide
some kind of localization to some formatting strings.
Can be modified before loading/writing files }
FormatSettings: TFormatSettings;
constructor Create;
destructor Destroy; override;
{ Error messages }
procedure AddErrorMsg(const AMsg: String); overload;
procedure AddErrorMsg(const AMsg: String; const Args: array of const); overload;
procedure ClearErrorList; inline;
{ Protection }
function IsProtected: Boolean;
{@@ Retrieves error messages collected during reading/writing }
property ErrorMsg: String read GetErrorMsg;
{@@ Identifies the file format which was detected when reading the file }
property FileFormatID: TsSpreadFormatID read FFormatID;
{@@ Filename of the saved workbook }
property FileName: String read FFileName;
{@@ Option flags for the workbook - see boXXXX declarations }
property Options: TsWorkbookOptions read FOptions write FOptions;
{@@ Workbook protection flags }
property Protection: TsWorkbookProtections read FProtection write FProtection;
{@@ Units of row heights and column widths }
property Units: TsSizeUnits read FUnits;
end;
{@@ Exception types for fpspreadsheet }
EFpSpreadsheet = class(Exception);
EFpSpreadsheetReader = class(EFpSpreadsheet);
@ -892,6 +1014,10 @@ const
HEADER_FOOTER_INDEX_EVEN = 2;
HEADER_FOOTER_INDEX_ALL = 1;
var
{@@ FPC format settings for which all strings have been converted to UTF8 }
UTF8FormatSettings: TFormatSettings;
implementation
@ -914,5 +1040,125 @@ begin
Position := AFont.Position;
end;
{-------------------------------------------------------------------------------
sBasicWorksheet
-------------------------------------------------------------------------------}
constructor TsBasicWorksheet.Create;
begin
inherited;
FProtection := DEFAULT_SHEET_PROTECTION;
end;
{@@ ----------------------------------------------------------------------------
Checks whether the specified cell contains a hyperlink
-------------------------------------------------------------------------------}
function TsBasicWorksheet.HasHyperlink(ACell: PCell): Boolean;
begin
Result := (ACell <> nil) and (cfHyperlink in ACell^.Flags);
end;
{@@ ----------------------------------------------------------------------------
Returns whether the worksheet is protected
-------------------------------------------------------------------------------}
function TsBasicWorksheet.IsProtected: Boolean;
begin
Result := soProtected in FOptions;
end;
{-------------------------------------------------------------------------------
TsBasicWorkbook
-------------------------------------------------------------------------------}
constructor TsBasicWorkbook.Create;
begin
inherited;
FormatSettings := UTF8FormatSettings;
FUnits := suMillimeters; // Units for column width and row height
FFormatID := sfidUnknown;
FLog := TStringList.Create;
FProtection := [];
end;
destructor TsBasicWorkbook.Destroy;
begin
FLog.Free;
inherited;
end;
{@@ ----------------------------------------------------------------------------
Adds a (simple) error message to an internal list
@param AMsg Error text to be stored in the list
-------------------------------------------------------------------------------}
procedure TsBasicWorkbook.AddErrorMsg(const AMsg: String);
begin
FLog.Add(AMsg);
end;
{@@ ----------------------------------------------------------------------------
Adds an error message composed by means of format codes to an internal list
@param AMsg Error text to be stored in the list
@param Args Array of arguments to be used by the Format() function
-------------------------------------------------------------------------------}
procedure TsBasicWorkbook.AddErrorMsg(const AMsg: String;
const Args: Array of const);
begin
FLog.Add(Format(AMsg, Args));
end;
{@@ ----------------------------------------------------------------------------
Clears the internal error message list
-------------------------------------------------------------------------------}
procedure TsBasicWorkbook.ClearErrorList;
begin
FLog.Clear;
end;
{@@ ----------------------------------------------------------------------------
Getter to retrieve the error messages collected during reading/writing
-------------------------------------------------------------------------------}
function TsBasicWorkbook.GetErrorMsg: String;
begin
Result := FLog.Text;
end;
{@@ ----------------------------------------------------------------------------
Returns whether the workbook is protected
-------------------------------------------------------------------------------}
function TsBasicWorkbook.IsProtected: Boolean;
begin
Result := (FProtection <> []);
end;
{@@ ----------------------------------------------------------------------------
Creates a FPC format settings record in which all strings are encoded as
UTF8.
-------------------------------------------------------------------------------}
procedure InitUTF8FormatSettings;
// remove when available in LazUtils
var
i: Integer;
begin
UTF8FormatSettings := DefaultFormatSettings;
UTF8FormatSettings.CurrencyString := AnsiToUTF8(DefaultFormatSettings.CurrencyString);
for i:=1 to 12 do begin
UTF8FormatSettings.LongMonthNames[i] := AnsiToUTF8(DefaultFormatSettings.LongMonthNames[i]);
UTF8FormatSettings.ShortMonthNames[i] := AnsiToUTF8(DefaultFormatSettings.ShortMonthNames[i]);
end;
for i:=1 to 7 do begin
UTF8FormatSettings.LongDayNames[i] := AnsiToUTF8(DefaultFormatSettings.LongDayNames[i]);
UTF8FormatSettings.ShortDayNames[i] := AnsiToUTF8(DefaultFormatSettings.ShortDayNames[i]);
end;
end;
initialization
InitUTF8FormatSettings;
end.

View File

@ -18,7 +18,7 @@ unit fpsutils;
interface
uses
Classes, SysUtils, TypInfo, //StrUtils,
Classes, SysUtils, TypInfo,
fpstypes;
// Exported types
@ -194,7 +194,8 @@ procedure SplitHyperlink(AValue: String; out ATarget, ABookmark: String);
procedure FixHyperlinkPathDelims(var ATarget: String);
procedure InitCell(out ACell: TCell); overload;
procedure InitCell(AWorksheet: Pointer; ARow, ACol: Cardinal; out ACell: TCell); overload;
procedure InitCell(AWorksheet: TsBasicWorksheet; ARow, ACol: Cardinal;
out ACell: TCell); overload;
procedure InitCryptoInfo(out AValue: TsCryptoInfo);
procedure InitFormatRecord(out AValue: TsCellFormat);
procedure InitImageRecord(out AValue: TsImage; ARow, ACol: Cardinal;
@ -210,6 +211,8 @@ function SameFont(AFont: TsFont; AFontName: String; AFontSize: Single;
function Range(ARow1, ACol1, ARow2, ACol2: Cardinal): TsCellRange;
function GetFontAsString(AFont: TsFont): String;
//function GetUniqueTempDir(Global: Boolean): String;
procedure AppendToStream(AStream: TStream; const AString: String); inline; overload;
@ -226,9 +229,6 @@ var
for conversion of distances to pixels}
ScreenPixelsPerInch: Integer = 96;
{@@ FPC format settings for which all strings have been converted to UTF8 }
UTF8FormatSettings: TFormatSettings;
implementation
@ -2348,7 +2348,8 @@ end;
@param ACol Column index of the new cell
@return New cell record with row and column fields preset to passed values.
-------------------------------------------------------------------------------}
procedure InitCell(AWorksheet: Pointer; ARow, ACol: Cardinal; out ACell: TCell);
procedure InitCell(AWorksheet: TsbasicWorksheet;
ARow, ACol: Cardinal; out ACell: TCell);
begin
InitCell(ACell);
ACell.Worksheet := AWorksheet;
@ -2552,6 +2553,26 @@ begin
end;
end;
{@@ ----------------------------------------------------------------------------
Combines the relevant font properties into a string
-------------------------------------------------------------------------------}
function GetFontAsString(AFont: TsFont): String;
begin
if AFont = nil then
Result := ''
else begin
Result := Format('%s; size %.1g; %s', [
AFont.FontName, AFont.Size, GetColorName(AFont.Color)]);
if (fssBold in AFont.Style) then Result := Result + '; bold';
if (fssItalic in AFont.Style) then Result := Result + '; italic';
if (fssUnderline in AFont.Style) then Result := Result + '; underline';
if (fssStrikeout in AFont.Style) then result := Result + '; strikeout';
if AFont.Position = fpSubscript then Result := Result + '; subscript';
if AFont.Position = fpSuperscript then Result := Result + '; superscript';
end;
end;
(*
{@@ ----------------------------------------------------------------------------
Constructs a string of length "Len" containing random uppercase characters
@ -2838,30 +2859,5 @@ end;
{$POP}
{@@ ----------------------------------------------------------------------------
Creates a FPC format settings record in which all strings are encoded as
UTF8.
-------------------------------------------------------------------------------}
procedure InitUTF8FormatSettings;
// remove when available in LazUtils
var
i: Integer;
begin
UTF8FormatSettings := DefaultFormatSettings;
UTF8FormatSettings.CurrencyString := AnsiToUTF8(DefaultFormatSettings.CurrencyString);
for i:=1 to 12 do begin
UTF8FormatSettings.LongMonthNames[i] := AnsiToUTF8(DefaultFormatSettings.LongMonthNames[i]);
UTF8FormatSettings.ShortMonthNames[i] := AnsiToUTF8(DefaultFormatSettings.ShortMonthNames[i]);
end;
for i:=1 to 7 do begin
UTF8FormatSettings.LongDayNames[i] := AnsiToUTF8(DefaultFormatSettings.LongDayNames[i]);
UTF8FormatSettings.ShortDayNames[i] := AnsiToUTF8(DefaultFormatSettings.ShortDayNames[i]);
end;
end;
initialization
InitUTF8FormatSettings;
end.

View File

@ -15,7 +15,7 @@ uses
{$ELSE}
fpszipper,
{$ENDIF}
fpSpreadsheet, fpsreaderwriter;
fpstypes, fpsreaderwriter;
type
TsSpreadXMLReader = class(TsCustomSpreadReader)
@ -53,7 +53,8 @@ procedure UnzipFile(AZipFileName, AZippedFile, ADestFolder: String);
function UnzipToStream(AZipStream: TStream; const AZippedFile: String;
ADestStream: TStream): Boolean;
function CreateTempStream(AWorkbook: TsWorkbook; AFileNameBase: String): TStream;
function CreateTempStream(AWorkbook: TsBasicWorkbook;
AFileNameBase: String): TStream;
procedure DestroyTempStream(AStream: TStream);
@ -379,7 +380,8 @@ end;
In the latter two cases a filename mask is provided to create a temporary
filename around this mask.
-------------------------------------------------------------------------------}
function CreateTempStream(AWorkbook: TsWorkbook; AFilenameBase: String): TStream;
function CreateTempStream(AWorkbook: TsBasicWorkbook;
AFilenameBase: String): TStream;
begin
if boFileStream in AWorkbook.Options then
Result := TFileStream.Create(GetTempFileName('', AFilenameBase), fmCreate)

View File

@ -31,7 +31,7 @@ interface
uses
Classes, SysUtils,
fpimage, fgl, lconvencoding,
fpsTypes, fpSpreadsheet, fpsUtils, fpsReaderWriter;
fpsTypes, fpsUtils, fpsReaderWriter;
type
@ -52,10 +52,10 @@ type
TWikiTableTokenizer = class
private
FWorkbook: TsWorkbook;
FWorkbook: TsBasicWorkbook;
public
Tokens: TWikiTableTokenList;
constructor Create(AWorkbook: TsWorkbook); virtual;
constructor Create(AWorkbook: TsBasicWorkbook); virtual;
destructor Destroy; override;
procedure Clear;
function AddToken(AValue: string): TWikiTableToken;
@ -79,7 +79,7 @@ type
TsWikiTable_PipesReader = class(TsWikiTableReader)
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
end;
@ -98,7 +98,7 @@ type
TsWikiTable_WikiMediaWriter = class(TsWikiTableWriter)
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
end;
@ -110,12 +110,12 @@ var
implementation
uses
fpsStrings, fpsXMLCommon;
fpsStrings, fpsXMLCommon, fpSpreadsheet;
{ TWikiTableTokenizer }
constructor TWikiTableTokenizer.Create(AWorkbook: TsWorkbook);
constructor TWikiTableTokenizer.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
@ -321,7 +321,7 @@ var
lLineSplitter: TWikiTableTokenizer;
lCurToken: TWikiTableToken;
begin
FWorksheet := FWorkbook.AddWorksheet('Table', true);
FWorksheet := (FWorkbook as TsWorkbook).AddWorksheet('Table', true);
lLineSplitter := TWikiTableTokenizer.Create(FWorkbook);
try
for i := 0 to AStrings.Count-1 do
@ -331,11 +331,11 @@ begin
for j := 0 to lLineSplitter.Tokens.Count-1 do
begin
lCurToken := lLineSplitter.Tokens[j];
FWorksheet.WriteText(i, j, lCurToken.Value);
(FWorksheet as TsWorksheet).WriteText(i, j, lCurToken.Value);
if lCurToken.Bold then
FWorksheet.WriteFontStyle(i, j, [fssBold]);
(FWorksheet as TsWorksheet).WriteFontStyle(i, j, [fssBold]);
if lCurToken.UseBackgroundColor then
FWorksheet.WriteBackgroundColor(i, j, lCurToken.BackgroundColor);
(FWorksheet as TsWorksheet).WriteBackgroundColor(i, j, lCurToken.BackgroundColor);
end;
end;
finally
@ -346,7 +346,7 @@ end;
{ TsWikiTable_PipesReader }
constructor TsWikiTable_PipesReader.Create(AWorkbook: TsWorkbook);
constructor TsWikiTable_PipesReader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
SubFormat := sfWikiTable_Pipes;
@ -420,25 +420,27 @@ var
borders: TsCellBorders;
fs: TFormatSettings;
fmt: PsCellFormat;
sheet: TsWorksheet;
begin
FWorksheet := Workbook.GetFirstWorksheet();
FWorksheet.UpdateCaches;
FWorksheet := (Workbook as TsWorkbook).GetFirstWorksheet();
sheet := FWorksheet as TsWorksheet;
sheet.UpdateCaches;
fs := FWorksheet.FormatSettings;
fs := sheet.FormatSettings;
fs.DecimalSeparator := '.';
fs.ThousandSeparator := ',';
AStrings.Add('<!-- generated by fpspreadsheet -->');
// Show/hide grid lines
if soShowGridLines in FWorksheet.Options then
if soShowGridLines in sheet.Options then
lCurStr := '{| class="wikitable"' // sortable"'
else
lCurStr := '{| border="0" cellpadding="2"';
// Default font
lStyleStr := '';
lFont := FWorkbook.GetDefaultFont;
lFont := (FWorkbook as TsWorkbook).GetDefaultFont;
if lFont.FontName <> DEFAULT_FONTNAME then
lStyleStr := lStyleStr + Format('font-family:%s;', [lFont.FontName]);
if fssBold in lFont.Style then
@ -454,16 +456,16 @@ begin
AStrings.Add(lCurStr);
for i := 0 to FWorksheet.GetLastRowIndex() do
for i := 0 to sheet.GetLastRowIndex() do
begin
AStrings.Add('|-');
//lRow := FWorksheet.FindRow(i);
//lRow := sheet.FindRow(i);
for j := 0 to FWorksheet.GetLastColIndex do
for j := 0 to sheet.GetLastColIndex do
begin
lCell := FWorksheet.FindCell(i, j);
//lCol := FWorksheet.FindCol(j);
lCurStr := FWorksheet.ReadAsText(lCell, fs);
lCell := sheet.FindCell(i, j);
//lCol := sheet.FindCol(j);
lCurStr := sheet.ReadAsText(lCell, fs);
// Check for invalid characters
if not ValidXMLText(lCurStr, false) then
@ -480,32 +482,32 @@ begin
lRowHeightStr := '';
// Format
fmt := FWorksheet.GetPointerToEffectiveCellFormat(i, j);
fmt := sheet.GetPointerToEffectiveCellFormat(i, j);
if fmt <> nil then
lCurUsedFormatting := fmt^.UsedFormattingFields else
lCurUsedFormatting := [];
// Row header
isHeader := (soHasFrozenPanes in FWorksheet.Options) and
((i < cardinal(FWorksheet.TopPaneHeight)) or (j < cardinal(FWorksheet.LeftPaneWidth)));
((i < cardinal(sheet.TopPaneHeight)) or (j < cardinal(sheet.LeftPaneWidth)));
// Column width (to be considered in first row)
if i = 0 then
lColWidthStr := Format(' width="%.0fpt"', [
FWorkbook.ConvertUnits(FWorksheet.GetColWidth(i, suChars), FWorkbook.Units, suPoints)
(FWorkbook as TsWorkbook).ConvertUnits(sheet.GetColWidth(i, suChars), FWorkbook.Units, suPoints)
]);
// Row height (to be considered in first column)
if j = 0 then
lRowHeightStr := Format(' height="%.0fpt"', [
FWorkbook.ConvertUnits(FWorksheet.GetRowHeight(j, suLines), FWorkbook.Units, suPoints)
(FWorkbook as TsWorkbook).ConvertUnits(sheet.GetRowHeight(j, suLines), FWorkbook.Units, suPoints)
]);
// Font
lFont := FWorkbook.GetDefaultFont;
lFont := (FWorkbook as TsWorkbook).GetDefaultFont;
if (uffFont in lCurUsedFormatting) and (fmt <> nil) then
begin
lFont := FWorkbook.GetFont(fmt^.FontIndex);
lFont := (FWorkbook as TsWorkbook).GetFont(fmt^.FontIndex);
if fssBold in lFont.Style then lCurStr := '<b>' + lCurStr + '</b>';
if fssItalic in lFont.Style then lCurStr := '<i>' + lCurStr + '</i>';
if fssUnderline in lFont.Style then lCurStr := '<u>' + lCurStr + '</u>';
@ -570,9 +572,9 @@ begin
end;
// Merged cells
if FWorksheet.IsMerged(lCell) then
if sheet.IsMerged(lCell) then
begin
FWorksheet.FindMergedRange(lCell, r1, c1, r2, c2);
sheet.FindMergedRange(lCell, r1, c1, r2, c2);
if (i = r1) and (j = c1) then
begin
if r1 < r2 then
@ -619,7 +621,7 @@ end;
{ TsWikiTable_WikiMediaWriter }
constructor TsWikiTable_WikiMediaWriter.Create(AWorkbook: TsWorkbook);
constructor TsWikiTable_WikiMediaWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
SubFormat := sfWikiTable_WikiMedia;

View File

@ -34,7 +34,7 @@ interface
uses
Classes, SysUtils, lconvencoding,
fpsTypes, fpspreadsheet, fpsUtils, xlscommon;
fpsTypes, fpsUtils, xlscommon;
const
BIFF2_MAX_PALETTE_SIZE = 8;
@ -75,7 +75,7 @@ type
procedure ReadWindow2(AStream: TStream); override;
procedure ReadXF(AStream: TStream);
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
{ General reading methods }
procedure ReadFromStream(AStream: TStream; APassword: String = '';
AParams: TsStreamParams = []); override;
@ -100,8 +100,8 @@ type
procedure WriteColumnDefault(AStream: TStream;
AFirstColIndex, ALastColIndex: Word; AFormatIndex: Integer);
procedure WriteColumnDefaults(AStream: TStream);
procedure WriteDefaultRowHeight(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDefaultRowHeight(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFontIndex: Integer);
procedure WriteFonts(AStream: TStream);
@ -111,7 +111,7 @@ type
procedure AddBuiltinNumFormats; override;
function FunctionSupported(AExcelCode: Integer;
const AFuncName: String): Boolean; override;
procedure PopulatePalette(AWorkbook: TsWorkbook); override;
procedure PopulatePalette(AWorkbook: TsbasicWorkbook); override;
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
ACell: PCell); override;
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
@ -126,7 +126,7 @@ type
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: double; ACell: PCell); override;
procedure WritePASSWORD(AStream: TStream);
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
procedure WriteRow(AStream: TStream; ASheet: TsBasicWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); override;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal;
AFormula: TsRPNFormula; ACell: PCell); override;
@ -134,11 +134,11 @@ type
procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); override;
procedure WriteStringRecord(AStream: TStream; AString: String); override;
procedure WriteWindow1(AStream: TStream); override;
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
procedure WriteWindow2(AStream: TStream; ASheet: TsBasicWorksheet);
procedure WriteXF(AStream: TStream; AFormatRecord: PsCellFormat;
XFType_Prot: Byte = 0); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsbasicWorkbook); override;
procedure WriteToStream(AStream: TStream; AParams: TsStreamParams = []); override;
end;
@ -180,7 +180,7 @@ uses
LazLogger,
{$ENDIF}
Math,
fpsStrings, fpsReaderWriter, fpsPalette, fpsNumFormat;
fpsStrings, fpspreadsheet, fpsReaderWriter, fpsPalette, fpsNumFormat;
const
{ Excel record IDs }
@ -320,7 +320,7 @@ end;
{ TsSpreadBIFF2Reader }
{------------------------------------------------------------------------------}
constructor TsSpreadBIFF2Reader.Create(AWorkbook: TsWorkbook);
constructor TsSpreadBIFF2Reader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
InitBiff2Limitations(FLimitations);
@ -342,10 +342,10 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := TsWorksheet(FWorksheet).AddCell(ARow, ACol);
ApplyCellFormatting(cell, XF);
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
{@@ ----------------------------------------------------------------------------
@ -358,7 +358,10 @@ var
r, c: Cardinal;
xf: Word;
cell: PCell;
sheet: TsWorksheet;
begin
sheet := FWorksheet as TsWorksheet;
{ Read entire record, starting at Row }
rec.Row := 0; // to silence the compiler...
AStream.ReadBuffer(rec.Row, SizeOf(TBIFF2_BoolErrRecord) - 2*SizeOf(Word));
@ -372,19 +375,19 @@ begin
InitCell(FWorksheet, r, c, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(r, c);
cell := sheet.AddCell(r, c);
{ Retrieve boolean or error value depending on the "ValueType" }
case rec.ValueType of
0: FWorksheet.WriteBoolValue(cell, boolean(rec.BoolErrValue));
1: FWorksheet.WriteErrorValue(cell, ConvertFromExcelError(rec.BoolErrValue));
0: sheet.WriteBoolValue(cell, boolean(rec.BoolErrValue));
1: sheet.WriteErrorValue(cell, ConvertFromExcelError(rec.BoolErrValue));
end;
{ Apply formatting }
ApplyCellFormatting(cell, xf);
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, r, c, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, r, c, cell);
end;
procedure TsSpreadBIFF2Reader.ReadColumnDefault(AStream: TStream);
@ -398,7 +401,10 @@ var
nf: TsNumFormatParams;
nfs: String;
b: Byte;
book: TsWorkbook;
begin
book := TsWorkbook(FWorkbook);
{ Index of first column }
col1 := WordLEToN(AStream.ReadWord);
@ -417,9 +423,9 @@ begin
fontIndex := (attr2 and $C0) shr 6;
if fontIndex > 4 then dec(fontIndex); // Watch out for the nasty missing font #4...
fnt := TsFont(FFontList[fontIndex]);
fmt.FontIndex := Workbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
fmt.FontIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
if fmt.FontIndex = -1 then
fmt.FontIndex := Workbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
fmt.FontIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
if fmt.FontIndex > 0 then
Include(fmt.UsedFormattingFields, uffFont);
@ -427,8 +433,8 @@ begin
b := attr2 and $3F;
nfs := NumFormatList[b];
if nfs <> '' then begin
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
nf := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormatIndex := book.AddNumberFormat(nfs);
nf := book.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormat := nf.NumFormat;
fmt.NumberFormatStr := nf.NumFormatStr;
if fmt.NumberFormat <> nfGeneral then
@ -477,10 +483,10 @@ begin
// Add the decoded data to the format list
FCellFormatList.Add(fmt);
fmtIndex := FWorkbook.AddCellFormat(fmt);
fmtIndex := book.AddCellFormat(fmt);
for c := col1 to col2 do
FWorksheet.WriteColFormatIndex(c, fmtIndex);
TsWorksheet(FWorksheet).WriteColFormatIndex(c, fmtIndex);
end;
procedure TsSpreadBIFF2Reader.ReadColWidth(AStream: TStream);
@ -490,18 +496,21 @@ var
c, c1, c2: Cardinal;
w: Word;
colwidth: Single;
sheet: TsWorksheet;
begin
sheet := TsWorksheet(FWorksheet);
// read column start and end index of column range
c1 := AStream.ReadByte;
c2 := AStream.ReadByte;
// read col width in 1/256 of the width of "0" character
w := WordLEToN(AStream.ReadWord);
// calculate width in units of "characters"
colwidth := FWorkbook.ConvertUnits(w / 256, suChars, FWorkbook.Units);
colwidth := (FWorkbook as TsWorkbook).ConvertUnits(w / 256, suChars, FWorkbook.Units);
// assign width to columns, but only if different from default column width.
if not SameValue(colwidth, FWorksheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then
if not SameValue(colwidth, sheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then
for c := c1 to c2 do
FWorksheet.WriteColWidth(c, colwidth, FWorkbook.Units);
sheet.WriteColWidth(c, colwidth, FWorkbook.Units);
end;
procedure TsSpreadBIFF2Reader.ReadDefRowHeight(AStream: TStream);
@ -511,12 +520,7 @@ var
begin
hw := WordLEToN(AStream.ReadWord);
h := TwipsToPts(hw and $7FFF);
FWorksheet.WriteDefaultRowHeight(h, suPoints);
{
h := TwipsToPts(hw and $8000) / FWorkbook.GetDefaultFontSize;
if h > ROW_HEIGHT_CORRECTION then
FWorksheet.DefaultRowHeight := h - ROW_HEIGHT_CORRECTION;
}
(FWorksheet as TsWorksheet).WriteDefaultRowHeight(h, suPoints);
end;
procedure TsSpreadBIFF2Reader.ReadFONT(AStream: TStream);
@ -553,7 +557,7 @@ begin
FFontList.Add(FFont);
if isDefaultFont then
Workbook.SetDefaultFont(FFont.FontName, FFont.Size);
TsWorkbook(FWorkbook).SetDefaultFont(FFont.FontName, FFont.Size);
end;
procedure TsSpreadBIFF2Reader.ReadFONTCOLOR(AStream: TStream);
@ -606,7 +610,7 @@ begin
BIFF2EOF := False;
{ In BIFF2 files there is only one worksheet, let's create it }
FWorksheet := FWorkbook.AddWorksheet('Sheet', true);
FWorksheet := TsWorkbook(FWorkbook).AddWorksheet('Sheet', true);
{ Read all records in a loop }
BOFFound := false;
@ -685,7 +689,10 @@ var
nfs: String;
err: TsErrorValue;
cell: PCell;
sheet: TsWorksheet;
begin
sheet := TsWorksheet(FWorksheet);
{ BIFF Record row/column/style }
ReadRowColXF(AStream, ARow, ACol, XF);
@ -701,7 +708,7 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := sheet.AddCell(ARow, ACol);
// Now determine the type of the formula result
if (Data[6] = $FF) and (Data[7] = $FF) then
@ -709,7 +716,7 @@ begin
0: // String -> Value is found in next record (STRING)
FIncompleteCell := cell;
1: // Boolean value
FWorksheet.WriteBoolValue(cell, Data[2] = 1);
sheet.WriteBoolValue(cell, Data[2] = 1);
2: begin // Error value
case Data[2] of
ERR_INTERSECTION_EMPTY : err := errEmptyIntersection;
@ -720,10 +727,10 @@ begin
ERR_OVERFLOW : err := errOverflow;
ERR_ARG_ERROR : err := errArgError;
end;
FWorksheet.WriteErrorValue(cell, err);
sheet.WriteErrorValue(cell, err);
end;
3: // Empty cell
FWorksheet.WriteBlank(cell);
sheet.WriteBlank(cell);
end
else
begin
@ -733,23 +740,23 @@ begin
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nfs);
if IsDateTime(formulaResult, nf, nfs, dt) then
FWorksheet.WriteDateTime(cell, dt, nf, nfs)
sheet.WriteDateTime(cell, dt, nf, nfs)
else
FWorksheet.WriteNumber(cell, formulaResult, nf, nfs);
sheet.WriteNumber(cell, formulaResult, nf, nfs);
end;
{ Formula token array }
if (boReadFormulas in FWorkbook.Options) then
begin
ok := ReadRPNTokenArray(AStream, cell);
if not ok then FWorksheet.WriteErrorValue(cell, errFormulaNotSupported);
if not ok then sheet.WriteErrorValue(cell, errFormulaNotSupported);
end;
{ Apply formatting to cell }
ApplyCellFormatting(cell, XF);
if FIsVirtualMode and (cell <> FIncompleteCell) then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
procedure TsSpreadBIFF2Reader.ReadLabel(AStream: TStream);
@ -761,7 +768,10 @@ var
ansiStr: ansistring;
valueStr: UTF8String;
cell: PCell;
sheet: TsWorksheet;
begin
sheet := FWorksheet as TsWorksheet;
{ Read entire record, starting at Row, except for string data }
rec.Row := 0; // to silence the compiler...
AStream.ReadBuffer(rec.Row, SizeOf(TBIFF2_LabelRecord) - 2*SizeOf(Word));
@ -777,33 +787,20 @@ begin
{ Save the data }
valueStr := ConvertEncoding(ansiStr, FCodePage, encodingUTF8);
{
case WorkBookEncoding of
seLatin2: AStrValue := CP1250ToUTF8(AValue);
seCyrillic: AStrValue := CP1251ToUTF8(AValue);
seGreek: AStrValue := CP1253ToUTF8(AValue);
seTurkish: AStrValue := CP1254ToUTF8(AValue);
seHebrew: AStrValue := CP1255ToUTF8(AValue);
seArabic: AStrValue := CP1256ToUTF8(AValue);
else
// Latin 1 is the default
AStrValue := CP1252ToUTF8(AValue);
end;
}
{ Create cell }
if FIsVirtualMode then begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
FWorksheet.WriteText(cell, valueStr);
cell := sheet.AddCell(ARow, ACol);
sheet.WriteText(cell, valueStr);
{ Apply formatting to cell }
ApplyCellFormatting(cell, XF);
if FIsVirtualMode and (cell <> FIncompleteCell) then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
procedure TsSpreadBIFF2Reader.ReadNumber(AStream: TStream);
@ -816,7 +813,10 @@ var
nf: TsNumberFormat;
nfs: String;
cell: PCell;
sheet: TsWorksheet;
begin
sheet := FWorksheet as TsWorksheet;
{ Read entire record, starting at Row }
rec.Row := 0; // to silence the compiler...
AStream.ReadBuffer(rec.Row, SizeOf(TBIFF2_NumberRecord) - 2*SizeOf(Word));
@ -831,30 +831,33 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := sheet.AddCell(ARow, ACol);
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nfs);
if IsDateTime(value, nf, nfs, dt) then
FWorksheet.WriteDateTime(cell, dt, nf, nfs)
sheet.WriteDateTime(cell, dt, nf, nfs)
else
FWorksheet.WriteNumber(cell, value, nf, nfs);
sheet.WriteNumber(cell, value, nf, nfs);
{ Apply formatting to cell }
ApplyCellFormatting(cell, XF);
if FIsVirtualMode and (cell <> FIncompleteCell) then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
procedure TsSpreadBIFF2Reader.ReadInteger(AStream: TStream);
var
sheet: TsWorksheet;
ARow, ACol: Cardinal;
XF: Word;
AWord : Word = 0;
cell: PCell;
rec: TBIFF2_IntegerRecord;
begin
sheet := FWorksheet as TsWorksheet;
{ Read record into buffer }
rec.Row := 0; // to silence the comiler...
AStream.ReadBuffer(rec.Row, SizeOf(TBIFF2_NumberRecord) - 2*SizeOf(Word));
@ -870,16 +873,16 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := sheet.AddCell(ARow, ACol);
{ Save the data }
FWorksheet.WriteNumber(cell, AWord);
sheet.WriteNumber(cell, AWord);
{ Apply formatting to cell }
ApplyCellFormatting(cell, XF);
if FIsVirtualMode and (cell <> FIncompleteCell) then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
TsWorkbook(FWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
{@@ ----------------------------------------------------------------------------
@ -911,14 +914,14 @@ begin
// Use the same password for workbook and worksheet protection because
// BIFF2 can have only a single sheet.
FWorkbook.CryptoInfo := cinfo;
FWorksheet.CryptoInfo := cinfo;
(FWorkbook as TsWorkbook).CryptoInfo := cinfo;
(FWorksheet as TsWorksheet).CryptoInfo := cinfo;
end;
procedure TsSpreadBIFF2Reader.ReadPROTECT(AStream: TStream);
begin
inherited ReadPROTECT(AStream);
FWorksheet.Protect(Workbook.IsProtected);
(FWorksheet as TsWorksheet).Protect(Workbook.IsProtected);
end;
{@@ ----------------------------------------------------------------------------
@ -966,13 +969,18 @@ var
defRowHeight: Single;
containsXF: Boolean;
xf: Word;
book: TsWorkbook;
sheet: TsWorksheet;
begin
book := FWorkbook as TsWorkbook;
sheet := FWorksheet as TsWorksheet;
rowRec.RowIndex := 0; // to silence the compiler...
AStream.ReadBuffer(rowrec, SizeOf(TRowRecord));
h := WordLEToN(rowrec.Height);
auto := h and $8000 <> 0;
rowheight := FWorkbook.ConvertUnits(TwipsToPts(h and $7FFF), suPoints, FWorkbook.Units);
defRowHeight := FWorksheet.ReadDefaultRowHeight(FWorkbook.Units);
rowheight := book.ConvertUnits(TwipsToPts(h and $7FFF), suPoints, FWorkbook.Units);
defRowHeight := sheet.ReadDefaultRowHeight(FWorkbook.Units);
containsXF := rowRec.ContainsXF = 1;
xf := WordLEToN(rowRec.XFIndex);
@ -982,7 +990,7 @@ begin
exit;
// Otherwise: create a row record
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex));
lRow := sheet.GetRow(WordLEToN(rowrec.RowIndex));
lRow^.Height := rowHeight;
if auto then
lRow^.RowHeightType := rhtAuto else
@ -1062,7 +1070,9 @@ begin
FIncompleteCell^.UTF8StringValue := ConvertEncoding(s, FCodePage, encodingUTF8);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
TsWorkbook(FWorkbook).OnReadCellData(FWorkbook,
FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell
);
end;
end;
FIncompleteCell := nil;
@ -1120,7 +1130,10 @@ var
nfs: String;
i: Integer;
fnt: TsFont;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
// Read entire xf record into buffer
InitFormatRecord(fmt);
fmt.ID := FCellFormatList.Count;
@ -1132,9 +1145,9 @@ begin
i := rec.FontIndex;
if i > 4 then dec(i); // Watch out for the nasty missing font #4...
fnt := TsFont(FFontList[i]);
fmt.FontIndex := Workbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
fmt.FontIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
if fmt.FontIndex = -1 then
fmt.FontIndex := Workbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
fmt.FontIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
if fmt.FontIndex > 0 then
Include(fmt.UsedFormattingFields, uffFont);
@ -1143,8 +1156,8 @@ begin
nfs := NumFormatList[b];
if nfs <> '' then
begin
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
nf := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormatIndex := book.AddNumberFormat(nfs);
nf := book.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormat := nf.NumFormat;
fmt.NumberFormatStr := nf.NumFormatStr;
if fmt.NumberFormat <> nfGeneral then
@ -1211,7 +1224,7 @@ end;
{ TsSpreadBIFF2Writer }
{------------------------------------------------------------------------------}
constructor TsSpreadBIFF2Writer.Create(AWorkbook: TsWorkbook);
constructor TsSpreadBIFF2Writer.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
@ -1252,7 +1265,7 @@ var
fmt: PsCellFormat;
fontIdx, formatIdx: Integer;
begin
fmt := Workbook.GetPointerToCellFormat(AFormatIndex);
fmt := (Workbook as TsWorkbook).GetPointerToCellFormat(AFormatIndex);
if fmt^.UsedFormattingFields = [] then begin
Attrib1 := 15 + MASK_XF_TYPE_PROT_LOCKED_BIFF2; // $40
@ -1308,7 +1321,7 @@ begin
AFormatIndex := 0;
if (AFormatRecord <> nil) and (uffNumberFormat in AFormatRecord^.UsedFormattingFields) then
begin
nfParams := Workbook.GetNumberFormat(AFormatRecord^.NumberFormatIndex);
nfParams := TsWorkbook(FWorkbook).GetNumberFormat(AFormatRecord^.NumberFormatIndex);
nfs := nfParams.NumFormatStr;
AFormatIndex := NumFormatList.IndexOf(nfs);
if AFormatIndex = -1 then AFormatIndex := 0;
@ -1323,7 +1336,7 @@ begin
end;
end;
procedure TsSpreadBIFF2Writer.PopulatePalette(AWorkbook: TsWorkbook);
procedure TsSpreadBIFF2Writer.PopulatePalette(AWorkbook: TsBasicWorkbook);
begin
FPalette.Clear;
FPalette.AddBuiltinColors(false);
@ -1353,7 +1366,7 @@ var
fmt: PsCellFormat;
w: Word;
begin
fmt := Workbook.GetPointerToCellFormat(AFormatIndex);
fmt := TsWorkbook(FWorkbook).GetPointerToCellFormat(AFormatIndex);
rec.XFIndex_Locked_Hidden := 0; // to silence the compiler...
FillChar(rec, SizeOf(rec), 0);
@ -1466,7 +1479,7 @@ var
lCol, lCol1: PCol;
lastcol: Integer;
begin
sheet := Workbook.GetFirstWorksheet;
sheet := TsWorkbook(FWorkbook).GetFirstWorksheet;
j := 0;
while (j < sheet.Cols.Count) do begin
lCol := PCol(sheet.Cols[j]);
@ -1518,9 +1531,9 @@ begin
{ Column width }
{ calculate width to be in units of 1/256 of pixel width of character "0" }
if ACol^.ColWidthType = cwtDefault then
w := FWorksheet.ReadDefaultColWidth(suChars)
w := TsWorksheet(FWorksheet).ReadDefaultColWidth(suChars)
else
w := FWorkbook.ConvertUnits(ACol^.Width, FWorkbook.Units, suChars);
w := tsWorkbook(FWorkbook).ConvertUnits(ACol^.Width, FWorkbook.Units, suChars);
rec.ColWidth := WordToLE(round(w*256));
{ Write out }
@ -1536,7 +1549,7 @@ var
sheet: TsWorksheet;
col: PCol;
begin
sheet := Workbook.GetFirstWorksheet;
sheet := TsWorkbook(FWorkbook).GetFirstWorksheet;
for j := 0 to sheet.Cols.Count-1 do begin
col := PCol(sheet.Cols[j]);
WriteColWidth(AStream, col);
@ -1547,7 +1560,7 @@ end;
Writes an Excel 2 DIMENSIONS record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF2Writer.WriteDimensions(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
firstRow, lastRow, firstCol, lastCol: Cardinal;
rec: TBIFF2_DimensionsRecord;
@ -1595,7 +1608,7 @@ var
begin
Unused(AParams);
FWorksheet := Workbook.GetWorksheetByIndex(FSheetIndex);
FWorksheet := (FWorkbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex);
if FWorksheet = nil then
raise EFPSpreadsheetWriter.Create(rsWorksheetNotFound1);
@ -1633,7 +1646,7 @@ begin
if (boVirtualMode in Workbook.Options) then
WriteVirtualCells(AStream, FWorksheet)
else
WriteCellsToStream(AStream, FWorksheet.Cells);
WriteCellsToStream(AStream, TsWorksheet(FWorksheet).Cells);
WriteWindow1(AStream);
// { -- currently not working
@ -1673,9 +1686,10 @@ end;
Writes an Excel 2 WINDOW2 record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF2Writer.WriteWindow2(AStream: TStream;
ASheet: TsWorksheet);
ASheet: TsBasicWorksheet);
var
b: Byte;
sheet: TsWorksheet absolute ASheet;
begin
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_WINDOW2));
@ -1685,17 +1699,17 @@ begin
AStream.WriteByte(0);
{ Show grid lines }
b := IfThen(soShowGridLines in ASheet.Options, 1, 0);
b := IfThen(soShowGridLines in sheet.Options, 1, 0);
AStream.WriteByte(b);
{ Show sheet headers }
b := IfThen(soShowHeaders in ASheet.Options, 1, 0);
b := IfThen(soShowHeaders in sheet.Options, 1, 0);
AStream.WriteByte(b);
{ Panes are frozen? }
b := 0;
if (soHasFrozenPanes in ASheet.Options) and
((ASheet.LeftPaneWidth > 0) or (ASheet.TopPaneHeight > 0))
if (soHasFrozenPanes in sheet.Options) and
((sheet.LeftPaneWidth > 0) or (sheet.TopPaneHeight > 0))
then
b := 1;
AStream.WriteByte(b);
@ -1820,7 +1834,7 @@ var
optn: Word;
font: TsFont;
begin
font := Workbook.GetFont(AFontIndex);
font := TsWorkbook(FWorkbook).GetFont(AFontIndex);
if font = nil then // this happens for FONT4 in case of BIFF
exit;
@ -1868,7 +1882,7 @@ procedure TsSpreadBiff2Writer.WriteFonts(AStream: TStream);
var
i: Integer;
begin
for i:=0 to Workbook.GetFontCount-1 do
for i:=0 to TsWorkbook(FWorkbook).GetFontCount-1 do
WriteFont(AStream, i);
end;
@ -2075,7 +2089,7 @@ end;
corresponding ROW record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF2Writer.WriteDefaultRowHeight(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
h: Single;
begin
@ -2085,7 +2099,7 @@ begin
{ Default height for unused rows, in twips = 1/20 of a point
Bits 0-14: Default height for unused rows, in twips
Bit 15 = 1: Row height not changed manually }
h := AWorksheet.ReadDefaultRowHeight(suPoints); // h is in points
h := TsWorksheet(AWorksheet).ReadDefaultRowHeight(suPoints); // h is in points
AStream.WriteWord(WordToLE(PtsToTwips(h))); // write as twips
end;
@ -2267,20 +2281,25 @@ procedure TsSpreadBIFF2Writer.WritePassword(AStream: TStream);
var
hash: Word;
hb, hs: LongInt;
book: TsWorkbook;
sheet: TsWorksheet;
begin
book := FWorkbook as TsWorkbook;
sheet := FWorksheet as TsWorksheet;
hb := 0;
if (Workbook.CryptoInfo.PasswordHash <> '') and
not TryStrToInt('$' + Workbook.CryptoInfo.PasswordHash, hb) then
if (book.CryptoInfo.PasswordHash <> '') and
not TryStrToInt('$' + book.CryptoInfo.PasswordHash, hb) then
begin
Workbook.AddErrorMsg(rsPasswordRemoved_NotValid);
book.AddErrorMsg(rsPasswordRemoved_NotValid);
exit;
end;
hs := 0;
if (FWorksheet.CryptoInfo.PasswordHash <> '') and
not TryStrToInt('$' + FWorksheet.CryptoInfo.PasswordHash, hs) then
if (sheet.CryptoInfo.PasswordHash <> '') and
not TryStrToInt('$' + sheet.CryptoInfo.PasswordHash, hs) then
begin
Workbook.AddErrorMsg(rsPasswordRemoved_NotValid);
book.AddErrorMsg(rsPasswordRemoved_NotValid);
exit;
end;
@ -2290,28 +2309,28 @@ begin
// Only workbook password set. Check for Excel algorithm.
if (hb <> 0) and (hs = 0) then begin
if Workbook.CryptoInfo.Algorithm <> caExcel then begin
Workbook.AddErrorMsg(rsPasswordRemoved_Excel);
if book.CryptoInfo.Algorithm <> caExcel then begin
book.AddErrorMsg(rsPasswordRemoved_Excel);
exit;
end;
hash := hb;
end else
// Only worksheet password set, check for Excel algorithm
if (hs <> 0) and (hb = 0) then begin
if FWorksheet.CryptoInfo.Algorithm <> caExcel then begin
Workbook.AddErrorMsg(rsPasswordRemoved_Excel);
if sheet.CryptoInfo.Algorithm <> caExcel then begin
book.AddErrorMsg(rsPasswordRemoved_Excel);
exit;
end;
hash := hs;
end else
if (hs <> hb) then begin
Workbook.AddErrorMsg(rsPasswordRemoved_BIFF2);
book.AddErrorMsg(rsPasswordRemoved_BIFF2);
exit;
end else
if (Workbook.CryptoInfo.Algorithm <> caExcel) or
(FWorksheet.CryptoInfo.Algorithm <> caExcel) then
if (book.CryptoInfo.Algorithm <> caExcel) or
(sheet.CryptoInfo.Algorithm <> caExcel) then
begin
Workbook.AddErrorMsg(rsPasswordRemoved_Excel);
book.AddErrorMsg(rsPasswordRemoved_Excel);
exit;
end else
hash := hs; // or hb -- they are equal here.
@ -2321,7 +2340,7 @@ begin
AStream.WriteWord(WordToLE(hash));
end;
procedure TsSpreadBIFF2Writer.WriteRow(AStream: TStream; ASheet: TsWorksheet;
procedure TsSpreadBIFF2Writer.WriteRow(AStream: TStream; ASheet: TsBasicWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow);
var
containsXF: Boolean;
@ -2329,6 +2348,8 @@ var
auto: Boolean;
w: Word;
xf: Word;
book: TsWorkbook;
sheet: TsWorksheet;
begin
if (ARowIndex >= FLimitations.MaxRowCount) or
(AFirstColIndex >= FLimitations.MaxColCount) or
@ -2336,6 +2357,9 @@ begin
then
exit;
book := FWorkbook as TsWorkbook;
sheet := ASheet as TsWorksheet;
containsXF := (ARow <> nil) and (ARow^.FormatIndex > 0);
{ BIFF record header }
@ -2353,12 +2377,12 @@ begin
auto := true;
{ Row height (in twips, 1/20 point) and info on custom row height }
if (ARow = nil) or (ARow^.RowHeightType = rhtDefault) then
rowheight := PtsToTwips(ASheet.ReadDefaultRowHeight(suPoints))
rowheight := PtsToTwips(sheet.ReadDefaultRowHeight(suPoints))
else
if (ARow^.Height = 0) then
rowheight := 0
else begin
rowheight := PtsToTwips(FWorkbook.ConvertUnits(ARow^.Height, FWorkbook.Units, suPoints));
rowheight := PtsToTwips(book.ConvertUnits(ARow^.Height, book.Units, suPoints));
auto := ARow^.RowHeightType <> rhtCustom;
end;
w := rowheight and $7FFF;

View File

@ -58,7 +58,7 @@ interface
uses
Classes, SysUtils, fpcanvas, lconvencoding,
fpsTypes, fpspreadsheet,
fpsTypes,
xlscommon,
{$ifdef USE_NEW_OLE}
fpolebasic,
@ -83,7 +83,7 @@ type
procedure ReadRPNSheetIndex(AStream: TStream; out ADocumentURL: String;
out ASheet1, ASheet2: Integer); override;
procedure ReadRSTRING(AStream: TStream);
procedure ReadStandardWidth(AStream: TStream; ASheet: TsWorksheet);
procedure ReadStandardWidth(AStream: TStream; ASheet: TsBasicWorksheet);
procedure ReadStringRecord(AStream: TStream); override;
procedure ReadWorkbookGlobals(AStream: TStream); override;
procedure ReadWorksheet(AStream: TStream); override;
@ -100,14 +100,14 @@ type
protected
function FunctionSupported(AExcelCode: Integer; const AFuncName: String): Boolean; override;
procedure InternalWriteToStream(AStream: TStream);
procedure PopulatePalette(AWorkbook: TsWorkbook); override;
procedure PopulatePalette(AWorkbook: TsBasicWorkbook); override;
{ Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; AWorkSheet: TsWorksheet): Int64;
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
function WriteBoundsheet(AStream: TStream; AWorkSheet: TsBasicWorksheet): Int64;
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsBasicWorksheet;
const AName: String; AIndexToREF, ASheetIndex: Word;
AKind: TsBIFFExternKind); override;
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream);
@ -117,16 +117,17 @@ type
procedure WriteIndex(AStream: TStream);
procedure WriteLABEL(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override;
procedure WriteLocalLinkTable(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteLocalLinkTable(AStream: TStream;
AWorksheet: TsBasicWorksheet);
function WriteRPNSheetIndex(AStream: TStream; ADocumentURL: String;
ASheet1, ASheet2: Integer): Word; override;
procedure WriteStringRecord(AStream: TStream; AString: String); override;
procedure WriteStyle(AStream: TStream);
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
procedure WriteWindow2(AStream: TStream; ASheet: TsBasicWorksheet);
procedure WriteXF(AStream: TStream; AFormatRecord: PsCellFormat;
XFType_Prot: Byte = 0); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False; AParams: TsStreamParams = []); override;
@ -228,7 +229,8 @@ uses
LazLogger,
{$ENDIF}
Math,
fpsStrings, fpsReaderWriter, fpsStreams, fpsPalette, fpsNumFormat, xlsconst;
fpsStrings, fpspreadsheet, fpsReaderWriter, fpsStreams,
fpsPalette, fpsNumFormat, xlsconst;
const
{ Excel record IDs }
@ -397,7 +399,9 @@ begin
SetLength(s, len);
AStream.ReadBuffer(s[1], len*SizeOf(AnsiChar));
sheet := FWorkbook.AddWorksheet(ConvertEncoding(s, FCodePage, EncodingUTF8), true);
sheet := (FWorkbook as TsWorkbook).AddWorksheet(
ConvertEncoding(s, FCodePage, EncodingUTF8), true
);
if sheetState <> 0 then
sheet.Options := sheet.Options + [soHidden];
end;
@ -513,7 +517,7 @@ var
RecordType: Word;
CurStreamPos: Int64;
begin
FWorksheet := FWorkbook.GetWorksheetByIndex(FCurSheetIndex);
FWorksheet := (FWorkbook as TsWorkbook).GetWorksheetByIndex(FCurSheetIndex);
while (not SectionEOF) do
begin
{ Read the record header }
@ -703,15 +707,20 @@ var
rtfRuns: TBiff5_RichTextFormattingRuns;
fntIndex: Integer;
fnt: TsFont;
sheet: TsWorksheet;
book: TsWorkbook;
begin
sheet := TsWorksheet(FWorksheet);
book := TsWorkbook(FWorkbook);
ReadRowColXF(AStream, ARow, ACol, XF);
{ Create cell }
if FIsVirtualMode then begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
InitCell(sheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := sheet.AddCell(ARow, ACol);
{ Read data string (Byte string with 16-bit length) }
L := WordLEtoN(AStream.ReadWord);
@ -720,7 +729,7 @@ begin
{ Save the data string to cell }
valueStr := ConvertEncoding(ansistr, FCodePage, encodingUTF8);
FWorksheet.WriteText(cell, valuestr);
sheet.WriteText(cell, valuestr);
{ Read rich-text formatting runs }
B := AStream.ReadByte;
@ -734,9 +743,9 @@ begin
// in the file is different from the font index stored by the workbook.
fntIndex := rtfRuns[i].FontIndex;
fnt := TsFont(FFontList[fntIndex]);
fntIndex := FWorkbook.FindFont(fnt.FontName, fnt.Size, fnt.Style,fnt.Color, fnt.Position);
fntIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style,fnt.Color, fnt.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
cell^.RichTextParams[i].FontIndex := fntIndex;
// Hyperlink index (not used here)
cell^.RichTextParams[i].HyperlinkIndex := -1;
@ -746,20 +755,21 @@ begin
ApplyCellFormatting(cell, XF);
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
book.OnReadCellData(Workbook, ARow, ACol, cell);
end;
{ Reads the default column width that is used when a bit in the GCW bit structure
is set for the corresponding column. The GCW is ignored here. The column
width read from the STANDARDWIDTH record overrides the one from the
DEFCOLWIDTH record. }
procedure TsSpreadBIFF5Reader.ReadStandardWidth(AStream: TStream; ASheet: TsWorksheet);
procedure TsSpreadBIFF5Reader.ReadStandardWidth(AStream: TStream;
ASheet: TsBasicWorksheet);
var
w: Word;
begin
// read width in 1/256 of the width of "0" character
w := WordLEToN(AStream.ReadWord);
ASheet.WriteDefaultRowHeight(w / 256, suChars);
(ASheet as TsWorksheet).WriteDefaultRowHeight(w / 256, suChars);
end;
{ Reads a STRING record which contains the result of string formula. }
@ -777,7 +787,9 @@ begin
FIncompletecell^.UTF8StringValue := ConvertEncoding(s, FCodePage, encodingUTF8);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
(Workbook as TsWorkbook).OnReadCellData(
Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell
);
end;
end;
FIncompleteCell := nil;
@ -823,8 +835,10 @@ var
dw: DWord;
fill: Word;
fs: TsFillStyle;
// fnt: TsFont;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
InitFormatRecord(fmt);
fmt.ID := FCellFormatList.Count;
@ -843,8 +857,8 @@ begin
// "General" (NumFormatIndex = 0) not stored in workbook's NumFormatList
if (rec.NumFormatIndex > 0) and not SameText(nfs, 'General') then
begin
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
nfParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormatIndex := book.AddNumberFormat(nfs);
nfParams := book.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormat := nfParams.NumFormat;
fmt.NumberFormatStr := nfs;
Include(fmt.UsedFormattingFields, uffNumberFormat);
@ -1090,7 +1104,7 @@ begin
if FFontList.Count = 4 then FFontList.Add(nil);
if isDefaultFont then
FWorkbook.SetDefaultFont(font.FontName, font.Size);
(FWorkbook as TsWorkbook).SetDefaultFont(font.FontName, font.Size);
end;
// Read the FORMAT record for formatting numerical data
@ -1149,17 +1163,17 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := (FWorksheet as TsWorksheet).AddCell(ARow, ACol);
{ Save the data }
valueStr := ConvertEncoding(ansistr, FCodePage, encodingUTF8);
FWorksheet.WriteText(cell, valueStr); //ISO_8859_1ToUTF8(ansistr));
(FWorksheet as TsWorksheet).WriteText(cell, valueStr); //ISO_8859_1ToUTF8(ansistr));
{ Add attributes }
ApplyCellFormatting(cell, XF);
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
(Workbook as TsWorkbook).OnReadCellData(Workbook, ARow, ACol, cell);
end;
@ -1167,7 +1181,7 @@ end;
{ TsSpreadBIFF5Writer }
{------------------------------------------------------------------------------}
constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsWorkbook);
constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
FDateMode := Excel5Settings.DateMode;
@ -1192,14 +1206,17 @@ var
sheetPos: array of Int64;
i: Integer;
pane: Byte;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
{ Write workbook globals }
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
WriteCODEPAGE(AStream, FCodePage);
WriteWindowProtect(AStream, bpLockWindows in Workbook.Protection);
WritePROTECT(AStream, bpLockStructure in Workbook.Protection);
WritePASSWORD(AStream, Workbook.CryptoInfo);
WritePASSWORD(AStream, book.CryptoInfo);
WriteGlobalLinkTable(AStream);
WriteDefinedNames(AStream);
WriteWINDOW1(AStream);
@ -1210,17 +1227,17 @@ begin
WriteStyle(AStream);
// A BOUNDSHEET for each worksheet
SetLength(sheetPos, Workbook.GetWorksheetCount);
for i := 0 to Workbook.GetWorksheetCount - 1 do
sheetPos[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i));
SetLength(sheetPos, book.GetWorksheetCount);
for i := 0 to book.GetWorksheetCount - 1 do
sheetPos[i] := WriteBoundsheet(AStream, book.GetWorksheetByIndex(i));
WriteEOF(AStream);
{ Write each worksheet }
for i := 0 to Workbook.GetWorksheetCount - 1 do
for i := 0 to book.GetWorksheetCount - 1 do
begin
FWorksheet := Workbook.GetWorksheetByIndex(i);
FWorksheet := book.GetWorksheetByIndex(i);
{ First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record }
@ -1255,7 +1272,7 @@ begin
WritePROTECT(AStream, true);
// WriteScenarioProtect(AStream);
WriteObjectProtect(AStream, FWorksheet);
WritePASSWORD(AStream, FWorksheet.CryptoInfo);
WritePASSWORD(AStream, TsWorksheet(FWorksheet).CryptoInfo);
end;
WriteDefaultColWidth(AStream, FWorksheet);
@ -1271,7 +1288,7 @@ begin
WriteVirtualCells(AStream, FWorksheet)
else begin
WriteRows(AStream, FWorksheet);
WriteCellsToStream(AStream, FWorksheet.Cells);
WriteCellsToStream(AStream, TsWorksheet(FWorksheet).Cells);
end;
WriteEOF(AStream);
@ -1287,7 +1304,7 @@ end;
BIFF8 begins with the 8 default colors which are duplicated. Then the user
colors follow up to a max of total 64 entries.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.PopulatePalette(AWorkbook: TsWorkbook);
procedure TsSpreadBIFF5Writer.PopulatePalette(AWorkbook: TsBasicWorkbook);
var
i: Integer;
begin
@ -1405,7 +1422,7 @@ end;
of the BOF of this sheet should be written (4 bytes size).
-------------------------------------------------------------------------------}
function TsSpreadBIFF5Writer.WriteBoundsheet(AStream: TStream;
AWorkSheet: TsWorksheet): Int64;
AWorkSheet: TsBasicWorksheet): Int64;
var
len: Byte;
xlsSheetName: ansistring;
@ -1442,8 +1459,8 @@ end;
Writes out a DEFINEDNAMES record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.WriteDefinedName(AStream: TStream;
AWorksheet: TsWorksheet; const AName: String; AIndexToREF, ASheetIndex: Word;
AKind: TsBIFFExternKind);
AWorksheet: TsBasicWorksheet; const AName: String;
AIndexToREF, ASheetIndex: Word; AKind: TsBIFFExternKind);
procedure WriteRangeFormula(MemStream: TMemoryStream; ARange: TsCellRange;
AIndexToREF, ASheetIndex, ACounter: Word);
@ -1503,42 +1520,46 @@ var
memstream: TMemoryStream;
rng: TsCellRange;
j: Integer;
sheet: TsWorksheet;
begin
sheet := AWorksheet as TsWorksheet;
// Since this is a variable length record we begin by writing the formula
// to a memory stream
memstream := TMemoryStream.Create;
try
case AName of
#06: begin // Print range
for j := 0 to AWorksheet.PageLayout.NumPrintRanges-1 do
for j := 0 to sheet.PageLayout.NumPrintRanges-1 do
begin
rng := AWorksheet.PageLayout.PrintRange[j];
rng := sheet.PageLayout.PrintRange[j];
WriteRangeFormula(memstream, rng, AIndexToRef, ASheetIndex, j+1);
end;
end;
#07: begin
j := 1;
if AWorksheet.PageLayout.HasRepeatedCols then
if sheet.PageLayout.HasRepeatedCols then
begin
rng.Col1 := AWorksheet.PageLayout.RepeatedCols.FirstIndex;
rng.Col2 := AWorksheet.PageLayout.RepeatedCols.LastIndex;
rng.Col1 := sheet.PageLayout.RepeatedCols.FirstIndex;
rng.Col2 := sheet.PageLayout.RepeatedCols.LastIndex;
if rng.Col2 = UNASSIGNED_ROW_COL_INDEX then rng.Col2 := rng.Col1;
rng.Row1 := 0;
rng.Row2 := 65535;
WriteRangeFormula(memstream, rng, AIndexToRef, ASheetIndex, j);
inc(j);
end;
if AWorksheet.PageLayout.HasRepeatedRows then
if sheet.PageLayout.HasRepeatedRows then
begin
rng.Row1 := AWorksheet.PageLayout.RepeatedRows.FirstIndex;
rng.Row2 := AWorksheet.PageLayout.RepeatedRows.LastIndex;
rng.Row1 := sheet.PageLayout.RepeatedRows.FirstIndex;
rng.Row2 := sheet.PageLayout.RepeatedRows.LastIndex;
if rng.Row2 = UNASSIGNED_ROW_COL_INDEX then rng.Row2 := rng.Row1;
rng.Col1 := 0;
rng.Col2 := 255;
WriteRangeFormula(memstream, rng, AIndexToRef, ASheetIndex, j);
end;
end;
else raise EFPSpreadsheetWriter.Create('Name not supported');
else
raise EFPSpreadsheetWriter.Create('Name not supported');
end; // case
{ BIFF record header }
@ -1598,7 +1619,8 @@ end;
See bug 18886: excel5 files are truncated when imported
--------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure TsSpreadBIFF5Writer.WriteDimensions(AStream: TStream;
AWorksheet: TsBasicWorksheet);
var
rec: TBIFF5_DimensionsRecord;
firstCol, lastCol, firstRow, lastRow: Cardinal;
@ -1704,8 +1726,8 @@ procedure TsSpreadBiff5Writer.WriteFonts(AStream: TStream);
var
i: Integer;
begin
for i:=0 to Workbook.GetFontCount-1 do
WriteFont(AStream, Workbook.GetFont(i));
for i:=0 to TsWorkbook(Workbook).GetFontCount-1 do
WriteFont(AStream, TsWorkbook(Workbook).GetFont(i));
end;
{@@ ----------------------------------------------------------------------------
@ -1907,7 +1929,7 @@ end;
internal 3D references to other sheets
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.WriteLocalLinkTable(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
i, n: Integer;
externSheetList: TsBIFFExternSheetList;
@ -1993,7 +2015,7 @@ begin
externSheetList := FLinkLists.GetLocalLinks(FWorksheet);
s := FWorkbook.GetWorksheetByIndex(ASheet1).Name;
s := (FWorkbook as TsWorkbook).GetWorksheetByIndex(ASheet1).Name;
externSheetIdx := externSheetList.IndexOfSheet(s);
if ASheet2 = -1 then
@ -2065,11 +2087,14 @@ end;
Writes an Excel 5 WINDOW2 record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Writer.WriteWindow2(AStream: TStream;
ASheet: TsWorksheet);
ASheet: TsBasicWorksheet);
var
Options: Word;
book: TsWorkbook;
actSheet: TsWorksheet;
begin
book := FWorkbook as TsWorkbook;
{ BIFF Record header }
WriteBiffHeader(AStream, INT_EXCEL_ID_WINDOW2, 10);
@ -2087,13 +2112,15 @@ begin
Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES;
if (soShowHeaders in ASheet.Options) then
Options := Options or MASK_WINDOW2_OPTION_SHOW_SHEET_HEADERS;
if (soHasFrozenPanes in ASheet.Options) and ((ASheet.LeftPaneWidth > 0) or (ASheet.TopPaneHeight > 0)) then
if (soHasFrozenPanes in ASheet.Options) and
((TsWorksheet(ASheet).LeftPaneWidth > 0) or (TsWorksheet(ASheet).TopPaneHeight > 0))
then
Options := Options or MASK_WINDOW2_OPTION_PANES_ARE_FROZEN;
if (ASheet.BiDiMode = bdRTL) then
if (TsWorksheet(ASheet).BiDiMode = bdRTL) then
Options := Options or MASK_WINDOW2_OPTION_COLUMNS_RIGHT_TO_LEFT;
if FWorkbook.ActiveWorksheet <> nil then
actSheet := FWorkbook.ActiveWorksheet else
actSheet := Fworkbook.GetWorksheetByIndex(0);
if book.ActiveWorksheet <> nil then
actSheet := book.ActiveWorksheet else
actSheet := book.GetWorksheetByIndex(0);
if (ASheet = actSheet) then
Options := Options or MASK_WINDOW2_OPTION_SHEET_ACTIVE or MASK_WINDOW2_OPTION_SHEET_SELECTED;
@ -2160,7 +2187,7 @@ begin
j := 0;
if (AFormatRecord <> nil) and (uffNumberFormat in AFormatRecord^.UsedFormattingFields)
then begin
nfParams := Workbook.GetNumberFormat(AFormatRecord^.NumberFormatIndex);
nfParams := TsWorkbook(Workbook).GetNumberFormat(AFormatRecord^.NumberFormatIndex);
nfs := nfParams.NumFormatStr;
j := NumFormatList.IndexOf(nfs);
if j = -1 then j := 0;

View File

@ -55,7 +55,7 @@ interface
uses
Classes, SysUtils, fpcanvas, DateUtils, contnrs, lazutf8,
fpstypes, fpspreadsheet, xlscommon,
fpstypes, xlscommon,
{$ifdef USE_NEW_OLE}
fpolebasic,
{$else}
@ -175,7 +175,7 @@ type
procedure ReadWorksheet(AStream: TStream); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
procedure ReadFromStream(AStream: TStream;
APassword: String = ''; AParams: TsStreamParams = []); override;
@ -203,19 +203,20 @@ type
function IndexOfSharedString(const AText: String;
const ARichTextParams: TsRichTextParams): Integer;
procedure InternalWriteToStream(AStream: TStream);
procedure PopulatePalette(AWorkbook: TsWorkbook); override;
procedure PopulateSharedStringTable(AWorkbook: TsWorkbook);
procedure PopulatePalette(AWorkbook: TsBasicWorkbook); override;
procedure PopulateSharedStringTable(AWorkbook: TsBasicWorkbook);
{ Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; AWorksheet: TsWorksheet): Int64;
function WriteBoundsheet(AStream: TStream;
AWorksheet: TsBasicWorksheet): Int64;
procedure WriteComment(AStream: TStream; ACell: PCell); override;
procedure WriteComments(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
procedure WriteComments(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsBasicWorksheet;
const AName: String; AIndexToREF, ASheetIndex: Word;
AKind: TsBIFFExternKind);
procedure WriteDefinedNames(AStream: TStream);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDimensions(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteEOF(AStream: TStream);
procedure WriteEXTERNBOOK(AStream: TStream; AUrl: String);
procedure WriteEXTERNSHEET(AStream: TStream);
@ -225,14 +226,14 @@ type
ANumFormatIndex: Integer); override;
procedure WriteHeaderFooter(AStream: TStream; AIsHeader: Boolean); override;
procedure WriteHyperlink(AStream: TStream; AHyperlink: PsHyperlink;
AWorksheet: TsWorksheet);
procedure WriteHyperlinks(AStream: TStream; AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
procedure WriteHyperlinks(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteHyperlinkToolTip(AStream: TStream; const ARow, ACol: Cardinal;
const ATooltip: String);
procedure WriteINDEX(AStream: TStream);
procedure WriteLABEL(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override;
procedure WriteMergedCells(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteMergedCells(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteMSODrawing1(AStream: TStream; ANumShapes: Word; AComment: PsComment);
procedure WriteMSODrawing2(AStream: TStream; AComment: PsComment; AObjID: Word);
procedure WriteMSODrawing2_Data(AStream: TStream; AComment: PsComment; AShapeID: Word);
@ -255,11 +256,11 @@ type
procedure WriteSTRINGRecord(AStream: TStream; AString: string); override;
procedure WriteSTYLE(AStream: TStream);
procedure WriteTXO(AStream: TStream; AComment: PsComment);
procedure WriteWINDOW2(AStream: TStream; ASheet: TsWorksheet);
procedure WriteWINDOW2(AStream: TStream; ASheet: TsBasicWorksheet);
procedure WriteXF(AStream: TStream; AFormatRecord: PsCellFormat;
XFType_Prot: Byte = 0); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
destructor Destroy; override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
@ -363,7 +364,7 @@ uses
{$ENDIF}
Math, lconvencoding, LazFileUtils, URIParser,
fpsStrings, {%H-}fpsPatches, fpsStreams, fpsReaderWriter, fpsPalette,
fpsNumFormat, fpsExprParser, xlsEscher;
fpspreadsheet, fpsNumFormat, fpsExprParser, xlsEscher;
const
{ Excel record IDs }
@ -769,7 +770,7 @@ end;
{------------------------------------------------------------------------------}
{ TsSpreadBIFF8Reader }
{------------------------------------------------------------------------------}
constructor TsSpreadBIFF8Reader.Create(AWorkbook: TsWorkbook);
constructor TsSpreadBIFF8Reader.Create(AWorkbook: TsBasicWorkbook);
begin
inherited;
InitBIFF8Limitations(FLimitations);
@ -858,7 +859,7 @@ begin
if TBIFF8Comment(FCommentList[i]).ID = commentID then
begin
commentText := TBIFF8Comment(FCommentList[i]).Text;
FWorksheet.WriteComment(r, c, commentText);
TsWorksheet(FWorksheet).WriteComment(r, c, commentText);
exit;
end;
end;
@ -1158,7 +1159,7 @@ var
RecordType: Word;
CurStreamPos: Int64;
begin
FWorksheet := FWorkbook.GetWorksheetByIndex(FCurSheetIndex);
FWorksheet := (FWorkbook as TsWorkbook).GetWorksheetByIndex(FCurSheetIndex);
while (not SectionEOF) do
begin
{ Read the record header }
@ -1269,7 +1270,7 @@ begin
{ Read string with flags }
wideName := ReadWideString(AStream, len, rtParams);
sheet := FWorkbook.AddWorksheet(UTF8Encode(widename), true);
sheet := (FWorkbook as TsWorkbook).AddWorksheet(UTF8Encode(widename), true);
if sheetState <> 0 then
sheet.Options := sheet.Options + [soHidden];
end;
@ -1357,7 +1358,10 @@ var
rtParams: TsRichTextParams;
fntIndex: Integer;
fnt: TsFont;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
{ BIFF Record data: Row, Column, XF Index }
ReadRowColXF(AStream, ARow, ACol, XF);
@ -1372,9 +1376,9 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell); // "virtual" cell
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol); // "real" cell
cell := (FWorksheet as TsWorksheet).AddCell(ARow, ACol); // "real" cell
FWorksheet.WriteText(cell, UTF16ToUTF8(wideStrValue));
(FWorksheet as TsWorksheet).WriteText(cell, UTF16ToUTF8(wideStrValue));
{ Add attributes }
ApplyCellFormatting(cell, XF);
@ -1389,9 +1393,9 @@ begin
// Font index of new format - need to adjust index!
fntIndex := rtParams[i].FontIndex;
fnt := TsFont(FFontList[fntIndex]);
fntIndex := FWorkbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
cell^.RichTextParams[i].FontIndex := fntIndex;
// Hyperlink index, not used here
cell^.RichTextParams[i].HyperlinkIndex := -1;
@ -1399,7 +1403,7 @@ begin
end;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
book.OnReadCellData(Workbook, ARow, ACol, cell);
end;
procedure TsSpreadBIFF8Reader.ReadMergedCells(const AStream: TStream);
@ -1416,7 +1420,7 @@ begin
// Read range
AStream.ReadBuffer(rng, SizeOf(rng));
// Transfer cell range to worksheet
FWorksheet.MergeCells(
(FWorksheet as TsWorksheet).MergeCells(
WordLEToN(rng.Row1), WordLEToN(rng.Col1),
WordLEToN(rng.Row2), WordLEToN(rng.Col2)
);
@ -1629,7 +1633,10 @@ var
rtfRuns: TBiff8_RichTextFormattingRuns;
fntIndex: Integer;
fnt: TsFont;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
{ BIFF Record data: Row, Column, XF Index }
ReadRowColXF(AStream, ARow, ACol, XF);
@ -1644,10 +1651,10 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell); // "virtual" cell
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol); // "real" cell
cell := (FWorksheet as TsWorksheet).AddCell(ARow, ACol); // "real" cell
{ Save the data string}
FWorksheet.WriteText(cell, UTF16ToUTF8(wideStrValue));
(FWorksheet as TsWorksheet).WriteText(cell, UTF16ToUTF8(wideStrValue));
{ Read rich-text formatting runs }
L := WordLEToN(AStream.ReadWord);
@ -1660,9 +1667,9 @@ begin
// necessarily the same as the index used by the workbook!
fntIndex := WordLEToN(rtfRuns[j].FontIndex);
fnt := TsFont(FFontList[fntIndex]);
fntIndex := FWorkbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
cell^.RichTextParams[j].FontIndex := fntIndex;
// Index of the first character using this font: 0-based in file, 1-based in fps
cell^.RichTextParams[j].FirstIndex := WordLEToN(rtfRuns[j].FirstIndex) + 1;
@ -1674,7 +1681,7 @@ begin
ApplyCellFormatting(cell, XF);
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
book.OnReadCellData(book, ARow, ACol, cell);
end;
procedure TsSpreadBIFF8Reader.ReadSST(const AStream: TStream);
@ -1773,7 +1780,10 @@ var
rtParams: TsRichTextParams;
fnt: TsFont;
fntIndex: Integer;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
rec.Row := 0; // to silence the compiler...
{ Read entire record, starting at Row }
@ -1794,9 +1804,9 @@ begin
InitCell(FWorksheet, ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
cell := FWorksheet.AddCell(ARow, ACol);
cell := (FWorksheet as TsWorksheet).AddCell(ARow, ACol);
FWorksheet.WriteText(cell, FSharedStringTable.Strings[SSTIndex]);
(FWorksheet as TsWorksheet).WriteText(cell, FSharedStringTable.Strings[SSTIndex]);
{ Add attributes }
ApplyCellFormatting(cell, XF);
@ -1814,16 +1824,16 @@ begin
cell^.RichTextParams[i].FirstIndex := rtParams[i].FirstIndex;
fntIndex := rtParams[i].FontIndex;
fnt := TsFont(FFontList[fntIndex]);
fntIndex := FWorkbook.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.FindFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
if fntIndex = -1 then
fntIndex := FWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
fntIndex := book.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fnt.Position);
cell^.RichTextParams[i].FontIndex := fntIndex;
cell^.RichTextParams[i].HyperlinkIndex := -1;
end;
end;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
book.OnReadCellData(book, ARow, ACol, cell);
end;
{ Helper function for reading a string with 8-bit length. }
@ -1841,13 +1851,16 @@ end;
procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream);
var
wideStr: WideString;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
wideStr := ReadWideString(AStream, false);
if (FIncompleteCell <> nil) and (wideStr <> '') then begin
FIncompleteCell^.UTF8StringValue := UTF8Encode(wideStr);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
book.OnReadCellData(book, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
end;
FIncompleteCell := nil;
end;
@ -1875,7 +1888,10 @@ var
nfs: String;
nfParams: TsNumFormatParams;
iclr: Integer;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
InitFormatRecord(fmt);
fmt.ID := FCellFormatList.Count;
@ -1894,8 +1910,8 @@ begin
// "General" (NumFormatIndex = 0) not stored in workbook's NumFormatList
if (rec.NumFormatIndex > 0) and not SameText(nfs, 'General') then
begin
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
nfParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
fmt.NumberFormatIndex := book.AddNumberFormat(nfs);
nfParams := book.GetNumberFormat(fmt.NumberFormatIndex);
if nfParams <> nil then
begin
fmt.NumberFormat := nfParams.NumFormat;
@ -2265,7 +2281,7 @@ begin
if FFontList.Count = 4 then FFontList.Add(nil);
if isDefaultFont then
Workbook.SetDefaultFont(font.FontName, font.Size);
(Workbook as TsWorkbook).SetDefaultFont(font.FontName, font.Size);
end;
{@@ ----------------------------------------------------------------------------
@ -2312,10 +2328,11 @@ begin
len := WordLEToN(AStream.ReadWord);
s := ReadWideString(AStream, len, rtParams);
if AIsHeader then
FWorksheet.PageLayout.Headers[1] := UTF8Encode(s)
else
FWOrksheet.PageLayout.Footers[1] := UTF8Encode(s);
with (FWorksheet as TsWorksheet).Pagelayout do
if AIsHeader then
Headers[1] := UTF8Encode(s)
else
Footers[1] := UTF8Encode(s);
{ Options poDifferentFirst and poDifferentOddEvent are not used, BIFF supports
only common headers/footers }
@ -2461,7 +2478,7 @@ begin
// Add hyperlink(s) to worksheet
for row := row1 to row2 do
for col := col1 to col2 do
FWorksheet.WriteHyperlink(row, col, link);
TsWorksheet(FWorksheet).WriteHyperlink(row, col, link);
end;
@ -2476,6 +2493,7 @@ var
row1, col1, row2, col2: Word;
hyperlink: PsHyperlink;
numbytes: Integer;
sheet: TsWorksheet;
begin
{ Record type; this matches the BIFF record type }
AStream.ReadWord;
@ -2494,7 +2512,8 @@ begin
txt := UTF8Encode(wideStr);
{ Add tooltip to hyperlinks }
for hyperlink in FWorksheet.Hyperlinks.GetRangeEnumerator(row1, col1, row2, col2) do
sheet := FWorksheet as TsWorksheet;
for hyperlink in sheet.Hyperlinks.GetRangeEnumerator(row1, col1, row2, col2) do
hyperlink^.ToolTip := txt;
end;
@ -2506,7 +2525,7 @@ end;
{@@ ----------------------------------------------------------------------------
Constructor of the Excel 8 writer
-------------------------------------------------------------------------------}
constructor TsSpreadBIFF8Writer.Create(AWorkbook: TsWorkbook);
constructor TsSpreadBIFF8Writer.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
InitBiff8Limitations(FLimitations);
@ -2576,6 +2595,7 @@ procedure TsSpreadBIFF8Writer.CollectExternData;
end;
var
book: TsWorkbook;
sheet: TsWorksheet;
i: Integer;
writeIt: Boolean;
@ -2586,9 +2606,11 @@ begin
FBiff8ExternBooks := TsBIFF8ExternBookList.Create;
FBiff8ExternSheets := TsBIFF8ExternSheetList.Create(FBiff8ExternBooks);
book := FWorkbook as TsWorkbook;
{ Add sheets used in print ranges, repeated cols or repeated rows }
for i:=0 to FWorkbook.GetWorksheetCount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i);
for i:=0 to book.GetWorksheetCount-1 do begin
sheet := book.GetWorksheetByIndex(i);
with sheet.PageLayout do
writeIt := (NumPrintRanges > 0) or HasRepeatedCols or HasRepeatedRows;
if writeIt then
@ -2596,9 +2618,9 @@ begin
end;
{ Add sheets related to 3d references of all sheets }
for i:=0 to FWorkbook.GetWorksheetCount-1 do
for i:=0 to book.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet := book.GetWorksheetByIndex(i);
DoCollectForSheet(sheet);
end;
@ -2632,7 +2654,7 @@ Begin
Bit 9: 0 = Print notes as displayed; 1 = Print notes at end of sheet
Bit 11-10: 00 = Print errors as displayed; 1 = Do not print errors
2 = Print errors as “--”; 3 = Print errors as “#N/A” }
if poCommentsAtEnd in FWorksheet.PageLayout.Options then
if poCommentsAtEnd in (FWorksheet as TsWorksheet).PageLayout.Options then
Result := Result or $0200;
end;
@ -2671,7 +2693,9 @@ var
sheetPos: array of Int64;
i: Integer;
pane: Byte;
book: TsWorkbook;
begin
book := FWorkbook as TsWorkbook;
CollectExternData;
{ Write workbook globals }
@ -2679,7 +2703,7 @@ begin
WriteCodePage(AStream, 'ucs2le'); // = utf-16
WriteWindowProtect(AStream, bpLockWindows in Workbook.Protection);
WritePROTECT(AStream, bpLockStructure in Workbook.Protection);
WritePASSWORD(AStream, Workbook.CryptoInfo);
WritePASSWORD(AStream, book.CryptoInfo);
WriteWINDOW1(AStream);
WriteFonts(AStream);
WriteNumFormats(AStream);
@ -2688,9 +2712,9 @@ begin
WriteStyle(AStream);
// A BOUNDSHEET for each worksheet
SetLength(sheetPos, Workbook.GetWorksheetCount);
for i := 0 to Workbook.GetWorksheetCount - 1 do
sheetPos[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i));
SetLength(sheetPos, book.GetWorksheetCount);
for i := 0 to book.GetWorksheetCount - 1 do
sheetPos[i] := WriteBoundsheet(AStream, book.GetWorksheetByIndex(i));
WriteEXTERNBOOK(AStream, '');
WriteEXTERNSHEET(AStream);
@ -2700,9 +2724,9 @@ begin
WriteEOF(AStream);
{ Write each worksheet }
for i := 0 to Workbook.GetWorksheetCount - 1 do
for i := 0 to book.GetWorksheetCount - 1 do
begin
FWorksheet := Workbook.GetWorksheetByIndex(i);
FWorksheet := book.GetWorksheetByIndex(i);
{ First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record }
@ -2734,7 +2758,7 @@ begin
WritePROTECT(AStream, true);
// WriteScenarioProtect(AStream);
WriteObjectProtect(AStream, FWorksheet);
WritePASSWORD(AStream, FWorksheet.CryptoInfo);
WritePASSWORD(AStream, (FWorksheet as TsWorksheet).CryptoInfo);
end;
WriteDefaultColWidth(AStream, FWorksheet);
@ -2745,7 +2769,7 @@ begin
WriteVirtualCells(AStream, FWorksheet)
else begin
WriteRows(AStream, FWorksheet);
WriteCellsToStream(AStream, FWorksheet.Cells);
WriteCellsToStream(AStream, (FWorksheet as TsWorksheet).Cells);
WriteComments(AStream, FWorksheet);
end;
@ -2770,7 +2794,7 @@ end;
BIFF8 begins with the 8 default colors which are duplicated. Then the user
colors follow up to a max of total 64 entries.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.PopulatePalette(AWorkbook: TsWorkbook);
procedure TsSpreadBIFF8Writer.PopulatePalette(AWorkbook: TsBasicWorkbook);
var
i: Integer;
begin
@ -2791,18 +2815,19 @@ end;
{@@ ----------------------------------------------------------------------------
Collects all strings of the workbook in the SharedStringTable
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.PopulateSharedStringTable(AWorkbook: TsWorkbook);
procedure TsSpreadBIFF8Writer.PopulateSharedStringTable(AWorkbook: TsBasicWorkbook);
var
i, idx: Integer;
cell: PCell;
sheet: TsWorksheet;
book: TsWorkbook absolute AWorkbook;
begin
FNumStrings := 0;
FSharedStringTable := TStringList.Create;
for i:=0 to AWorkbook.GetWorksheetCount-1 do
for i:=0 to book.GetWorksheetCount-1 do
begin
sheet := AWorkbook.GetWorksheetByIndex(i);
sheet := book.GetWorksheetByIndex(i);
for cell in sheet.Cells do begin
if (cell^.ContentType <> cctUTF8String) then
Continue;
@ -2925,7 +2950,7 @@ end;
of the BOF of this sheet should be written (4 bytes size).
-------------------------------------------------------------------------------}
function TsSpreadBIFF8Writer.WriteBoundsheet(AStream: TStream;
AWorksheet: TsWorksheet): Int64;
AWorksheet: TsBasicWorksheet): Int64;
var
len: Byte;
wideSheetName: WideString;
@ -2972,21 +2997,24 @@ end;
Writes all comments to the worksheet stream
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteComments(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
index: Integer;
comment: PsComment;
sheet: TsWorksheet;
begin
exit; // Remove after comments can be written correctly
{$warning TODO: Fix writing of cell comments in BIFF8 (file is readable by OpenOffice, but not by Excel)}
sheet := AWorksheet as TsWorksheet;
{ At first we have to write all Escher-related records for all comments;
MSODRAWING - OBJ - MSODRAWING - TXO }
index := 1;
for comment in AWorksheet.Comments do
for comment in sheet.Comments do
begin
if index = 1 then
WriteMSODrawing1(AStream, FWorksheet.Comments.Count, comment)
WriteMSODrawing1(AStream, sheet.Comments.Count, comment)
else
WriteMSODrawing2(AStream, comment, index);
WriteOBJ(AStream, index);
@ -2997,7 +3025,7 @@ begin
{ The NOTE records for all comments follow subsequently. }
index := 1;
for comment in AWorksheet.Comments do
for comment in sheet.Comments do
begin
WriteNOTE(AStream, comment, index);
inc(index);
@ -3009,8 +3037,8 @@ end;
Implements only the builtin defined names for print ranges and titles!
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteDefinedName(AStream: TStream;
AWorksheet: TsWorksheet; const AName: String; AIndexToREF, ASheetIndex: Word;
AKind: TsBIFFExternKind);
AWorksheet: TsBasicWorksheet; const AName: String;
AIndexToREF, ASheetIndex: Word; AKind: TsBIFFExternKind);
procedure WriteRangeFormula(MemStream: TMemoryStream; ARange: TsCellRange;
AIndexToRef, ACounter: Word);
@ -3042,6 +3070,8 @@ var
memstream: TMemoryStream;
rng: TsCellRange;
j: Integer;
idx: Integer;
sheet: TsWorksheet absolute AWorksheet;
begin
// Since this is a variable length record we begin by writing the formula
@ -3050,28 +3080,28 @@ begin
try
case AName of
#06: begin // Print range
for j := 0 to AWorksheet.PageLayout.NumPrintRanges-1 do
for j := 0 to sheet.PageLayout.NumPrintRanges-1 do
begin
rng := AWorksheet.PageLayout.PrintRange[j];
rng := sheet.PageLayout.PrintRange[j];
WriteRangeFormula(memstream, rng, AIndexToRef, j+1);
end;
end;
#07: begin // Print titles
j := 1;
if AWorksheet.PageLayout.HasRepeatedCols then
if sheet.PageLayout.HasRepeatedCols then
begin
rng.Col1 := AWorksheet.PageLayout.RepeatedCols.FirstIndex;
rng.Col2 := AWorksheet.PageLayout.RepeatedCols.LastIndex;
rng.Col1 := sheet.PageLayout.RepeatedCols.FirstIndex;
rng.Col2 := sheet.PageLayout.RepeatedCols.LastIndex;
if rng.Col2 = UNASSIGNED_ROW_COL_INDEX then rng.Col2 := rng.Col1;
rng.Row1 := 0;
rng.Row2 := 65535;
WriteRangeFormula(memstream, rng, AIndexToRef, j);
inc(j);
end;
if AWorksheet.PageLayout.HasRepeatedRows then
if sheet.PageLayout.HasRepeatedRows then
begin
rng.Row1 := AWorksheet.PageLayout.RepeatedRows.FirstIndex;
rng.Row2 := AWorksheet.PageLayout.RepeatedRows.LastIndex;
rng.Row1 := sheet.PageLayout.RepeatedRows.FirstIndex;
rng.Row2 := sheet.PageLayout.RepeatedRows.LastIndex;
if rng.Row2 = UNASSIGNED_ROW_COL_INDEX then rng.Row2 := rng.Row1;
rng.Col1 := 0;
rng.Col2 := 255;
@ -3102,7 +3132,8 @@ begin
AStream.WriteWord(0);
{ Index to sheet (1-based) }
AStream.WriteWord(WordToLE(FWorkbook.GetWorksheetIndex(AWorksheet)+1));
idx := (FWorkbook as TsWorkbook).GetWorksheetIndex(AWorksheet);
AStream.WriteWord(WordToLE(idx+1));
{ Length of menu text }
AStream.WriteByte(0);
@ -3134,18 +3165,21 @@ end;
procedure TsSpreadBIFF8Writer.WriteDefinedNames(AStream: TStream);
var
bookIdx: Integer;
book: TsWorkbook;
sheet: TsWorksheet;
i: Integer;
begin
if (FBiff8ExternBooks = nil) or (FBiff8ExternSheets = nil) then
exit;
book := FWorkbook as TsWorkbook;
// Defined names in "internal" book only
bookIdx := FBiff8ExternBooks.IndexOfInternalbook;
for i:=0 to FWorkbook.GetWorksheetCount-1 do
for i:=0 to book.GetWorksheetCount-1 do
begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet := book.GetWorksheetByIndex(i);
if (sheet.PageLayout.NumPrintRanges > 0) or
sheet.PageLayout.HasRepeatedCols or sheet.PageLayout.HasRepeatedRows then
begin
@ -3170,7 +3204,7 @@ end;
See bug 18886: excel5 files are truncated when imported
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteDimensions(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
firstRow, lastRow, firstCol, lastCol: Cardinal;
rec: TBIFF8_DimensionsRecord;
@ -3219,7 +3253,7 @@ begin
{ Current workbook -- assuming that it has index 0 in list FExternBook8 }
if AUrl = '' then begin
{ Number of sheets in this workbook }
AStream.WriteWord(WordToLE(FWorkbook.GetWorksheetCount));
AStream.WriteWord(WordToLE((FWorkbook as TsWorkbook).GetWorksheetCount));
{ Relict from BIFF5 }
AStream.WriteWord(WordToLE($0401));
@ -3344,9 +3378,11 @@ end;
procedure TsSpreadBiff8Writer.WriteFonts(AStream: TStream);
var
i: Integer;
book: TsWorkbook;
begin
for i:=0 to Workbook.GetFontCount-1 do
WriteFONT(AStream, Workbook.GetFont(i));
book := FWorkbook as TsWorkbook;
for i:=0 to book.GetFontCount-1 do
WriteFONT(AStream, book.GetFont(i));
end;
{@@ ----------------------------------------------------------------------------
@ -3407,7 +3443,7 @@ var
len: Integer;
id: Word;
begin
with FWorksheet.PageLayout do
with (FWorksheet as TsWorksheet).PageLayout do
if AIsHeader then
begin
if (Headers[HEADER_FOOTER_INDEX_ALL] = '') then
@ -3440,7 +3476,7 @@ end;
Writes an Excel 8 HYPERLINK record
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteHyperlink(AStream: TStream;
AHyperlink: PsHyperlink; AWorksheet: TsWorksheet);
AHyperlink: PsHyperlink; AWorksheet: TsBasicWorksheet);
var
temp: TStream;
guid: TGUID;
@ -3456,11 +3492,11 @@ var
isInternal: Boolean;
dirUpCounter: Integer;
begin
cell := AWorksheet.FindCell(AHyperlink^.Row, AHyperlink^.Col);
cell := (AWorksheet as TsWorksheet).FindCell(AHyperlink^.Row, AHyperlink^.Col);
if (cell = nil) or (AHyperlink^.Target='') then
exit;
descr := AWorksheet.ReadAsText(cell); // Hyperlink description
descr := (AWorksheet as TsWorksheet).ReadAsText(cell); // Hyperlink description
SplitHyperlink(AHyperlink^.Target, target, bookmark);
u := ParseURI(AHyperlink^.Target);
isInternal := (target = '') and (bookmark <> '');
@ -3597,11 +3633,11 @@ end;
Writes all hyperlinks
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteHyperlinks(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
hyperlink: PsHyperlink;
begin
for hyperlink in AWorksheet.Hyperlinks do begin
for hyperlink in (AWorksheet as TsWorksheet).Hyperlinks do begin
{ Write HYPERLINK record }
WriteHyperlink(AStream, hyperlink, AWorksheet);
{ Write HYPERLINK TOOLTIP record }
@ -3787,18 +3823,19 @@ begin
end;
procedure TsSpreadBIFF8Writer.WriteMergedCells(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
const
MAX_PER_RECORD = 1026;
var
n0, n: Integer;
rng: PsCellRange;
newRecord: Boolean;
sheet: TsWorksheet absolute AWorksheet;
begin
n0 := AWorksheet.MergedCells.Count;
n0 := sheet.MergedCells.Count;
n := Min(n0, MAX_PER_RECORD);
newRecord := true;
for rng in AWorksheet.MergedCells do
for rng in sheet.MergedCells do
begin
if newRecord then
begin
@ -4781,11 +4818,15 @@ end;
sheets.
-------------------------------------------------------------------------------}
procedure TsSpreadBIFF8Writer.WriteWINDOW2(AStream: TStream;
ASheet: TsWorksheet);
ASheet: TsBasicWorksheet);
var
Options: Word;
actSheet: TsWorksheet;
book: TsWorkbook;
sheet, actSheet: TsWorksheet;
begin
book := FWorkbook as TsWorkbook;
sheet := ASheet as TsWorksheet;
{ BIFF Record header }
WriteBiffHeader(AStream, INT_EXCEL_ID_WINDOW2, 18);
@ -4800,18 +4841,18 @@ begin
{ Bug 0026386 -> every sheet must be selected/active, otherwise Excel cannot print
---> wp: after changes for issue 0028452: this is not necessary any more. }
if (soShowGridLines in ASheet.Options) then
if (soShowGridLines in sheet.Options) then
Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES;
if (soShowHeaders in ASheet.Options) then
if (soShowHeaders in sheet.Options) then
Options := Options or MASK_WINDOW2_OPTION_SHOW_SHEET_HEADERS;
if (soHasFrozenPanes in ASheet.Options) and ((ASheet.LeftPaneWidth > 0) or (ASheet.TopPaneHeight > 0)) then
if (soHasFrozenPanes in sheet.Options) and ((sheet.LeftPaneWidth > 0) or (sheet.TopPaneHeight > 0)) then
Options := Options or MASK_WINDOW2_OPTION_PANES_ARE_FROZEN;
if FWorkbook.ActiveWorksheet <> nil then
actSheet := FWorkbook.ActiveWorksheet else
actSheet := Fworkbook.GetWorksheetByIndex(0);
if (ASheet = actSheet) then
if book.ActiveWorksheet <> nil then
actSheet := book.ActiveWorksheet else
actSheet := book.GetWorksheetByIndex(0);
if (sheet = actSheet) then
Options := Options or MASK_WINDOW2_OPTION_SHEET_ACTIVE or MASK_WINDOW2_OPTION_SHEET_SELECTED;
if (ASheet.BiDiMode = bdRTL) then
if (sheet.BiDiMode = bdRTL) then
Options := Options or MASK_WINDOW2_OPTION_COLUMNS_RIGHT_TO_LEFT;
AStream.WriteWord(WordToLE(Options));
@ -4870,7 +4911,7 @@ begin
j := 0;
if (AFormatRecord <> nil) and (uffNumberFormat in AFormatRecord^.UsedFormattingFields)
then begin
nfParams := Workbook.GetNumberFormat(AFormatRecord^.NumberFormatIndex);
nfParams := (Workbook as TsWorkbook).GetNumberFormat(AFormatRecord^.NumberFormatIndex);
if nfParams <> nil then
begin
nfs := nfParams.NumFormatStr;

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ interface
uses
Classes, SysUtils,
laz2_xmlread, laz2_DOM,
fpsTypes, fpspreadsheet, fpsReaderWriter, xlsCommon;
fpsTypes, fpsReaderWriter, xlsCommon;
type
@ -35,21 +35,21 @@ type
FPointSeparatorSettings: TFormatSettings;
function GetCommentStr(ACell: PCell): String;
function GetFormulaStr(ACell: PCell): String;
function GetFrozenPanesStr(AWorksheet: TsWorksheet; AIndent: String): String;
function GetFrozenPanesStr(AWorksheet: TsBasicWorksheet; AIndent: String): String;
function GetHyperlinkStr(ACell: PCell): String;
function GetIndexStr(AIndex: Integer): String;
function GetLayoutStr(AWorksheet: TsWorksheet): String;
function GetLayoutStr(AWorksheet: TsBasicWorksheet): String;
function GetMergeStr(ACell: PCell): String;
function GetPageFooterStr(AWorksheet: TsWorksheet): String;
function GetPageHeaderStr(AWorksheet: TsWorksheet): String;
function GetPageMarginStr(AWorksheet: TsWorksheet): String;
function GetPageFooterStr(AWorksheet: TsBasicWorksheet): String;
function GetPageHeaderStr(AWorksheet: TsBasicWorksheet): String;
function GetPageMarginStr(AWorksheet: TsBasicWorksheet): String;
function GetStyleStr(AFormatIndex: Integer): String;
procedure WriteExcelWorkbook(AStream: TStream);
procedure WriteStyle(AStream: TStream; AIndex: Integer);
procedure WriteStyles(AStream: TStream);
procedure WriteTable(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteWorksheet(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteWorksheetOptions(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteTable(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteWorksheet(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteWorksheetOptions(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteWorksheets(AStream: TStream);
protected
@ -68,7 +68,7 @@ type
const AValue: double; ACell: PCell); override;
public
constructor Create(AWorkbook: TsWorkbook); override;
constructor Create(AWorkbook: TsBasicWorkbook); override;
procedure WriteToStream(AStream: TStream; AParams: TsStreamParams = []); override;
end;
@ -90,7 +90,7 @@ implementation
uses
StrUtils, Math,
fpsStrings, fpsUtils, fpsNumFormat, fpsXmlCommon, fpsHTMLUtils;
fpsStrings, fpspreadsheet, fpsUtils, fpsNumFormat, fpsXmlCommon, fpsHTMLUtils;
const
FMT_OFFSET = 61;
@ -164,7 +164,7 @@ end;
Defines the date mode and the limitations of the file format.
Initializes the format settings to be used when writing to xml.
-------------------------------------------------------------------------------}
constructor TsSpreadExcelXMLWriter.Create(AWorkbook: TsWorkbook);
constructor TsSpreadExcelXMLWriter.Create(AWorkbook: TsBasicWorkbook);
begin
inherited Create(AWorkbook);
@ -186,7 +186,7 @@ var
comment: PsComment;
begin
Result := '';
comment := FWorksheet.FindComment(ACell);
comment := (FWorksheet as TsWorksheet).FindComment(ACell);
if Assigned(comment) then
Result := INDENT1 + '<Comment><Data>' + comment^.Text + '</Data></Comment>' + LF + CELL_INDENT;
// If there will be some rich-text-like formatting in the future, use
@ -197,40 +197,41 @@ function TsSpreadExcelXMLWriter.GetFormulaStr(ACell: PCell): String;
begin
if HasFormula(ACell) then
begin
Result := UTF8TextToXMLText(FWorksheet.ConvertFormulaDialect(ACell, fdExcelR1C1));
Result := UTF8TextToXMLText((FWorksheet as TsWorksheet).ConvertFormulaDialect(ACell, fdExcelR1C1));
Result := ' ss:Formula="=' + Result + '"';
end else
Result := '';
end;
function TsSpreadExcelXMLWriter.GetFrozenPanesStr(AWorksheet: TsWorksheet;
function TsSpreadExcelXMLWriter.GetFrozenPanesStr(AWorksheet: TsBasicWorksheet;
AIndent: String): String;
var
activePane: Integer;
sheet: TsWorksheet absolute AWorksheet;
begin
if (soHasFrozenPanes in AWorksheet.Options) then
if (soHasFrozenPanes in sheet.Options) then
begin
Result := AIndent +
'<FreezePanes/>' + LF + AIndent +
'<FrozenNoSplit/>' + LF;
if FWorksheet.LeftPaneWidth > 0 then
if sheet.LeftPaneWidth > 0 then
Result := Result + AIndent +
'<SplitVertical>1</SplitVertical>' + LF + AIndent +
'<LeftColumnRightPane>' + IntToStr(FWorksheet.LeftPaneWidth) + '</LeftColumnRightPane>' + LF;
'<LeftColumnRightPane>' + IntToStr(sheet.LeftPaneWidth) + '</LeftColumnRightPane>' + LF;
if FWorksheet.TopPaneHeight > 0 then
if sheet.TopPaneHeight > 0 then
Result := Result + AIndent +
'<SplitHorizontal>1</SplitHorizontal>' + LF + AIndent +
'<TopRowBottomPane>' + IntToStr(FWorksheet.TopPaneHeight) + '</TopRowBottomPane>' + LF;
'<TopRowBottomPane>' + IntToStr(sheet.TopPaneHeight) + '</TopRowBottomPane>' + LF;
if (FWorksheet.LeftPaneWidth = 0) and (FWorkSheet.TopPaneHeight = 0) then
if (sheet.LeftPaneWidth = 0) and (sheet.TopPaneHeight = 0) then
activePane := 3
else
if (FWorksheet.LeftPaneWidth = 0) then
if (sheet.LeftPaneWidth = 0) then
activePane := 2
else
if (FWorksheet.TopPaneHeight = 0) then
if (sheet.TopPaneHeight = 0) then
activePane := 1
else
activePane := 0;
@ -245,7 +246,7 @@ var
hyperlink: PsHyperlink;
begin
Result := '';
hyperlink := FWorksheet.FindHyperlink(ACell);
hyperlink := (FWorksheet as TsWorksheet).FindHyperlink(ACell);
if Assigned(hyperlink) then
Result := ' ss:HRef="' + hyperlink^.Target + '"';
end;
@ -255,17 +256,19 @@ begin
Result := Format(' ss:Index="%d"', [AIndex]);
end;
function TsSpreadExcelXMLWriter.GetLayoutStr(AWorksheet: TsWorksheet): String;
function TsSpreadExcelXMLWriter.GetLayoutStr(AWorksheet: TsBasicWorksheet): String;
var
sheet: TsWorksheet absolute AWorksheet;
begin
Result := '';
if AWorksheet.PageLayout.Orientation = spoLandscape then
if sheet.PageLayout.Orientation = spoLandscape then
Result := Result + ' x:Orientation="Landscape"';
if (poHorCentered in AWorksheet.PageLayout.Options) then
if (poHorCentered in sheet.PageLayout.Options) then
Result := Result + ' x:CenterHorizontal="1"';
if (poVertCentered in AWorksheet.PageLayout.Options) then
if (poVertCentered in sheet.PageLayout.Options) then
Result := Result + ' x:CenterVertical="1"';
if (poUseStartPageNumber in AWorksheet.PageLayout.Options) then
Result := Result + ' x:StartPageNumber="' + IntToStr(AWorksheet.PageLayout.StartPageNumber) + '"';
if (poUseStartPageNumber in sheet.PageLayout.Options) then
Result := Result + ' x:StartPageNumber="' + IntToStr(sheet.PageLayout.StartPageNumber) + '"';
Result := '<Layout' + Result + '/>';
end;
@ -274,8 +277,8 @@ var
r1, c1, r2, c2: Cardinal;
begin
Result := '';
if FWorksheet.IsMerged(ACell) then begin
FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
if (FWorksheet as TsWorksheet).IsMerged(ACell) then begin
(FWorksheet as TsWorksheet).FindMergedRange(ACell, r1, c1, r2, c2);
if c2 > c1 then
Result := Result + Format(' ss:MergeAcross="%d"', [c2-c1]);
if r2 > r1 then
@ -283,29 +286,38 @@ begin
end;
end;
function TsSpreadExcelXMLWriter.GetPageFooterStr(AWorksheet: TsWorksheet): String;
function TsSpreadExcelXMLWriter.GetPageFooterStr(
AWorksheet: TsBasicWorksheet): String;
var
sheet: TsWorksheet absolute AWorksheet;
begin
Result := Format('x:Margin="%g"', [mmToIn(AWorksheet.PageLayout.FooterMargin)], FPointSeparatorSettings);
if (AWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ALL] <> '') then
Result := Result + ' x:Data="' + UTF8TextToXMLText(AWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ALL], true) + '"';
Result := Format('x:Margin="%g"', [mmToIn(sheet.PageLayout.FooterMargin)], FPointSeparatorSettings);
if (sheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ALL] <> '') then
Result := Result + ' x:Data="' + UTF8TextToXMLText(sheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ALL], true) + '"';
Result := '<Footer ' + result + '/>';
end;
function TsSpreadExcelXMLWriter.GetPageHeaderStr(AWorksheet: TsWorksheet): String;
function TsSpreadExcelXMLWriter.GetPageHeaderStr(
AWorksheet: TsBasicWorksheet): String;
var
sheet: TsWorksheet absolute AWorksheet;
begin
Result := Format('x:Margin="%g"', [mmToIn(AWorksheet.PageLayout.HeaderMargin)], FPointSeparatorSettings);
if (AWorksheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL] <> '') then
Result := Result + ' x:Data="' + UTF8TextToXMLText(AWorksheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL], true) + '"';
Result := Format('x:Margin="%g"', [mmToIn(sheet.PageLayout.HeaderMargin)], FPointSeparatorSettings);
if (sheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL] <> '') then
Result := Result + ' x:Data="' + UTF8TextToXMLText(sheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL], true) + '"';
Result := '<Header ' + Result + '/>';
end;
function TsSpreadExcelXMLWriter.GetPageMarginStr(AWorksheet: TsWorksheet): String;
function TsSpreadExcelXMLWriter.GetPageMarginStr(
AWorksheet: TsBasicWorksheet): String;
var
sheet: TsWorksheet absolute AWorksheet;
begin
Result := Format('x:Bottom="%g" x:Left="%g" x:Right="%g" x:Top="%g"', [
mmToIn(AWorksheet.PageLayout.BottomMargin),
mmToIn(AWorksheet.PageLayout.LeftMargin),
mmToIn(AWorksheet.PageLayout.RightMargin),
mmToIn(AWorksheet.PageLayout.TopMargin)
mmToIn(sheet.PageLayout.BottomMargin),
mmToIn(sheet.PageLayout.LeftMargin),
mmToIn(sheet.PageLayout.RightMargin),
mmToIn(sheet.PageLayout.TopMargin)
], FPointSeparatorSettings);
Result := '<PageMargins ' + Result + '/>';
end;
@ -366,7 +378,7 @@ begin
WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
end;
if FWorksheet.ReadComment(ACell) <> '' then
if (FWorksheet as TsWorksheet).ReadComment(ACell) <> '' then
WriteComment(AStream, ACell);
end;
@ -380,11 +392,11 @@ var
begin
Unused(ARow, ACol);
ExcelDate := AValue;
fmt := FWorkbook.GetPointerToCellFormat(ACell^.FormatIndex);
fmt := (FWorkbook as TsWorkbook).GetPointerToCellFormat(ACell^.FormatIndex);
// Times have an offset of 1 day!
if (fmt <> nil) and (uffNumberFormat in fmt^.UsedFormattingFields) then
begin
nfp := FWorkbook.GetNumberFormat(fmt^.NumberFormatIndex);
nfp := (FWorkbook as TsWorkbook).GetNumberFormat(fmt^.NumberFormatIndex);
if IsTimeIntervalFormat(nfp) or IsTimeFormat(nfp) then
case FDateMode of
dm1900: ExcelDate := AValue + DATEMODE_1900_BASE;
@ -461,8 +473,8 @@ begin
if Length(ACell^.RichTextParams) > 0 then
begin
RichTextToHTML(
FWorkbook,
FWorksheet.ReadCellFont(ACell),
FWorkbook as TsWorkbook,
(FWorksheet as TsWorksheet).ReadCellFont(ACell),
AValue,
ACell^.RichTextParams,
valueStr, // html-formatted rich text
@ -531,8 +543,10 @@ var
fill: TsFillPattern;
cb: TsCellBorder;
cbs: TsCellBorderStyle;
book: TsWorkbook;
begin
deffnt := FWorkbook.GetDefaultFont;
book := FWorkbook as TsWorkbook;
deffnt := book.GetDefaultFont;
if AIndex = 0 then
begin
AppendToStream(AStream, Format(INDENT2 +
@ -551,7 +565,7 @@ begin
AppendToStream(AStream, Format(INDENT2 +
'<Style ss:ID="s%d">' + LF, [AIndex + FMT_OFFSET]));
fmt := FWorkbook.GetPointerToCellFormat(AIndex);
fmt := book.GetPointerToCellFormat(AIndex);
// Horizontal alignment
fmtHor := '';
@ -600,7 +614,7 @@ begin
// Font
if (uffFont in fmt^.UsedFormattingFields) then
begin
fnt := FWorkbook.GetFont(fmt^.FontIndex);
fnt := book.GetFont(fmt^.FontIndex);
s := '';
if fnt.FontName <> deffnt.FontName then
s := s + Format('ss:FontName="%s" ', [fnt.FontName]);
@ -624,7 +638,7 @@ begin
// Number Format
if (uffNumberFormat in fmt^.UsedFormattingFields) then
begin
nfp := FWorkbook.GetNumberFormat(fmt^.NumberFormatIndex);
nfp := book.GetNumberFormat(fmt^.NumberFormatIndex);
AppendToStream(AStream, Format(INDENT3 +
'<NumberFormat ss:Format="%s"/>' + LF, [UTF8TextToXMLText(nfp.NumFormatStr)]));
end;
@ -685,12 +699,14 @@ var
begin
AppendToStream(AStream, INDENT1 +
'<Styles>' + LF);
for i:=0 to FWorkbook.GetNumCellFormats-1 do WriteStyle(AStream, i);
for i:=0 to (FWorkbook as TsWorkbook).GetNumCellFormats-1 do
WriteStyle(AStream, i);
AppendToStream(AStream, INDENT1 +
'</Styles>' + LF);
end;
procedure TsSpreadExcelXMLWriter.WriteTable(AStream: TStream; AWorksheet: TsWorksheet);
procedure TsSpreadExcelXMLWriter.WriteTable(AStream: TStream;
AWorksheet: TsBasicWorksheet);
var
c, c1, c2: Cardinal;
r, r1, r2: Cardinal;
@ -700,27 +716,28 @@ var
styleStr: String;
col: PCol;
row: PRow;
sheet: TsWorksheet absolute AWorksheet;
begin
r1 := 0;
c1 := 0;
r2 := AWorksheet.GetLastRowIndex;
c2 := AWorksheet.GetLastColIndex;
r2 := sheet.GetLastRowIndex;
c2 := sheet.GetLastColIndex;
AppendToStream(AStream, TABLE_INDENT + Format(
'<Table ss:ExpandedColumnCount="%d" ss:ExpandedRowCount="%d" ' +
'x:FullColumns="1" x:FullRows="1" ' +
'ss:DefaultColumnWidth="%.2f" ' +
'ss:DefaultRowHeight="%.2f">' + LF,
[
AWorksheet.GetLastColIndex + 1, AWorksheet.GetLastRowIndex + 1,
AWorksheet.ReadDefaultColWidth(suPoints),
AWorksheet.ReadDefaultRowHeight(suPoints)
sheet.GetLastColIndex + 1, sheet.GetLastRowIndex + 1,
sheet.ReadDefaultColWidth(suPoints),
sheet.ReadDefaultRowHeight(suPoints)
],
FPointSeparatorSettings
));
for c := c1 to c2 do
begin
col := FWorksheet.FindCol(c);
col := sheet.FindCol(c);
styleStr := '';
colWidthStr := '';
if Assigned(col) then
@ -728,7 +745,7 @@ begin
// column width is needed in pts.
if col^.ColWidthType = cwtCustom then
colwidthStr := Format(' ss:Width="%0.2f" ss:AutoFitWidth="0"',
[FWorkbook.ConvertUnits(col^.Width, FWorkbook.Units, suPoints)],
[(FWorkbook as TsWorkbook).ConvertUnits(col^.Width, FWorkbook.Units, suPoints)],
FPointSeparatorSettings);
// column style
if col^.FormatIndex > 0 then
@ -740,13 +757,13 @@ begin
for r := r1 to r2 do
begin
row := FWorksheet.FindRow(r);
row := sheet.FindRow(r);
styleStr := '';
// Row height is needed in pts.
if Assigned(row) then
begin
rowheightStr := Format(' ss:Height="%.2f"',
[FWorkbook.ConvertUnits(row^.Height, FWorkbook.Units, suPoints)],
[(FWorkbook as TsWorkbook).ConvertUnits(row^.Height, FWorkbook.Units, suPoints)],
FPointSeparatorSettings
);
if row^.RowHeightType = rhtCustom then
@ -760,10 +777,10 @@ begin
'<Row %s%s>' + LF, [rowheightStr, styleStr]));
for c := c1 to c2 do
begin
cell := AWorksheet.FindCell(r, c);
cell := sheet.FindCell(r, c);
if cell <> nil then
begin
if FWorksheet.IsMerged(cell) and not FWorksheet.IsMergeBase(cell) then
if sheet.IsMerged(cell) and not sheet.IsMergeBase(cell) then
Continue;
WriteCellToStream(AStream, cell);
end;
@ -804,7 +821,7 @@ begin
end;
procedure TsSpreadExcelXMLWriter.WriteWorksheet(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
protectedStr: String;
begin
@ -827,7 +844,7 @@ begin
end;
procedure TsSpreadExcelXMLWriter.WriteWorksheetOptions(AStream: TStream;
AWorksheet: TsWorksheet);
AWorksheet: TsBasicWorksheet);
var
footerStr, headerStr: String;
hideGridStr: String;
@ -837,6 +854,7 @@ var
marginStr: String;
selectedStr: String;
protectStr: String;
sheet: TsWorksheet absolute AWorksheet;
begin
// Orientation, some PageLayout.Options
layoutStr := GetLayoutStr(AWorksheet);
@ -864,7 +882,7 @@ begin
hideHeadersStr := INDENT3 + '<DoNotDisplayHeadings/>' + LF else
hideHeadersStr := '';
if FWorkbook.ActiveWorksheet = AWorksheet then
if (FWorkbook as TsWorkbook).ActiveWorksheet = AWorksheet then
selectedStr := INDENT3 + '<Selected/>' + LF else
selectedStr := '';
@ -899,9 +917,11 @@ end;
procedure TsSpreadExcelXMLWriter.WriteWorksheets(AStream: TStream);
var
i: Integer;
book: TsWorkbook;
begin
for i:=0 to FWorkbook.GetWorksheetCount-1 do
WriteWorksheet(AStream, FWorkbook.GetWorksheetByIndex(i));
book := FWorkbook as TsWorkbook;
for i:=0 to book.GetWorksheetCount-1 do
WriteWorksheet(AStream, book.GetWorksheetByIndex(i));
end;

File diff suppressed because it is too large Load Diff