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. }