diff --git a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
index 3d7ebb480..f9e9e3f32 100644
--- a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
+++ b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
@@ -107,7 +107,7 @@
-
+
@@ -139,9 +139,12 @@
-
-
+
+
+
+
+
@@ -149,8 +152,8 @@
-
-
+
+
@@ -160,7 +163,7 @@
-
+
@@ -168,7 +171,7 @@
-
+
@@ -176,7 +179,7 @@
-
+
@@ -184,14 +187,14 @@
-
+
-
+
@@ -199,7 +202,7 @@
-
+
@@ -207,7 +210,7 @@
-
+
@@ -215,27 +218,25 @@
-
+
-
-
-
-
+
+
-
-
-
+
+
+
@@ -243,7 +244,7 @@
-
+
@@ -251,26 +252,23 @@
-
+
-
+
-
+
-
-
-
-
-
-
+
+
+
@@ -279,23 +277,23 @@
-
+
-
+
-
-
-
+
+
+
@@ -305,7 +303,7 @@
-
+
@@ -315,7 +313,7 @@
-
+
@@ -324,7 +322,7 @@
-
+
@@ -332,7 +330,7 @@
-
+
@@ -340,14 +338,14 @@
-
+
-
+
@@ -355,14 +353,14 @@
-
+
-
+
@@ -370,14 +368,14 @@
-
+
-
+
@@ -385,7 +383,7 @@
-
+
@@ -393,7 +391,7 @@
-
+
@@ -401,7 +399,7 @@
-
+
@@ -409,7 +407,7 @@
-
+
@@ -417,7 +415,7 @@
-
+
@@ -425,7 +423,7 @@
-
+
@@ -433,14 +431,14 @@
-
+
-
+
@@ -448,7 +446,7 @@
-
+
@@ -456,7 +454,7 @@
-
+
@@ -464,7 +462,7 @@
-
+
@@ -472,7 +470,7 @@
-
+
@@ -480,14 +478,16 @@
-
+
+
-
-
-
+
+
+
+
@@ -495,7 +495,7 @@
-
+
@@ -503,199 +503,213 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -725,15 +739,6 @@
-
-
-
-
-
-
-
-
-
diff --git a/components/fpspreadsheet/examples/other/test_write_formatting.pas b/components/fpspreadsheet/examples/other/test_write_formatting.pas
index 58879b825..06b65f589 100644
--- a/components/fpspreadsheet/examples/other/test_write_formatting.pas
+++ b/components/fpspreadsheet/examples/other/test_write_formatting.pas
@@ -13,7 +13,7 @@ program test_write_formatting;
uses
Classes, SysUtils, fpspreadsheet, xlsbiff8, fpsopendocument,
- laz_fpspreadsheet, fpsconvencoding;
+ laz_fpspreadsheet;
var
MyWorkbook: TsWorkbook;
diff --git a/components/fpspreadsheet/examples/other/test_write_formula.pas b/components/fpspreadsheet/examples/other/test_write_formula.pas
index 78954fb42..d30b063c4 100644
--- a/components/fpspreadsheet/examples/other/test_write_formula.pas
+++ b/components/fpspreadsheet/examples/other/test_write_formula.pas
@@ -12,7 +12,7 @@ program test_write_formula;
uses
Classes, SysUtils,
fpspreadsheet, xlsbiff5, xlsbiff8, fpsopendocument,
- laz_fpspreadsheet, fpsconvencoding;
+ laz_fpspreadsheet;
var
MyWorkbook: TsWorkbook;
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 463497639..cbc0b8799 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -521,8 +521,8 @@ type
FFirstFormatIndexInFile: Integer;
FNextFormatIndex: Integer;
procedure AddBuiltinFormats; virtual;
- procedure Analyze(var AFormatString: String; var ANumFormat: TsNumberFormat;
- var ADecimals: Word); virtual;
+ procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
+ var ANumFormat: TsNumberFormat; var ADecimals: Word); virtual;
procedure RemoveFormat(AIndex: Integer);
public
constructor Create;
@@ -555,7 +555,7 @@ type
FWorkbook: TsWorkbook;
FWorksheet: TsWorksheet;
FNumFormatList: TsCustomNumFormatList;
- procedure CreateNumFormatList; virtual; abstract;
+ procedure CreateNumFormatList; virtual;
{ Record reading methods }
procedure ReadBlank(AStream: TStream); virtual; abstract;
procedure ReadFormula(AStream: TStream); virtual; abstract;
@@ -587,7 +587,7 @@ type
FNumFormatList: TsCustomNumFormatList;
{ Helper routines }
procedure AddDefaultFormats(); virtual;
- procedure CreateNumFormatList; virtual; abstract;
+ procedure CreateNumFormatList; virtual;
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
function FindFormattingInList(AFormat: PCell): Integer;
procedure FixFormat(ACell: PCell); virtual;
@@ -1480,20 +1480,20 @@ begin
nfLongTime:
ACell^.NumberFormatStr := 'tt';
nfShortTimeAM:
- ACell^.NumberFormatStr := 't am/pm';
+ ACell^.NumberFormatStr := 'hh:nn AM/PM';
nfLongTimeAM:
- ACell^.NumberFormatStr := 'tt am/pm';
+ ACell^.NumberFormatStr := 'hh:nn:ss AM/PM';
nfFmtDateTime:
begin
fmt := lowercase(AFormatStr);
if fmt = 'dm' then ACell^.NumberFormatStr := 'd/mmm'
else if fmt = 'my' then ACell^.NumberFormatStr := 'mmm/yy'
- else if fmt = 'ms' then ACell^.NumberFormatStr := 'mm:ss' // Excel does not like the "n"
- else if fmt = 'msz' then ACell^.NumberFormatStr := 'mm:ss.z'
+ else if fmt = 'ms' then ACell^.NumberFormatStr := 'nn:ss'
+ else if fmt = 'msz' then ACell^.NumberFormatStr := 'nn:ss.z'
else ACell^.NumberFormatStr := AFormatStr;
end;
nfTimeInterval:
- if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:mm:ss'
+ if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:nn:ss'
else ACell^.NumberFormatStr := AFormatStr;
end;
ChangedCell(ARow, ACol);
@@ -2564,10 +2564,14 @@ begin
inc(FNextFormatIndex);
end;
-{ Adds the builtin format items to the list. Must be called before user items
- are added. Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. don't save
- formats <164) and must initialize the index of the first user format
- (FNextFormatIndex) which is automatically incremented when adding user formats. }
+{ Adds the builtin format items to the list. The formats must be specified in
+ a way which can be understood by fpc.
+ If fpc and file speak different languages "translation" must be made in
+ "Analyze" for reading and "FormatStringForWriting" for writing.
+ Must be called before user items are added.
+ Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. doesn't save formats <164)
+ and must initialize the index of the first user format (FNextFormatIndex)
+ which is automatically incremented when adding user formats. }
procedure TsCustomNumFormatList.AddBuiltinFormats;
begin
// must be overridden
@@ -2575,12 +2579,13 @@ end;
{ Takes the format string (AFormatString) as it is read from the file and
extracts the number format type (ANumFormat) and the number of decimals
- (ADecimals) out of it. If the format string cannot be directly handled by
- fpc it has to be transformed to make it compatible. Can be done in
- overridden versions which know more about the structure of the string in
- the actual file format. }
-procedure TsCustomNumFormatList.Analyze(var AFormatString: String;
- var ANumFormat: TsNumberFormat; var ADecimals: Word);
+ (ADecimals) out of it for use by fpc.
+ If the format string cannot be directly handled by fpc it has to be transformed
+ to make it compatible. Can be done in overridden versions which know more
+ about the structure of the string in the actual file format. }
+procedure TsCustomNumFormatList.Analyze(AFormatIndex: Integer;
+ var AFormatString: String; var ANumFormat: TsNumberFormat;
+ var ADecimals: Word);
const
SHORT_LONG_DATE: array[boolean] of TsNumberFormat = (
nfShortDate, nfLongDate
@@ -2600,7 +2605,42 @@ var
isInterval: Boolean;
isSci: Boolean;
isTime, isDate: Boolean;
+ lFormatData: TsNumFormatData;
+ i: Integer;
+ fmt: String;
begin
+ { Check the built-in formats first }
+ i := Find(AFormatIndex);
+ if i > 0 then begin
+ lFormatData := Items[i];
+ case lFormatData.NumFormat of
+ nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
+ begin
+ ANumFormat := lFormatData.NumFormat;
+ AFormatString := lFormatData.FormatString;
+ ADecimals := lFormatData.Decimals;
+ exit;
+ end;
+ nfShortDateTime, nfShortDate, nfLongDate,
+ nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval:
+ begin
+ ANumFormat := lFormatData.NumFormat;
+ AFormatString := lFormatData.FormatString;
+ ADecimals := 0;
+ exit;
+ end;
+ nfFmtDateTime:
+ begin
+ ANumFormat := lFormatData.NumFormat;
+ AFormatString := lFormatData.FormatString;
+ IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
+ exit;
+ end;
+ end;
+ end;
+
+ { Then check the non-standard formats. There is a chance that they may not be
+ reckognized correctly... }
ANumFormat := nfGeneral;
if IsPercentNumberFormat(AFormatString, ADecimals) then
ANumFormat := nfPercentage
@@ -2648,7 +2688,7 @@ begin
raise Exception.Create('TsCustomNumFormatList.AnalyzeAndAdd: Format index must be unique.');
// Analyze the format string and extract information for internal formatting
- Analyze(AFormatString, nf, decs);
+ Analyze(AFormatIndex, AFormatString, nf, decs);
// Add the new item
AddFormat(AFormatIndex, nf, AFormatString, decs);
@@ -2828,6 +2868,12 @@ begin
inherited Destroy;
end;
+procedure TsCustomSpreadReader.CreateNumFormatList;
+begin
+ { The format list needs to be created by descendants who know about the
+ special requirements of the file format. }
+end;
+
{@@
Default file reading method.
@@ -2979,6 +3025,12 @@ begin
NextXFIndex := 0;
end;
+procedure TsCustomSpreadWriter.CreateNumFormatList;
+begin
+ { The format list needs to be created by descendants who know about the
+ special requirements of the file format. }
+end;
+
procedure TsCustomSpreadWriter.ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
var
Len: Integer;
diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas
index b761389aa..7e64a6eea 100644
--- a/components/fpspreadsheet/fpsutils.pas
+++ b/components/fpspreadsheet/fpsutils.pas
@@ -653,8 +653,11 @@ end;
{ IsDateFormat checks if the format string s corresponds to a date format }
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
begin
+ s := Lowercase(s);
// Day, month, year are separated by a slash
- Result := (pos('/', s) > 0);
+ // We also check part of the year/month/day symbol because there may be
+ // other control code with a slash.
+ Result := (pos('y/', s) > 0) or (pos('m/', s) > 0) or (pos('/m', s) > 0) or (pos('/d', s) > 0);
if Result then
// Check validity of format string
try
@@ -688,6 +691,13 @@ begin
count := 1;
s := Uppercase(s);
+ // Seek for "H:MM:SS" or "H:MM" to see if it is a long or short time format.
+ if pos('H:MM:SS', s) <> 0 then
+ isLong := true
+ else
+ if pos('H:MM', s) <> 0 then
+ isLong := false
+ else
// If there are is a second colon s is a "long" time format
for i:=p+1 to Length(s) do
if s[i] = ':' then begin
@@ -698,9 +708,11 @@ begin
// Seek for "AM/PM" etc to detect that specific format
isAMPM := (pos('AM/PM', s) > 0) or (pos('A/P', s) > 0) or (pos('AMPM', s) > 0);
- // Look for square brackets indicating the interval format.
- p := pos('[', s);
- if p > 0 then isInterval := (pos(']', s) > 0) else isInterval := false;
+ // Look for special square bracket symbols indicating the interval format.
+ isInterval := (pos('[H]', s) <> 0) or (pos('[HH]', s) <> 0) or
+ (pos('[M]', s) <> 0) or (pos('[MM]', s) <> 0) or
+ (pos('[N]', s) <> 0) or (pos('[NN]', s) <> 0) or
+ (pos('[S]', s) <> 0) or (pos('[SS]', s) <> 0);
// Count decimals
pdp := pos('.', s);
diff --git a/components/fpspreadsheet/tests/formattests.pas b/components/fpspreadsheet/tests/formattests.pas
index 7150d29f1..a2d8cb28b 100644
--- a/components/fpspreadsheet/tests/formattests.pas
+++ b/components/fpspreadsheet/tests/formattests.pas
@@ -182,10 +182,10 @@ begin
for i:=Low(SollDateTimes) to High(SollDateTimes) do begin
SollDateTimeStrings[i, 0] := DateToStr(SollDateTimes[i]) + ' ' + FormatDateTime('t', SollDateTimes[i]);
SollDateTimeStrings[i, 1] := DateToStr(SollDateTimes[i]);
- SollDateTimeStrings[i, 2] := FormatDateTime('t', SollDateTimes[i]);
- SolLDateTimeStrings[i, 3] := FormatDateTime('tt', SollDateTimes[i]);
- SollDateTimeStrings[i, 4] := FormatDateTime('t am/pm', SollDateTimes[i]);
- SollDateTimeStrings[i, 5] := FormatDateTime('tt am/pm', SollDateTimes[i]);
+ SollDateTimeStrings[i, 2] := FormatDateTime('hh:nn', SollDateTimes[i]);
+ SolLDateTimeStrings[i, 3] := FormatDateTime('hh:nn:ss', SollDateTimes[i]);
+ SollDateTimeStrings[i, 4] := FormatDateTime('hh:nn am/pm', SollDateTimes[i]); // dont't use "t" - it does the hours wrong
+ SollDateTimeStrings[i, 5] := FormatDateTime('hh:nn:ss am/pm', SollDateTimes[i]);
SollDateTimeStrings[i, 6] := FormatDateTime('dd/mmm', SollDateTimes[i]);
SollDateTimeStrings[i, 7] := FormatDateTime('mmm/yy', SollDateTimes[i]);
SollDateTimeStrings[i, 8] := FormatDateTime('nn:ss', SollDateTimes[i]);
@@ -331,7 +331,11 @@ begin
Continue; // The formats nfFmtDateTime and nfTimeInterval are not supported by BIFF2
MyWorksheet.WriteDateTime(Row, Col, SollDateTimes[Row], SollDateTimeFormats[Col], SollDateTimeFormatStrings[Col]);
ActualString := MyWorksheet.ReadAsUTF8Text(Row, Col);
- CheckEquals(SollDateTimeStrings[Row, Col], ActualString, 'Test unsaved string mismatch cell ' + CellNotation(MyWorksheet,Row,Col));
+ CheckEquals(
+ Lowercase(SollDateTimeStrings[Row, Col]),
+ Lowercase(ActualString),
+ 'Test unsaved string mismatch cell ' + CellNotation(MyWorksheet,Row,Col)
+ );
end;
MyWorkBook.WriteToFile(TempFile, AFormat, true);
MyWorkbook.Free;
@@ -350,7 +354,11 @@ begin
if (AFormat = sfExcel2) and (SollDateTimeFormats[Col] in [nfFmtDateTime, nfTimeInterval]) then
Continue; // The formats nfFmtDateTime and nfTimeInterval are not supported by BIFF2
ActualString := MyWorksheet.ReadAsUTF8Text(Row,Col);
- CheckEquals(SollDateTimeStrings[Row, Col], ActualString, 'Test saved string mismatch cell '+CellNotation(MyWorksheet,Row,Col));
+ CheckEquals(
+ Lowercase(SollDateTimeStrings[Row, Col]),
+ Lowercase(ActualString),
+ 'Test saved string mismatch cell '+CellNotation(MyWorksheet,Row,Col)
+ );
end;
// Finalization
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index df8c00827..3aa2ff85b 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -348,6 +348,8 @@ type
TsBIFFNumFormatList = class(TsCustomNumFormatList)
protected
procedure AddBuiltinFormats; override;
+ procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
+ var ANumFormat: TsNumberFormat; var ADecimals: Word); override;
public
function FormatStringForWriting(AIndex: Integer): String; override;
end;
@@ -478,32 +480,6 @@ implementation
uses
StrUtils;
-const
- { see ➜ 5.49 }
- COUNT_DEFAULT_FORMATS = 58;
- NOT_USED = nfGeneral;
- DEFAULT_NUM_FORMATS: array[1..COUNT_DEFAULT_FORMATS] of TsNumberFormat = (
- nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
- nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
- nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15
- nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20
- nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35
- NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40
- nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45
- nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55
- NOT_USED, NOT_USED, NOT_USED // 56..58
- );
- DEFAULT_NUM_FORMAT_DECIMALS: array[1..COUNT_DEFAULT_FORMATS] of word = (
- 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
- 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11..20
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21..30
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, // 31..40
- 0, 0, 2, 2, 0, 3, 0, 1, 0, 0, // 41..50 #48 is "scientific", use "exponential" instead
- 0, 0, 0, 0, 0, 0, 0, 0); // 51..58
-
function ConvertExcelDateTimeToDateTime(
const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
begin
@@ -574,17 +550,17 @@ begin
// fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
AddFormat(14, nfShortDate);
AddFormat(15, nfLongDate);
- AddFormat(16, nfFmtDateTime, 'D-MMM');
- AddFormat(17, nfFmtDateTime, 'MMM-YY');
+ AddFormat(16, nfFmtDateTime, 'd/mmm');
+ AddFormat(17, nfFmtDateTime, 'mmm/yy');
AddFormat(18, nfShortTimeAM);
AddFormat(19, nfLongTimeAM);
AddFormat(20, nfShortTime);
AddFormat(21, nfLongTime);
AddFormat(22, nfShortDateTime);
// 23..44 not supported
- AddFormat(45, nfFmtDateTime, 'mm:ss');
- AddFormat(46, nfTimeInterval, '[h]:mm:ss');
- AddFormat(47, nfFmtDateTime, 'mm:ss.z'); // z will be replace by 0 later
+ AddFormat(45, nfFmtDateTime, 'nn:ss');
+ AddFormat(46, nfTimeInterval, '[h]:nn:ss');
+ AddFormat(47, nfFmtDateTime, 'nn:ss.z'); // z will be replace by 0 later
AddFormat(48, nfSci, '##0.0E+0', 1);
// 49 ("Text") not supported
@@ -594,6 +570,51 @@ begin
FNextFormatIndex := 164;
end;
+{ Considers some Excel specialities for format detection.
+ The output values will be passed to fpc. }
+procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
+ var AFormatString: String; var ANumFormat: TsNumberFormat;
+ var ADecimals: Word);
+var
+ fmt: String;
+begin
+ fmt := Lowercase(AFormatString);
+ { Check the built-in formats first }
+ if (pos('[$-F400]', AFormatString) = 1) then begin
+ ANumFormat := nfLongTime;
+ AFormatString := ''; // will be replaced by system's format setting
+ ADecimals := 0;
+ exit;
+ end;
+ if (pos('[$', fmt) = 1) then begin
+ if (pos('h:mm:ss\', fmt) > 0) then begin
+ // long time format
+ if (pos('am/pm', fmt) > 0) or (pos('a/p',fmt) > 0) then begin
+ ANumFormat := nfLongTimeAM;
+ AFormatString := '';
+ end else begin
+ ANumFormat := nfLongTime;
+ AFormatString := '';
+ end;
+ ADecimals := 0;
+ exit;
+ end;
+ if (pos('h:mm\', fmt) > 0) then begin
+ if (pos('am/pm', fmt) > 0) or (pos ('a/p', fmt) > 0) then begin
+ ANumFormat := nfShortTimeAM;
+ AFormatString := '';
+ end else begin
+ ANumFormat := nfShortTime;
+ AFormatString := '';
+ end;
+ end;
+ ADecimals := 0;
+ exit;
+ end;
+
+ inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals);
+end;
+
{ Creates formatting strings that are written into the file. }
function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
var
@@ -606,8 +627,12 @@ begin
nfFmtDateTime:
begin
Result := lowercase(item.FormatString);
- for i:=1 to Length(Result) do
+ for i:=1 to Length(Result) do begin
+ // The milliseccond format contains the symbol "z" in fpc, but Excel wants "0"
if Result[i] in ['z', 'Z'] then Result[i] := '0';
+ // The minutes in short time formats are coded by "n" in fpc, but Excel wants "m".
+ if Result[i] in ['n', 'N'] then Result[i] := 'm';
+ end;
end;
nfTimeInterval:
// Time interval format string could still be without square brackets
diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas
index b339ef0ac..9d455d412 100755
--- a/components/fpspreadsheet/xlsxooxml.pas
+++ b/components/fpspreadsheet/xlsxooxml.pas
@@ -41,6 +41,20 @@ uses
type
+ { TsOOXMLFormatList }
+ TsOOXMLNumFormatList = class(TsCustomNumFormatList)
+ protected
+ {
+ procedure AddBuiltinFormats; override;
+ procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
+ var ANumFormat: TsNumberFormat; var ADecimals: Word); override;
+ }
+ public
+ {
+ function FormatStringForWriting(AIndex: Integer): String; override;
+ }
+ end;
+
{ TsSpreadOOXMLWriter }
TsSpreadOOXMLWriter = class(TsCustomSpreadWriter)
@@ -52,22 +66,30 @@ type
FWorkbookString, FWorkbookRelsString, FStylesString, FSharedStrings: string;
FSheets: array of string;
FSharedStringsCount: Integer;
+
+ protected
+ { Helper routines }
+ procedure CreateNumFormatList; override;
+ protected
{ Streams with the contents of files }
FSContentTypes: TStringStream;
FSRelsRels: TStringStream;
FSWorkbook, FSWorkbookRels, FSStyles, FSSharedStrings: TStringStream;
FSSheets: array of TStringStream;
FCurSheetNum: Integer;
+ protected
{ Routines to write those files }
procedure WriteGlobalFiles;
procedure WriteContent;
procedure WriteWorksheet(CurSheet: TsWorksheet);
function GetStyleIndex(ACell: PCell): Cardinal;
+ protected
{ Record writing methods }
//todo: add WriteDate
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); override;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); override;
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; const AValue: TDateTime; ACell: PCell); override;
+
public
constructor Create(AWorkbook: TsWorkbook); override;
destructor Destroy; override;
@@ -114,6 +136,7 @@ const
MIME_STYLES = MIME_SPREADML + '.styles+xml';
MIME_STRINGS = MIME_SPREADML + '.sharedStrings+xml';
+
{ TsSpreadOOXMLWriter }
procedure TsSpreadOOXMLWriter.WriteGlobalFiles;
@@ -367,6 +390,12 @@ begin
inherited Destroy;
end;
+procedure TsSpreadOOXMLWriter.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsOOXMLNumFormatList.Create;
+end;
+
{
Writes a string to a file. Helper convenience method.
}