diff --git a/components/fpspreadsheet/examples/read_write/excel2demo/excel2write.lpr b/components/fpspreadsheet/examples/read_write/excel2demo/excel2write.lpr index fa234474e..9214e6395 100644 --- a/components/fpspreadsheet/examples/read_write/excel2demo/excel2write.lpr +++ b/components/fpspreadsheet/examples/read_write/excel2demo/excel2write.lpr @@ -254,11 +254,9 @@ begin inc(r); MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)'); MyWorksheet.WriteNumber(r, 1, number); - MyWorksheet.WriteFontColor(r, 1, NA_COLOR); MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)'); MyWorksheet.WriteNumber(r, 2, -number); MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0_);("$"#,##0)'); - MyWorksheet.WriteFontColor(r, 2, NA_COLOR); inc(r); MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)'); MyWorksheet.WriteNumber(r, 1, number); diff --git a/components/fpspreadsheet/examples/visual/fpsctrls/demo_ctrls.lpi b/components/fpspreadsheet/examples/visual/fpsctrls/demo_ctrls.lpi index 6a13ccd1b..fda5e2a34 100644 --- a/components/fpspreadsheet/examples/visual/fpsctrls/demo_ctrls.lpi +++ b/components/fpspreadsheet/examples/visual/fpsctrls/demo_ctrls.lpi @@ -127,9 +127,6 @@ - - - diff --git a/components/fpspreadsheet/examples/visual/fpsctrls/main.lfm b/components/fpspreadsheet/examples/visual/fpsctrls/main.lfm index b99afd30a..6ae395f94 100644 --- a/components/fpspreadsheet/examples/visual/fpsctrls/main.lfm +++ b/components/fpspreadsheet/examples/visual/fpsctrls/main.lfm @@ -105,7 +105,7 @@ object MainForm: TMainForm 'Font1=Arial; size 10; blue; underline' 'Font2=Arial; size 10; black; bold' 'Font3=Arial; size 10; black; italic' - 'CellFormat0=' + 'CellFormat0=nfGeneral' ) TitleCaptions.Strings = ( 'Properties' @@ -820,6 +820,34 @@ object MainForm: TMainForm Hint = 'Currency format (negative values in red)' NumberFormat = nfCurrencyRed end + object AcNumFormatExp: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Exponential' + Hint = 'Exponential format' + NumberFormat = nfExp + end + object AcNumFormatFraction1: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Fraction (1 digit)' + NumberFormat = nfFraction + NumberFormatString = '# #/#' + end + object AcNumFormatFraction2: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Fraction (2 digits)' + NumberFormat = nfFraction + NumberFormatString = '# ##/##' + end + object AcNumFormatFraction3: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Fraction (3 digits)' + NumberFormat = nfFraction + NumberFormatString = '# ###/###' + end object AcFileOpen: TFileOpen Category = 'File' Caption = '&Open ...' @@ -874,6 +902,12 @@ object MainForm: TMainForm ImageIndex = 49 OnExecute = AcColDeleteExecute end + object AcSettingsFormatSettings: TAction + Category = 'Settings' + Caption = 'Number format settings...' + Hint = 'Define number format settings' + OnExecute = AcSettingsFormatSettingsExecute + end object AcSettingsCSVParams: TAction Category = 'Settings' Caption = 'CSV parameters...' @@ -886,40 +920,6 @@ object MainForm: TMainForm Hint = 'Define currency symbols' OnExecute = AcSettingsCurrencyExecute end - object AcSettingsFormatSettings: TAction - Category = 'Settings' - Caption = 'Number format settings...' - Hint = 'Define number format settings' - OnExecute = AcSettingsFormatSettingsExecute - end - object AcNumFormatExp: TsNumberFormatAction - Category = 'FPSpreadsheet' - WorkbookSource = WorkbookSource - Caption = 'Exponential' - Hint = 'Exponential format' - NumberFormat = nfExp - end - object AcNumFormatFraction1: TsNumberFormatAction - Category = 'FPSpreadsheet' - WorkbookSource = WorkbookSource - Caption = 'Fraction (1 digit)' - NumberFormat = nfFraction - NumberFormatString = '# #/#' - end - object AcNumFormatFraction2: TsNumberFormatAction - Category = 'FPSpreadsheet' - WorkbookSource = WorkbookSource - Caption = 'Fraction (2 digits)' - NumberFormat = nfFraction - NumberFormatString = '# ##/##' - end - object AcNumFormatFraction3: TsNumberFormatAction - Category = 'FPSpreadsheet' - WorkbookSource = WorkbookSource - Caption = 'Fraction (3 digits)' - NumberFormat = nfFraction - NumberFormatString = '# ###/###' - end object AcNumFormatDateTime: TsNumberFormatAction Category = 'FPSpreadsheet' WorkbookSource = WorkbookSource @@ -941,6 +941,20 @@ object MainForm: TMainForm Hint = 'Short date format' NumberFormat = nfShortDate end + object AcNumFormatDayMonth: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Day and month' + Hint = 'Day and month only' + NumberFormat = nfDayMonth + end + object AcNumFormatMonthYear: TsNumberFormatAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Month and year' + Hint = 'Month and year only' + NumberFormat = nfMonthYear + end object AcNumFormatLongTime: TsNumberFormatAction Category = 'FPSpreadsheet' WorkbookSource = WorkbookSource @@ -5057,6 +5071,17 @@ object MainForm: TMainForm Action = AcNumFormatShortDate AutoCheck = True end + object MenuItem118: TMenuItem + Caption = '-' + end + object MenuItem119: TMenuItem + Action = AcNumFormatDayMonth + AutoCheck = True + end + object MenuItem120: TMenuItem + Action = AcNumFormatMonthYear + AutoCheck = True + end end object PuTimeFormat: TPopupMenu left = 504 diff --git a/components/fpspreadsheet/examples/visual/fpsctrls/main.pas b/components/fpspreadsheet/examples/visual/fpsctrls/main.pas index db41a7946..8ad5f771b 100644 --- a/components/fpspreadsheet/examples/visual/fpsctrls/main.pas +++ b/components/fpspreadsheet/examples/visual/fpsctrls/main.pas @@ -48,6 +48,9 @@ type MenuItem115: TMenuItem; MenuItem116: TMenuItem; MenuItem117: TMenuItem; + MenuItem118: TMenuItem; + MenuItem119: TMenuItem; + MenuItem120: TMenuItem; MnuSettings: TMenuItem; MenuItem11: TMenuItem; MenuItem12: TMenuItem; @@ -235,6 +238,8 @@ type AcNumFormatFraction2: TsNumberFormatAction; AcNumFormatFraction1: TsNumberFormatAction; AcNumFormatFraction3: TsNumberFormatAction; + AcNumFormatDayMonth: TsNumberFormatAction; + AcNumFormatMonthYear: TsNumberFormatAction; Splitter2: TSplitter; Splitter3: TSplitter; ToolBar2: TToolBar; diff --git a/components/fpspreadsheet/examples/visual/spready/mainform.lfm b/components/fpspreadsheet/examples/visual/spready/mainform.lfm index 370e581a2..1f53e80ec 100644 --- a/components/fpspreadsheet/examples/visual/spready/mainform.lfm +++ b/components/fpspreadsheet/examples/visual/spready/mainform.lfm @@ -1303,11 +1303,11 @@ object MainFrm: TMainFrm AutoCheck = True end object MenuItem54: TMenuItem - Action = AcNFCustomDM + Action = AcNFDayMonth AutoCheck = True end object MenuItem55: TMenuItem - Action = AcNFCustomMY + Action = AcNFMonthDay AutoCheck = True end object MenuItem61: TMenuItem @@ -3077,98 +3077,98 @@ object MainFrm: TMainFrm OnExecute = AcNumFormatExecute end object AcNFCurrency: TAction - Tag = 1050 + Tag = 1060 Category = 'Format' AutoCheck = True Caption = 'Currency' OnExecute = AcNumFormatExecute end object AcNFCurrencyRed: TAction - Tag = 1060 + Tag = 1070 Category = 'Format' AutoCheck = True Caption = 'Currency (negative values in red)' OnExecute = AcNumFormatExecute end object AcNFShortDateTime: TAction - Tag = 1070 + Tag = 1080 Category = 'Format' AutoCheck = True Caption = 'Date + time' OnExecute = AcNumFormatExecute end object AcNFShortDate: TAction - Tag = 1080 + Tag = 1090 Category = 'Format' AutoCheck = True Caption = 'Short date' OnExecute = AcNumFormatExecute end object AcNFLongDate: TAction - Tag = 1090 + Tag = 1100 Category = 'Format' AutoCheck = True Caption = 'Long date' OnExecute = AcNumFormatExecute end - object AcNFCustomDM: TAction - Tag = 1151 - Category = 'Format' - AutoCheck = True - Caption = 'Day + month' - OnExecute = AcNumFormatExecute - end - object AcNFCustomMY: TAction - Tag = 1152 - Category = 'Format' - AutoCheck = True - Caption = 'Month + year' - OnExecute = AcNumFormatExecute - end object AcNFShortTime: TAction - Tag = 1100 + Tag = 1110 Category = 'Format' AutoCheck = True Caption = 'Short time' OnExecute = AcNumFormatExecute end object AcNFLongTime: TAction - Tag = 1110 + Tag = 1120 Category = 'Format' AutoCheck = True Caption = 'Long time' OnExecute = AcNumFormatExecute end object AcNFShortTimeAM: TAction - Tag = 1120 + Tag = 1130 Category = 'Format' AutoCheck = True Caption = 'Short time AM/PM' OnExecute = AcNumFormatExecute end object AcNFLongTimeAM: TAction - Tag = 1130 + Tag = 1140 Category = 'Format' AutoCheck = True Caption = 'Long time AM/PM' OnExecute = AcNumFormatExecute end + object AcNFDayMonth: TAction + Tag = 1150 + Category = 'Format' + AutoCheck = True + Caption = 'Day + month' + OnExecute = AcNumFormatExecute + end + object AcNFMonthDay: TAction + Tag = 1160 + Category = 'Format' + AutoCheck = True + Caption = 'Month + year' + OnExecute = AcNumFormatExecute + end object AcNFCusstomMS: TAction - Tag = 1153 + Tag = 1181 Category = 'Format' AutoCheck = True Caption = 'Minutes + seconds' OnExecute = AcNumFormatExecute end object AcNFCustomMSZ: TAction - Tag = 1154 + Tag = 1182 Category = 'Format' AutoCheck = True Caption = 'Minutes + seconds + milliseconds' OnExecute = AcNumFormatExecute end object AcNFTimeInterval: TAction - Tag = 1140 + Tag = 1170 Category = 'Format' AutoCheck = True Caption = 'Time interval' @@ -4001,11 +4001,11 @@ object MainFrm: TMainFrm AutoCheck = True end object MnuFmtDateTimeDM: TMenuItem - Action = AcNFCustomDM + Action = AcNFDayMonth AutoCheck = True end object MnuFmtDateTimeMY: TMenuItem - Action = AcNFCustomMY + Action = AcNFMonthDay AutoCheck = True end object MenuItem43: TMenuItem diff --git a/components/fpspreadsheet/examples/visual/spready/mainform.pas b/components/fpspreadsheet/examples/visual/spready/mainform.pas index f261c718c..e182f585c 100644 --- a/components/fpspreadsheet/examples/visual/spready/mainform.pas +++ b/components/fpspreadsheet/examples/visual/spready/mainform.pas @@ -66,8 +66,8 @@ type AcNFShortTimeAM: TAction; AcNFLongTimeAM: TAction; AcNFTimeInterval: TAction; - AcNFCustomDM: TAction; - AcNFCustomMY: TAction; + AcNFDayMonth: TAction; + AcNFMonthDay: TAction; AcNFCusstomMS: TAction; AcNFCustomMSZ: TAction; AcNew: TAction; @@ -716,7 +716,7 @@ end; procedure TMainFrm.AcNumFormatExecute(Sender: TObject); const - DATETIME_CUSTOM: array[0..4] of string = ('', 'dd/mmm', 'mmm/yy', 'nn:ss', 'nn:ss.zzz'); + DATETIME_CUSTOM: array[0..2] of string = ('', 'nn:ss', 'nn:ss.zzz'); var c, r: Cardinal; cell: PCell; @@ -1417,14 +1417,12 @@ begin Worksheet.ReadNumFormat(cell, nf, nfs); for i:=0 to ActionList.ActionCount-1 do begin ac := TAction(ActionList.Actions[i]); - if (ac.Tag >= NUMFMT_TAG) and (ac.Tag < NUMFMT_TAG + 200) then begin + if (ac.Tag >= NUMFMT_TAG) and (ac.Tag < NUMFMT_TAG + 300) then begin found := ((ac.Tag - NUMFMT_TAG) div 10 = ord(nf)); if nf = nfCustom then case (ac.Tag - NUMFMT_TAG) mod 10 of - 1: found := nfs = 'dd/mmm'; - 2: found := nfs = 'mmm/yy'; - 3: found := nfs = 'nn:ss'; - 4: found := nfs = 'nn:ss.z'; + 1: found := nfs = 'nn:ss'; + 2: found := nfs = 'nn:ss.z'; end; ac.Checked := found; end; diff --git a/components/fpspreadsheet/fpsnumformat.pas b/components/fpspreadsheet/fpsnumformat.pas index bfd8a5884..bb12f721c 100644 --- a/components/fpspreadsheet/fpsnumformat.pas +++ b/components/fpspreadsheet/fpsnumformat.pas @@ -26,7 +26,7 @@ type constructor Create(AWorkbook: TsWorkbook; AOwnsData: Boolean); destructor Destroy; override; function AddFormat(ASections: TsNumFormatSections): Integer; overload; - function AddFormat(AFormatStr: String; ADialect: TsNumFormatDialect): Integer; overload; + function AddFormat(AFormatStr: String): Integer; overload; procedure Clear; procedure Delete(AIndex: Integer); function Find(ASections: TsNumFormatSections): Integer; @@ -214,14 +214,13 @@ begin end; end; -function TsNumFormatList.AddFormat(AFormatStr: String; - ADialect: TsNumFormatDialect): Integer; +function TsNumFormatList.AddFormat(AFormatStr: String): Integer; var parser: TsNumFormatParser; newSections: TsNumFormatSections; i: Integer; begin - parser := TsNumFormatParser.Create(FWorkbook, AFormatStr, ADialect); + parser := TsNumFormatParser.Create(FWorkbook, AFormatStr); try SetLength(newSections, parser.ParsedSectionCount); for i:=0 to High(newSections) do diff --git a/components/fpspreadsheet/fpsnumformatparser.pas b/components/fpspreadsheet/fpsnumformatparser.pas index a6de8c392..84f390ca1 100644 --- a/components/fpspreadsheet/fpsnumformatparser.pas +++ b/components/fpspreadsheet/fpsnumformatparser.pas @@ -20,7 +20,10 @@ const psErrNoValidNumberFormat = 6; psErrNoValidDateTimeFormat = 7; psErrQuoteExpected = 8; - psAmbiguousSymbol = 9; + psErrMultipleCurrSymbols = 9; + psErrMultipleFracSymbols = 10; + psErrMultipleExpChars = 11; + psAmbiguousSymbol = 12; type @@ -35,13 +38,12 @@ type FEnd: PChar; FCurrSection: Integer; FStatus: Integer; - FDialect: TsNumFormatDialect; function GetCurrencySymbol: String; function GetDecimals: byte; function GetFracDenominator: Integer; function GetFracInt: Integer; function GetFracNumerator: Integer; - function GetFormatString(ADialect: TsNumFormatDialect): String; + function GetFormatString: String; function GetNumFormat: TsNumberFormat; function GetParsedSectionCount: Integer; function GetParsedSections(AIndex: Integer): TsNumFormatSection; @@ -86,7 +88,7 @@ type procedure CheckSection(ASection: Integer); procedure FixMonthMinuteToken(ASection: Integer); // Format string - function BuildFormatString(ADialect: TsNumFormatDialect): String; virtual; + function BuildFormatString: String; virtual; // Token analysis function GetTokenIntValueAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Integer; @@ -96,8 +98,7 @@ type function IsTokenAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Boolean; public - constructor Create(AWorkbook: TsWorkbook; const AFormatString: String; - ADialect: TsNumFormatDialect = nfdDefault); + constructor Create(AWorkbook: TsWorkbook; const AFormatString: String); destructor Destroy; override; procedure ClearAll; function GetDateTimeCode(ASection: Integer): String; @@ -108,7 +109,7 @@ type property CurrencySymbol: String read GetCurrencySymbol; property Decimals: Byte read GetDecimals write SetDecimals; - property FormatString[ADialect: TsNumFormatDialect]: String read GetFormatString; + property FormatString: String read GetFormatString; property FracDenominator: Integer read GetFracDenominator; property FracInt: Integer read GetFracInt; property FracNumerator: Integer read GetFracNumerator; @@ -128,17 +129,13 @@ uses { TsNumFormatParser } {@@ Creates a number format parser for analyzing a formatstring that has been - read from a spreadsheet file. - In case of "red" number formats we also have to specify the number format - because the format string might not contain the color information, and we - extract it from the NumFormat in this case. } + read from a spreadsheet file. } constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook; - const AFormatString: String; ADialect: TsNumFormatDialect = nfdDefault); + const AFormatString: String); begin inherited Create; FCreateMethod := 0; FWorkbook := AWorkbook; - FDialect := ADialect; Parse(AFormatString); CheckSections; end; @@ -236,14 +233,14 @@ end; { Creates a formatstring for all sections. Note: this implementation is only valid for the fpc and Excel dialects of format string. } -function TsNumFormatParser.BuildFormatString(ADialect: TsNumFormatDialect): String; +function TsNumFormatParser.BuildFormatString: String; var i: Integer; begin if Length(FSections) > 0 then begin - Result := BuildFormatStringFromSection(FSections[0], ADialect); + Result := BuildFormatStringFromSection(FSections[0]); for i:=1 to High(FSections) do - Result := Result + ';' + BuildFormatStringFromSection(FSections[i], ADialect); + Result := Result + ';' + BuildFormatStringFromSection(FSections[i]); end; end; @@ -262,9 +259,9 @@ end; procedure TsNumFormatParser.CheckSection(ASection: Integer); var - el, next: Integer; + el, next, i: Integer; section: PsNumFormatSection; - nfs: String; + nfs, nfsTest: String; nf: TsNumberFormat; datetimeFormats: set of TsNumberformat; f1,f2: Integer; @@ -281,13 +278,23 @@ begin nftPercent: section^.Kind := section^.Kind + [nfkPercent]; nftExpChar: - section^.Kind := section^.Kind + [nfkExp]; + if (nfkExp in section^.Kind) then + FStatus := psErrMultipleExpChars + else + section^.Kind := section^.Kind + [nfkExp]; nftFracSymbol: - section^.Kind := section^.Kind + [nfkFraction]; + if (nfkFraction in section^.Kind) then + FStatus := psErrMultipleFracSymbols + else + section^.Kind := section^.Kind + [nfkFraction]; nftCurrSymbol: begin - section^.Kind := section^.Kind + [nfkCurrency]; - section^.CurrencySymbol := section^.Elements[el].TextValue; + if (nfkCurrency in section^.Kind) then + FStatus := psErrMultipleCurrSymbols + else begin + section^.Kind := section^.Kind + [nfkCurrency]; + section^.CurrencySymbol := section^.Elements[el].TextValue; + end; end; nftYear, nftMonth, nftDay: section^.Kind := section^.Kind + [nfkDate]; @@ -299,6 +306,9 @@ begin end; end; + if FStatus <> psOK then + exit; + if (section^.Kind * [nfkDate, nfkTime] <> []) and (section^.Kind * [nfkPercent, nfkExp, nfkCurrency, nfkFraction] <> []) then begin @@ -311,7 +321,7 @@ begin if (section^.Kind * [nfkDate, nfkTime] <> []) then begin FixMonthMinuteToken(ASection); - nfs := FormatString[nfdDefault]; + nfs := GetFormatString; if (nfkTimeInterval in section^.Kind) then section^.NumFormat := nfTimeInterval else @@ -319,11 +329,31 @@ begin datetimeFormats := [nfShortDateTime, nfLongDate, nfShortDate, nfLongTime, nfShortTime, nfLongTimeAM, nfShortTimeAM, nfDayMonth, nfMonthYear]; for nf in datetimeFormats do + begin + nfsTest := BuildDateTimeFormatString(nf, FWorkbook.FormatSettings); + if Length(nfsTest) = Length(nfs) then + begin + for i := 1 to Length(nfsTest) do + case nfsTest[i] of + '/': if not (nf in [nfLongTimeAM, nfShortTimeAM]) then + nfsTest[i] := FWorkbook.FormatSettings.DateSeparator; + ':': nfsTest[i] := FWorkbook.FormatSettings.TimeSeparator; + 'n': nfsTest[i] := 'm'; + end; + if SameText(nfs, nfsTest) then + begin + section^.NumFormat := nf; + break; + end; + end; +{ if SameText(nfs, BuildDateTimeFormatString(nf, FWorkbook.FormatSettings)) then begin section^.NumFormat := nf; break; end; + } + end; end; end else begin @@ -535,9 +565,9 @@ begin FSections[ASection].Elements[AIndex+1].FloatValue := AFloatValue; end; -function TsNumFormatParser.GetFormatString(ADialect: TsNumFormatDialect): String; +function TsNumFormatParser.GetFormatString: String; begin - Result := BuildFormatString(ADialect); + Result := BuildFormatString; end; { Extracts the currency symbol form the formatting sections. It is assumed that diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index bfb41514a..c94d7e931 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -150,7 +150,7 @@ type procedure CreateStreams; procedure DestroyStreams; procedure ListAllColumnStyles; - procedure ListAllNumFormats(ADialect: TsNumFormatDialect); override; + procedure ListAllNumFormats; override; procedure ListAllRowStyles; procedure ResetStreams; @@ -2562,7 +2562,7 @@ end; { Contains all number formats used in the workbook. Overrides the inherited method to assign a unique name according to the OpenDocument syntax ("N" to the format items. } -procedure TsSpreadOpenDocWriter.ListAllNumFormats(ADialect: TsNumFormatDialect); +procedure TsSpreadOpenDocWriter.ListAllNumFormats; const FMT_BASE = 1000; // Format number to start with. Not clear if this is correct... var @@ -2573,21 +2573,9 @@ begin for i:=0 to Workbook.GetNumberFormatCount - 1 do begin nfParams := Workbook.GetNumberFormat(i); - FNumFormatList.Add(Format('N%d:%s', [FMT_BASE+i, nfParams.NumFormatStr[ADialect]])); + if nfParams <> nil then + FNumFormatList.Add(Format('N%d:%s', [FMT_BASE+i, nfParams.NumFormatStr])); end; - { -var - n, i, j: Integer; -begin - n := NumFormatList.Count; - inherited ListAllNumFormats; - j := 0; - for i:=n to NumFormatList.Count-1 do - begin - NumFormatList.Items[i].Name := Format('N%d', [FMT_BASE + j]); - inc(j); - end; - } end; procedure TsSpreadOpenDocWriter.ListAllRowStyles; @@ -2917,7 +2905,7 @@ begin nfParams := FWorkbook.GetNumberFormat(nfidx); if nfParams <> nil then begin - nfs := nfParams.NumFormatStr[nfdExcel]; + nfs := nfParams.NumFormatStr; for j:=0 to NumFormatList.Count-1 do begin s := NumFormatList[j]; @@ -3408,7 +3396,7 @@ var FZip: TZipper; begin { Analyze the workbook and collect all information needed } - ListAllNumFormats(nfdExcel); + ListAllNumFormats; ListAllColumnStyles; ListAllRowStyles; diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 33fcfbdcf..a3df7d783 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -953,7 +953,7 @@ begin numFmtParams := sourceSheet.Workbook.GetNumberFormat(fmt.NumberFormatIndex); if numFmtParams <> nil then begin - nfs := numFmtParams.NumFormatStr[nfdExcel]; + nfs := numFmtParams.NumFormatStr; fmt.NumberFormatIndex := destSheet.Workbook.AddNumberFormat(nfs); end; end; @@ -2977,7 +2977,7 @@ begin if numFmt <> nil then begin ANumFormat := numFmt.NumFormat; - ANumFormatStr := numFmt.NumFormatStr[nfdDefault]; + ANumFormatStr := numFmt.NumFormatStr; end else begin ANumFormat := nfGeneral; @@ -4108,7 +4108,6 @@ begin RegisterCurrency(ACurrencySymbol); nfs := BuildCurrencyFormatString( - nfdDefault, ANumFormat, Workbook.FormatSettings, ADecimals, @@ -4156,10 +4155,10 @@ procedure TsWorksheet.WriteCurrency(ACell: PCell; AValue: Double; var fmt: TsCellFormat; begin - if not (ANumFormat in [nfCurrency, nfCurrencyRed]) then + if not IsCurrencyFormat(ANumFormat) then raise Exception.Create('[TsWorksheet.WriteCurrency] ANumFormat can only be nfCurrency or nfCurrencyRed'); - if (ACell <> nil) and IsCurrencyFormat(ANumFormat) then begin + if (ACell <> nil) then begin ACell^.ContentType := cctNumber; ACell^.NumberValue := AValue; @@ -4364,6 +4363,7 @@ procedure TsWorksheet.WriteDateTimeFormat(ACell: PCell; ANumFormat: TsNumberFormat; const ANumFormatString: String = ''); var fmt: TsCellFormat; + nfs: String; begin if ACell = nil then exit; @@ -4377,14 +4377,17 @@ begin begin Include(fmt.UsedFormattingFields, uffNumberFormat); if (ANumFormatString = '') then - fmt.NumberFormatStr := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings) + nfs := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings) else - fmt.NumberFormatStr := ANumFormatString; + nfs := ANumFormatString; end else begin Exclude(fmt.UsedFormattingFields, uffNumberFormat); fmt.NumberFormatStr := ''; end; + fmt.NumberFormat := ANumFormat; + fmt.NumberFormatStr := nfs; + fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs); ACell^.FormatIndex := FWorkbook.AddCellFormat(fmt); ChangedCell(ACell^.Row, ACell^.Col); @@ -4426,11 +4429,11 @@ begin fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); numFmt := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex); - numFmtStr := numFmt.NumFormatStr[nfdDefault]; + numFmtStr := numFmt.NumFormatStr; parser := TsNumFormatParser.Create(Workbook, numFmtStr); try parser.Decimals := ADecimals; - numFmtStr := parser.FormatString[nfdDefault]; + numFmtStr := parser.FormatString; fmt.NumberFormatIndex := Workbook.AddNumberFormat(numFmtStr); Include(fmt.UsedFormattingFields, uffNumberFormat); ACell^.FormatIndex := Workbook.AddCellFormat(fmt); @@ -4579,12 +4582,11 @@ begin fmt.NumberFormat := ANumFormat; if ANumFormat <> nfGeneral then begin Include(fmt.UsedFormattingFields, uffNumberFormat); - if ANumFormat in [nfCurrency, nfCurrencyRed] then + if IsCurrencyFormat(ANumFormat) then begin RegisterCurrency(ACurrencySymbol); - fmtStr := BuildCurrencyFormatString(nfdDefault, ANumFormat, - Workbook.FormatSettings, ADecimals, - APosCurrFormat, ANegCurrFormat, ACurrencySymbol); + fmtStr := BuildCurrencyFormatString(ANumFormat, Workbook.FormatSettings, + ADecimals, APosCurrFormat, ANegCurrFormat, ACurrencySymbol); end else fmtStr := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings, ADecimals); @@ -7197,7 +7199,7 @@ begin if numFmt <> nil then Result := Format('%s; %s (%s)', [Result, GetEnumName(TypeInfo(TsNumberFormat), ord(numFmt.NumFormat)), - numFmt.NumFormatStr[nfdDefault] + numFmt.NumFormatStr ]) else Result := Format('%s; %s', [Result, 'nfGeneral']); @@ -7487,7 +7489,7 @@ begin if AFormatStr = '' then Result := -1 // General number format is not stored else - Result := TsNumFormatList(FNumFormatList).AddFormat(AFormatStr, nfdDefault); + Result := TsNumFormatList(FNumFormatList).AddFormat(AFormatStr); end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index b6292760f..0fd2f8dcd 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -1560,7 +1560,7 @@ var begin if Worksheet = nil then exit; - cell := Worksheet.FindCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol); + cell := Worksheet.GetCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol); if Worksheet.IsMerged(cell) then cell := Worksheet.FindMergeBase(cell); s := Lines.Text; @@ -1695,9 +1695,12 @@ begin cctNumber: Lines.Text := FloatToStr(ACell^.NumberValue); cctDateTime: - if ACell^.DateTimeValue < 1.0 then + if ACell^.DateTimeValue < 1.0 then // Time only Lines.Text := FormatDateTime('tt', ACell^.DateTimeValue) else + if frac(ACell^.DateTimeValue) = 0 then // Date only + Lines.Text := FormatDateTime('ddddd', ACell^.DateTimevalue) + else // both Lines.Text := FormatDateTime('c', ACell^.DateTimeValue); else Lines.Text := Worksheet.ReadAsUTF8Text(ACell); @@ -2699,7 +2702,7 @@ begin numFmt := Workbook.GetNumberFormat(fmt.NumberFormatIndex); AStrings.Add(Format('NumberFormat=%s', [ GetEnumName(TypeInfo(TsNumberFormat), ord(numFmt.NumFormat))])); - AStrings.Add('NumberFormatStr=' + numFmt.NumFormatStr[nfdDefault]); + AStrings.Add('NumberFormatStr=' + numFmt.NumFormatStr); end; if (Worksheet = nil) or not Worksheet.IsMerged(ACell) then diff --git a/components/fpspreadsheet/fpsreaderwriter.pas b/components/fpspreadsheet/fpsreaderwriter.pas index 5884df6d8..1314e29bf 100644 --- a/components/fpspreadsheet/fpsreaderwriter.pas +++ b/components/fpspreadsheet/fpsreaderwriter.pas @@ -99,7 +99,7 @@ type procedure FixFormat(ACell: PCell); virtual; procedure GetSheetDimensions(AWorksheet: TsWorksheet; out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual; - procedure ListAllNumFormats(ADialect: TsNumFormatDialect); virtual; + procedure ListAllNumFormats; virtual; { Helpers for writing } procedure WriteCellToStream(AStream: TStream; ACell: PCell); @@ -482,7 +482,7 @@ end; Copies the format strings from the workbook's NumFormatList to the writer's internal NumFormatList. -------------------------------------------------------------------------------} -procedure TsCustomSpreadWriter.ListAllNumFormats(ADialect: TsNumFormatDialect); +procedure TsCustomSpreadWriter.ListAllNumFormats; var i: Integer; numFmt: TsNumFormatParams; @@ -493,7 +493,7 @@ begin numFmt := Workbook.GetNumberFormat(i); if numFmt <> nil then begin - numFmtStr := numFmt.NumFormatStr[ADialect]; + numFmtStr := numFmt.NumFormatStr; if FindNumFormatInList(numFmtStr) = -1 then FNumFormatList.Add(numFmtStr); end; diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas index d55df33e4..e28db7e59 100644 --- a/components/fpspreadsheet/fpstypes.pas +++ b/components/fpspreadsheet/fpstypes.pas @@ -445,11 +445,7 @@ type // other (format string goes directly into the file) nfCustom); - {@@ Identifies which "dialect" is used in the format strings: - nfdDefault is the dialect used by fpc - fndExcel is the dialect used by Excel } - TsNumFormatDialect = (nfdDefault, nfdExcel); - + {@@ Tokens used by the elements of the number format parser } TsNumFormatToken = ( nftText, // must be quoted, stored in TextValue nftThSep, // ',', replaced by FormatSettings.ThousandSeparator @@ -525,12 +521,12 @@ type TsNumFormatParams = class(TObject) protected function GetNumFormat: TsNumberFormat; virtual; - function GetNumFormatStr(ADialect: TsNumFormatDialect): String; virtual; + function GetNumFormatStr: String; virtual; public Sections: TsNumFormatSections; function SectionsEqualTo(ASections: TsNumFormatSections): Boolean; property NumFormat: TsNumberFormat read GetNumFormat; - property NumFormatStr[ADialect: TsNumFormatDialect]: String read GetNumFormatStr; + property NumFormatStr: String read GetNumFormatStr; end; TsNumFormatParamsClass = class of TsNumFormatParams; @@ -660,8 +656,7 @@ type cctError : (ErrorValue: TsErrorValue); end; -function BuildFormatStringFromSection(const ASection: TsNumFormatSection; - ADialect: TsNumFormatDialect): String; +function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String; implementation @@ -838,10 +833,10 @@ begin end; -{ Creates a format string for the given section. This implementation covers - the formatstring dialects of fpc (nfdDefault) and Excel (nfdExcel). } -function BuildFormatStringFromSection(const ASection: TsNumFormatSection; - ADialect: TsNumFormatDialect): String; +{ Creates a format string for the given number format section section. + The format string is created according to Excel convention (which is used by + ODS as well } +function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String; var element: TsNumFormatElement; i: Integer; @@ -880,62 +875,49 @@ begin nftText: if element.TextValue <> '' then result := Result + '"' + element.TextValue + '"'; nftYear: - Result := Result + DupeString(IfThen(ADialect = nfdExcel, 'Y', 'y'), element.IntValue); + Result := Result + DupeString('Y', element.IntValue); nftMonth: - Result := Result + DupeString(IfThen(ADialect = nfdExcel, 'M', 'm'), element.IntValue); + Result := Result + DupeString('M', element.IntValue); nftDay: - Result := Result + DupeString(IfThen(ADialect = nfdExcel, 'D', 'd'), element.IntValue); + Result := Result + DupeString('D', element.IntValue); nftHour: if element.IntValue < 0 then Result := Result + '[' + DupeString('h', -element.IntValue) + ']' else Result := Result + DupeString('h', element.IntValue); nftMinute: if element.IntValue < 0 - then Result := result + '[' + DupeString(IfThen(ADialect = nfdExcel, 'm', 'n'), -element.IntValue) + ']' - else Result := Result + DupeString(IfThen(ADialect = nfdExcel, 'm', 'n'), element.IntValue); + then Result := result + '[' + DupeString('m', -element.IntValue) + ']' + else Result := Result + DupeString('m', element.IntValue); nftSecond: if element.IntValue < 0 then Result := Result + '[' + DupeString('s', -element.IntValue) + ']' else Result := Result + DupeString('s', element.IntValue); nftMilliseconds: - if ADialect = nfdExcel then - Result := Result + Dupestring('0', element.IntValue) - else - Result := Result + DupeString('z', element.IntValue); + Result := Result + DupeString('0', element.IntValue); nftSign, nftSignBracket, nftExpChar, nftExpSign, nftAMPM, nftDateTimeSep: if element.TextValue <> '' then Result := Result + element.TextValue; nftCurrSymbol: - if element.TextValue <> '' then begin - if ADialect = nfdExcel then - Result := Result + '[$' + element.TextValue + ']' - else - Result := Result + '"' + element.TextValue + '"'; - end; + if element.TextValue <> '' then + Result := Result + '[$' + element.TextValue + ']'; nftEscaped: - if element.TextValue <> '' then begin - if ADialect = nfdExcel then - Result := Result + '\' + element.TextValue - else - Result := Result + element.TextValue; - end; + if element.TextValue <> '' then + Result := Result + '\' + element.TextValue; nftTextFormat: if element.TextValue <> '' then - if ADialect = nfdExcel then Result := Result + element.TextValue; + Result := Result + element.TextValue; nftRepeat: if element.TextValue <> '' then Result := Result + '*' + element.TextValue; nftColor: - if ADialect = nfdExcel then begin - case element.IntValue of - scBlack : Result := '[black]'; - scWhite : Result := '[white]'; - scRed : Result := '[red]'; - scBlue : Result := '[blue]'; - scGreen : Result := '[green]'; - scYellow : Result := '[yellow]'; - scMagenta: Result := '[magenta]'; - scCyan : Result := '[cyan]'; - else Result := Format('[Color%d]', [element.IntValue]); - end; + case element.IntValue of + scBlack : Result := '[black]'; + scWhite : Result := '[white]'; + scRed : Result := '[red]'; + scBlue : Result := '[blue]'; + scGreen : Result := '[green]'; + scYellow : Result := '[yellow]'; + scMagenta: Result := '[magenta]'; + scCyan : Result := '[cyan]'; + else Result := Format('[Color%d]', [element.IntValue]); end; end; end; @@ -962,14 +944,14 @@ begin end; end; -function TsNumFormatParams.GetNumFormatStr(ADialect: TsNumFormatDialect): String; +function TsNumFormatParams.GetNumFormatStr: String; var i: Integer; begin if Length(Sections) > 0 then begin - Result := BuildFormatStringFromSection(Sections[0], ADialect); + Result := BuildFormatStringFromSection(Sections[0]); for i := 1 to High(Sections) do - Result := Result + ';' + BuildFormatStringFromSection(Sections[i], ADialect); + Result := Result + ';' + BuildFormatStringFromSection(Sections[i]); end else Result := ''; end; diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index c729232f7..b35aab9ad 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -96,9 +96,9 @@ function IfThen(ACondition: Boolean; AValue1,AValue2: TsNumberFormat): TsNumberF procedure BuildCurrencyFormatList(AList: TStrings; APositive: Boolean; AValue: Double; const ACurrencySymbol: String); -function BuildCurrencyFormatString(ADialect: TsNumFormatDialect; - ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; - ADecimals, APosCurrFormat, ANegCurrFormat: Integer; ACurrencySymbol: String): String; +function BuildCurrencyFormatString(ANumberFormat: TsNumberFormat; + const AFormatSettings: TFormatSettings; ADecimals, APosCurrFmt, ANegCurrFmt: Integer; + ACurrencySymbol: String; Accounting: Boolean = false): String; function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; AFormatString: String = ''): String; function BuildFractionFormatString(AMixedFraction: Boolean; @@ -119,9 +119,10 @@ function MonthNamesToString(const AMonthNames: TMonthNameArray; const AEmptyStr: String): String; function SpecialDateTimeFormat(ACode: String; const AFormatSettings: TFormatSettings; ForWriting: Boolean): String; +{ procedure SplitFormatString(const AFormatString: String; out APositivePart, ANegativePart, AZeroPart: String); - + } procedure MakeTimeIntervalMask(Src: String; var Dest: String); function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams; @@ -1062,30 +1063,30 @@ end; or minus signs) is taken from the provided format settings. The format string consists of three sections, separated by semicolons. - @param ADialect Determines whether the format string is for use by - fpspreadsheet (nfdDefault) or by Excel (nfdExcel) @param ANumberFormat Identifier of the built-in number format for which the format string is to be generated. @param AFormatSettings FormatSettings to be applied (used to extract default values for the next parameters) @param ADecimals number of decimal places. If < 0, the CurrencyDecimals of the FormatSettings is used. - @param APosCurrFormat Identifier for the order of currency symbol, value and + @param APosCurrFmt Identifier for the order of currency symbol, value and spaces of positive values - see pcfXXXX constants in fpspreadsheet.pas. If < 0, the CurrencyFormat of the FormatSettings is used. - @param ANegCurrFormat Identifier for the order of currency symbol, value and + @param ANegCurrFmt Identifier for the order of currency symbol, value and spaces of negative values. Specifies also usage of (). - see ncfXXXX constants in fpspreadsheet.pas. If < 0, the NegCurrFormat of the FormatSettings is used. @param ACurrencySymbol Name of the currency, like $ or USD. If ? the CurrencyString of the FormatSettings is used. + @param Accounting If true, adds spaces for alignment of decimals @return String of formatting codes, such as '"$"#,##0.00;("$"#,##0.00);"$"0.00' -------------------------------------------------------------------------------} -function BuildCurrencyFormatString(ADialect: TsNumFormatDialect; - ANumberFormat: TsNumberFormat; const AFormatSettings: TFormatSettings; - ADecimals, APosCurrFormat, ANegCurrFormat: Integer; ACurrencySymbol: String): String; +function BuildCurrencyFormatString(ANumberFormat: TsNumberFormat; + const AFormatSettings: TFormatSettings; + ADecimals, APosCurrFmt, ANegCurrFmt: Integer; ACurrencySymbol: String; + Accounting: Boolean = false): String; { const POS_FMT: array[0..3] of string = ( @@ -1120,8 +1121,8 @@ var p, n: String; negRed: Boolean; begin - pcf := IfThen(APosCurrFormat < 0, AFormatSettings.CurrencyFormat, APosCurrFormat); - ncf := IfThen(ANegCurrFormat < 0, AFormatSettings.NegCurrFormat, ANegCurrFormat); + pcf := IfThen(APosCurrFmt < 0, AFormatSettings.CurrencyFormat, APosCurrFmt); + ncf := IfThen(ANegCurrFmt < 0, AFormatSettings.NegCurrFormat, ANegCurrFmt); if (ADecimals < 0) then ADecimals := AFormatSettings.CurrencyDecimals; if ACurrencySymbol = '?' then @@ -1134,25 +1135,25 @@ begin negRed := (ANumberFormat = nfCurrencyRed); p := POS_CURR_FMT[pcf]; // Format mask for positive values n := NEG_CURR_FMT[ncf]; // Format mask for negative values + // add extra space for the sign of the number for perfect alignment in Excel - if ADialect = nfdExcel then + if Accounting then case ncf of 0, 14: p := p + '_)'; 3, 11: p := p + '_-'; - 4, 15: p := '_(' + p; + 4, 15: p := '_(' + p; 5, 8 : p := '_-' + p; end; if ACurrencySymbol <> '' then begin Result := Format(p, ['#,##0' + decs, ACurrencySymbol]) + ';' + IfThen(negRed, '[red]', '') -// + IfThen(negRed and (ADialect = nfdExcel), '[red]', '') + Format(n, ['#,##0' + decs, ACurrencySymbol]) + ';' + Format(p, ['0'+decs, ACurrencySymbol]); end else begin Result := '#,##0' + decs; - if negRed and (ADialect = nfdExcel) then + if negRed then Result := Result +';[red]' else Result := Result +';'; @@ -1216,14 +1217,20 @@ begin Result := '0' + decs + 'E+00'; nfPercentage: Result := '0' + decs + '%'; + nfFraction: + if ADecimals = 0 then + Result := '# ??/??' + else + begin + decs := DupeString('?', ADecimals); + Result := '# ' + decs + '/' + decs; + end; nfCurrency, nfCurrencyRed: - Result := BuildCurrencyFormatString(nfdDefault, ANumberFormat, AFormatSettings, + Result := BuildCurrencyFormatString(ANumberFormat, AFormatSettings, ADecimals, AFormatSettings.CurrencyFormat, AFormatSettings.NegCurrFormat, AFormatSettings.CurrencyString); -// raise Exception.Create('BuildNumberFormatString: Use BuildCurrencyFormatString '+ -// 'to create a format string for currency values.'); nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime, - nfShortTimeAM, nfLongTimeAM, nfTimeInterval: + nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval: raise Exception.Create('BuildNumberFormatString: Use BuildDateTimeFormatSstring '+ 'to create a format string for date/time values.'); end; @@ -1384,8 +1391,8 @@ const MinInt64 = Low(Int64); var H1, H2, K1, K2, A, NewA, tmp, prevH1, prevK1: Int64; - B, diff, test, eps: Double; - Found, PendingOverflow: Boolean; + B, diff, test: Double; + PendingOverflow: Boolean; i: Integer = 0; begin Assert((APrecision > 0) and (APrecision < 1)); @@ -1610,6 +1617,7 @@ end; for negative numbers @param AZeroPart Third section of the formatting string for zero. -------------------------------------------------------------------------------} +(* procedure SplitFormatString(const AFormatString: String; out APositivePart, ANegativePart, AZeroPart: String); @@ -1666,7 +1674,7 @@ begin inc(P); end; end; - + *) {@@ ---------------------------------------------------------------------------- Creates a "time interval" format string having the first time code identifier in square brackets. @@ -2452,7 +2460,7 @@ var if AddThousandSeparator then begin j := Length(Result)-2; - while (j > 0) do + while (j > 1) do begin Insert(fs.ThousandSeparator, Result, j); dec(j, 3); @@ -2507,7 +2515,7 @@ var var fmtStr: String; begin - fmtStr := AParams.NumFormatStr[nfdExcel]; + fmtStr := AParams.NumFormatStr; raise Exception.CreateFmt(rsIsNoValidNumberFormatString, [fmtStr]); end; @@ -2583,7 +2591,7 @@ begin (7) number w/o decimals --> exponent } // Integer only, followed by end-of-line (case 4) - if (i = numEl) or (section.Elements[i].Token in (terminatingTokens - [nftSpace])) then + if (i = numEl) or (section.Elements[i].Token in (terminatingTokens - [nftSpace, nftEmptyCharWidth])) then begin Result := Result + FixIntPart(AValue, false, digitsZero, digitsOpt, digitsSpace); el := i; @@ -2744,7 +2752,7 @@ begin end; // Simple decimal number (nfFixed), followed by terminating tokens (case 5) - if (i < numEl) and (section.Elements[i].Token in terminatingTokens) then + if (i < numEl) and (section.Elements[i].Token in terminatingTokens - [nftEmptyCharWidth]) then begin // Simple decimal number (nfFixed) (case 1) Result := Result @@ -2849,6 +2857,9 @@ begin Result := Result + section.Elements[el].TextValue; end; + nftEmptyCharWidth: + Result := Result + ' '; + nftDateTimeSep: case section.Elements[el].TextValue of '/': Result := Result + fs.DateSeparator; @@ -2955,159 +2966,6 @@ begin end; inc(el); end; - - (* - section := AParams.Sections[sidx]; - nf := section.NumFormat; - case nf of - nfFixed: - Result := FloatToStrF(AValue, ffFixed, 20, section.Decimals, fs); - nfFixedTh: - Result := FloatToStrF(AValue, ffNumber, 20, section.Decimals, fs); - nfPercentage: - Result := FloatToStrF(AValue*100.0, ffFixed, 20, section.Decimals, fs) + '%'; - nfExp: - begin - elem := High(Section.Elements); - expDigits := 2; - if section.Elements[elem].Token = nftExpDigits then - expDigits := section.Elements[elem].IntValue; - Result := FloatToStrF(AValue, ffExponent, section.Decimals+1, expDigits, fs); - if (abs(AValue) >= 1.0) and ( - ((section.Elements[elem-1].Token <> nftExpSign) or (section.Elements[elem-1].TextValue = '-')) ) - then - Delete(Result, pos('+', Result), 1); - end; - nfFraction: - begin - AValue := abs(AValue); - if section.FracInt = 0 then - frint := 0 - else begin - frint := trunc(AValue); - AValue := frac(AValue); - end; - maxNum := Round(IntPower(10, section.FracNumerator)); - maxDenom := Round(IntPower(10, section.FracDenominator)); - FloatToFraction(AValue, maxnum, maxdenom, frnum, frdenom); - Result := IntToStr(frnum) + '/' + IntToStr(frdenom); - if frint <> 0 then - Result := IntToStr(frint) + ' ' + result; - if isNeg then Result := '-' + Result; - end; - nfCurrency, - nfCurrencyRed: - begin - valueDone := false; - for elem := 0 to High(section.Elements) do - case section.Elements[elem].Token of - nftSpace: - Result := Result + ' '; - nftText: - Result := Result + section.Elements[elem].TextValue; - nftCurrSymbol: - Result := Result + section.CurrencySymbol; - nftSign: - Result := Result + '-'; - nftSignBracket: - Result := Result + section.Elements[elem].TextValue; - nftDigit, nftOptDigit: - if not ValueDone then - begin - Result := Result + FloatToStrF(AValue, ffNumber, 20, section.Decimals, fs); - valueDone := true; - end; - end; - end; - nfShortDate, nfLongDate, nfShortTime, nfLongTime, nfShortDateTime, - nfShortTimeAM, nfLongTimeAM: - begin - DecodeDate(trunc(AValue), yr, mon, day); - DecodeTime(frac(AValue), hr, min, sec, ms); - elem := 0; - while elem < Length(section.Elements) do - begin - case section.Elements[elem].Token of - nftSpace: - Result := Result + ' '; - nftText: - Result := Result + section.Elements[elem].TextValue; - nftYear: - case section.Elements[elem].IntValue of - 1, - 2: Result := Result + IfThen(yr < 10, '0'+IntToStr(yr), IntToStr(yr)); - 4: Result := Result + IntToStr(yr); - end; - nftMonth: - case section.Elements[elem].IntValue of - 1: Result := Result + IntToStr(mon); - 2: Result := Result + IfThen(mon < 10, '0'+IntToStr(mon), IntToStr(mon)); - 3: Result := Result + fs.ShortMonthNames[mon]; - 4: Result := Result + fs.LongMonthNames[mon]; - end; - nftDay: - case section.Elements[elem].IntValue of - 1: result := result + IntToStr(day); - 2: result := Result + IfThen(day < 10, '0'+IntToStr(day), IntToStr(day)); - 3: Result := Result + fs.ShortDayNames[day]; - 4: Result := Result + fs.LongDayNames[day]; - end; - nftHour: - begin - if section.Elements[elem].IntValue < 0 then - hr := hr + trunc(AValue) * 24; - case abs(section.Elements[elem].IntValue) of - 1: Result := Result + IntToStr(hr); - 2: Result := Result + IfThen(hr < 10, '0'+IntToStr(hr), IntToStr(hr)); - end; - end; - nftMinute: - begin - if section.Elements[elem].IntValue < 0 then - min := min + trunc(AValue) * 24 * 60; - case abs(section.Elements[elem].IntValue) of - 1: Result := Result + IntToStr(min); - 2: Result := Result + IfThen(min < 10, '0'+IntToStr(min), IntToStr(min)); - end; - end; - nftSecond: - begin - if section.Elements[elem].IntValue < 0 then - sec := sec + trunc(AValue) * 24 * 60 * 60; - case abs(section.Elements[elem].IntValue) of - 1: Result := Result + IntToStr(sec); - 2: Result := Result + IfThen(sec < 10, '0'+IntToStr(sec), IntToStr(sec)); - end; - end; - nftDecSep: - Result := Result + fs.DecimalSeparator; - nftMilliseconds: - case section.Elements[elem].IntValue of - 1: Result := Result + IntToStr(ms div 100); - 2: Result := Result + Format('%02d', [ms div 10]); - 3: Result := Result + Format('%03d', [ms]); - end; - nftDateTimeSep: - case section.Elements[elem].TextValue of - '/': Result := Result + fs.DateSeparator; - ':': Result := Result + fs.TimeSeparator; - else Result := Result + section.Elements[elem].TextValue; - end; - nftAMPM: - if frac(AValue) <= 0.5 then - Result := Result + fs.TimeAMString - else - Result := Result + fs.TimePMString; - nftEscaped: - begin - inc(elem); - Result := Result + section.Elements[elem].TextValue; - end; - end; - inc(elem); - end; - end; - end;*) end; diff --git a/components/fpspreadsheet/tests/numformatparsertests.pas b/components/fpspreadsheet/tests/numformatparsertests.pas index cb8988ee5..c680b01c7 100644 --- a/components/fpspreadsheet/tests/numformatparsertests.pas +++ b/components/fpspreadsheet/tests/numformatparsertests.pas @@ -84,7 +84,7 @@ begin end; with ParserTestData[4] do begin FormatString := 'hh:mm:ss'; - SollFormatString := 'hh:nn:ss'; + SollFormatString := 'hh:mm:ss'; SollNumFormat := nfLongTime; SollSectionCount := 1; SollDecimals := 0; @@ -92,7 +92,7 @@ begin end; with ParserTestData[5] do begin FormatString := 'hh:mm:ss AM/PM'; - SollFormatString := 'hh:nn:ss AM/PM'; + SollFormatString := 'hh:mm:ss AM/PM'; SollNumFormat := nfLongTimeAM; SollSectionCount := 1; SollDecimals := 0; @@ -100,7 +100,7 @@ begin end; with ParserTestData[6] do begin FormatString := '[$-409]hh:mm:ss\ AM/PM;@'; - SollFormatString := 'hh:nn:ss AM/PM'; + SollFormatString := 'hh:mm:ss AM/PM'; SollNumFormat := nfLongTimeAM; SollSectionCount := 2; SollDecimals := 0; @@ -108,7 +108,7 @@ begin end; with ParserTestData[7] do begin FormatString := '[$-F400]dd.mm.yy\ hh:mm'; - SollFormatString := 'dd.mm.yy hh:nn'; + SollFormatString := 'dd.mm.yy hh:mm'; SollNumFormat := nfShortDateTime; SollSectionCount := 1; SollDecimals := 0; @@ -170,7 +170,7 @@ begin for i:=0 to 5 do begin parser := TsNumFormatParser.Create(MyWorkbook, ParserTestData[i].FormatString); try - actual := parser.FormatString[nfdDefault]; + actual := parser.FormatString; CheckEquals(ParserTestData[i].SollFormatString, actual, 'Test format string ' + ParserTestData[i].SollFormatString + ' construction mismatch'); CheckEquals(ord(ParserTestData[i].SollNumFormat), ord(parser.ParsedSections[0].NumFormat), diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi index 7ea7c1714..b814e593b 100644 --- a/components/fpspreadsheet/tests/spreadtestgui.lpi +++ b/components/fpspreadsheet/tests/spreadtestgui.lpi @@ -164,11 +164,6 @@ - - - - - diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index c8ce88aa9..31c172a01 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -97,7 +97,7 @@ type procedure WriteIXFE(AStream: TStream; XFIndex: Word); protected procedure AddBuiltinNumFormats; override; - procedure ListAllNumFormats(ADialect: TsNumFormatDialect); override; + procedure ListAllNumFormats; override; procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override; procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal; @@ -251,8 +251,7 @@ type end; -procedure InternalAddBuiltinNumFormats(AList: TStringList; - AFormatSettings: TFormatSettings; ADialect: TsNumFormatDialect); +procedure InternalAddBuiltinNumFormats(AList: TStringList; AFormatSettings: TFormatSettings); var fs: TFormatSettings absolute AFormatSettings; cs: String; @@ -266,10 +265,10 @@ begin Add('0.00'); // 2 Add('#,##0'); // 3 Add('#,##0.00'); // 4 - Add(BuildCurrencyFormatString(ADialect, nfCurrency, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 5 - Add(BuildCurrencyFormatString(ADialect, nfCurrencyRed, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 6 - Add(BuildCurrencyFormatString(ADialect, nfCurrency, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 7 - Add(BuildCurrencyFormatString(ADialect, nfCurrencyRed, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 8 + Add(BuildCurrencyFormatString(nfCurrency, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 5 + Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 6 + Add(BuildCurrencyFormatString(nfCurrency, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 7 + Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 8 Add('0%'); // 9 Add('0.00%'); // 10 Add('0.00E+00'); // 11 @@ -299,7 +298,7 @@ end; procedure TsSpreadBIFF2Reader.AddBuiltInNumFormats; begin FFirstNumFormatIndexInFile := 0; - InternalAddBuiltInNumFormats(FNumFormatList, Workbook.FormatSettings, nfdDefault); + InternalAddBuiltInNumFormats(FNumFormatList, Workbook.FormatSettings); end; procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream); @@ -905,7 +904,7 @@ begin fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs); nf := Workbook.GetNumberFormat(fmt.NumberFormatIndex); fmt.NumberFormat := nf.NumFormat; - fmt.NumberFormatStr := nf.NumFormatStr[nfdDefault]; + fmt.NumberFormatStr := nf.NumFormatStr; Include(fmt.UsedFormattingFields, uffNumberFormat); end; @@ -974,7 +973,7 @@ end; procedure TsSpreadBIFF2Writer.AddBuiltInNumFormats; begin FFirstNumFormatIndexInFile := 0; - InternalAddBuiltInNumFormats(FNumFormatList, Workbook.FormatSettings, nfdExcel); + InternalAddBuiltInNumFormats(FNumFormatList, Workbook.FormatSettings); end; {@@ ---------------------------------------------------------------------------- @@ -1034,9 +1033,8 @@ end; standard formats; these formats have been added by AddBuiltInFormats. Nothing to do here. -------------------------------------------------------------------------------} -procedure TsSpreadBIFF2Writer.ListAllNumFormats(ADialect: TsNumFormatDialect); +procedure TsSpreadBIFF2Writer.ListAllNumFormats; begin - Unused(ADialect); // Nothing to do here. end; @@ -1234,7 +1232,7 @@ begin WriteFonts(AStream); WriteCodePage(AStream, FCodePage); WriteFormatCount(AStream); - WriteNumFormats(AStream, nfdExcel); + WriteNumFormats(AStream); WriteXFRecords(AStream); WriteColWidths(AStream); WriteDimensions(AStream, FWorksheet); diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 3bf5e86e2..b632cacda 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -1004,7 +1004,7 @@ begin WriteCodepage(AStream, FCodePage); WriteWindow1(AStream); WriteFonts(AStream); - WriteNumFormats(AStream, nfdExcel); + WriteNumFormats(AStream); WritePalette(AStream); WriteXFRecords(AStream); WriteStyle(AStream); @@ -1497,20 +1497,12 @@ begin if (AFormatRecord <> nil) and (uffNumberFormat in AFormatRecord^.UsedFormattingFields) then begin nfParams := Workbook.GetNumberFormat(AFormatRecord^.NumberFormatIndex); - nfs := nfParams.NumFormatStr[nfdExcel]; + nfs := nfParams.NumFormatStr; j := NumFormatList.IndexOf(nfs); if j = -1 then j := 0; end; rec.NumFormatIndex := WordToLE(j); -{ - // The number formats in the FormatList are still in fpc dialect - // They will be converted to Excel syntax immediately before writing. - j := NumFormatList.Find(AFormatRecord^.NumberFormat, AFormatRecord^.NumberFormatStr); - if j > -1 then - rec.NumFormatIndex := NumFormatList[j].Index; - end; - rec.NumFormatIndex := WordToLE(rec.NumFormatIndex); - } + { XF type, cell protection and parent style XF } rec.XFType_Prot_ParentXF := XFType_Prot and MASK_XF_TYPE_PROT; if XFType_Prot and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 6c373b9f3..301499268 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -1669,7 +1669,7 @@ begin WriteCodePage(AStream, 'ucs2le'); // = utf8 WriteWindow1(AStream); WriteFonts(AStream); - WriteNumFormats(AStream, nfdExcel); + WriteNumFormats(AStream); WritePalette(AStream); WriteXFRecords(AStream); WriteStyle(AStream); @@ -2831,7 +2831,7 @@ begin nfParams := Workbook.GetNumberFormat(AFormatRecord^.NumberFormatIndex); if nfParams <> nil then begin - nfs := nfParams.NumFormatStr[nfdExcel]; + nfs := nfParams.NumFormatStr; j := NumFormatList.IndexOf(nfs); if j = -1 then j := 0; end; diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index b1ba69d1c..5354bffc8 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -369,7 +369,7 @@ type procedure WriteNumFormat(AStream: TStream; ANumFormatStr: String; ANumFormatIndex: Integer); virtual; // Writes out all FORMAT records - procedure WriteNumFormats(AStream: TStream; ADialect: TsNumFormatDialect); + procedure WriteNumFormats(AStream: TStream); // Writes out a floating point NUMBER record procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: Double; ACell: PCell); override; @@ -429,8 +429,7 @@ type end; procedure AddBuiltinBiffFormats(AList: TStringList; - AFormatSettings: TFormatSettings; ALastIndex: Integer; - ADialect: TsNumFormatDialect); + AFormatSettings: TFormatSettings; ALastIndex: Integer); implementation @@ -594,8 +593,7 @@ end; number format that Excel used. -------------------------------------------------------------------------------} procedure AddBuiltinBiffFormats(AList: TStringList; - AFormatSettings: TFormatSettings; ALastIndex: Integer; - ADialect: TsNumFormatDialect); + AFormatSettings: TFormatSettings; ALastIndex: Integer); var fs: TFormatSettings absolute AFormatSettings; cs: String; @@ -608,10 +606,10 @@ begin AList.Add('0.00'); // 2 AList.Add('#,##0'); // 3 AList.Add('#,##0.00'); // 4 - AList.Add(BuildCurrencyFormatString(ADialect, nfCurrency, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 5 - AList.Add(BuildCurrencyFormatString(ADialect, nfCurrencyRed, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 6 - AList.Add(BuildCurrencyFormatString(ADialect, nfCurrency, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 7 - AList.Add(BuildCurrencyFormatString(ADialect, nfCurrencyRed, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 8 + AList.Add(BuildCurrencyFormatString(nfCurrency, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 5 + AList.Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 0, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 6 + AList.Add(BuildCurrencyFormatString(nfCurrency, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 7 + AList.Add(BuildCurrencyFormatString(nfCurrencyRed, fs, 2, fs.CurrencyFormat, fs.NegCurrFormat, cs)); // 8 AList.Add('0%'); // 9 AList.Add('0.00%'); // 10 AList.Add('0.00E+00'); // 11 @@ -670,7 +668,7 @@ procedure TsSpreadBIFFReader.AddBuiltinNumFormats; begin FFirstNumFormatIndexInFile := 164; AddBuiltInBiffFormats( - FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1, nfdDefault + FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1 ); end; @@ -1861,7 +1859,7 @@ procedure TsSpreadBIFFWriter.AddBuiltinNumFormats; begin FFirstNumFormatIndexInFile := 164; AddBuiltInBiffFormats( - FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1, nfdExcel + FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1 ); end; @@ -2211,37 +2209,24 @@ end; Writes all number formats to the stream. Saving starts at the item with the FirstFormatIndexInFile. -------------------------------------------------------------------------------} -procedure TsSpreadBIFFWriter.WriteNumFormats(AStream: TStream; - ADialect: TsNumFormatDialect); +procedure TsSpreadBIFFWriter.WriteNumFormats(AStream: TStream); var i: Integer; parser: TsNumFormatParser; fmtStr: String; begin - ListAllNumFormats(ADialect); + ListAllNumFormats; for i:= FFirstNumFormatIndexInFile to NumFormatList.Count-1 do begin fmtStr := NumFormatList[i]; parser := TsNumFormatParser.Create(Workbook, fmtStr); try - fmtStr := parser.FormatString[ADialect];; + fmtStr := parser.FormatString; WriteNumFormat(AStream, fmtStr, i); finally parser.Free; end; end; - -{ - i := NumFormatList.FindByIndex(FFirstNumFormatIndexInFile); - if i > -1 then - while i < NumFormatList.Count do - begin - item := NumFormatList[i]; - if item <> nil then - WriteNumFormat(AStream, item, i); - inc(i); - end; -} end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index 676d18cd8..1b6f2f493 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -417,7 +417,7 @@ procedure TsSpreadOOXMLReader.AddBuiltinNumFormats; begin FFirstNumFormatIndexInFile := 164; AddBuiltInBiffFormats( - FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1, nfdDefault + FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1 ); end; @@ -2222,7 +2222,7 @@ begin numFmtStr := NumFormatList[i]; parser := TsNumFormatParser.Create(Workbook, numFmtStr); try - numFmtStr := UTF8TextToXMLText(parser.FormatString[nfdExcel]); + numFmtStr := UTF8TextToXMLText(parser.FormatString); xmlStr := xmlStr + Format('', [i, numFmtStr]); inc(n); @@ -2475,7 +2475,7 @@ begin numFmtParams := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); if numFmtParams <> nil then begin - numFmtStr := numFmtParams.NumFormatStr[nfdExcel]; + numFmtStr := numFmtParams.NumFormatStr; idx := NumFormatList.IndexOf(numFmtStr); end else idx := 0; // "General" format is at index 0 @@ -2905,7 +2905,7 @@ procedure TsSpreadOOXMLWriter.AddBuiltinNumFormats; begin FFirstNumFormatIndexInFile := 164; AddBuiltInBiffFormats( - FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1, nfdExcel + FNumFormatList, Workbook.FormatSettings, FFirstNumFormatIndexInFile-1 ); end; @@ -3048,7 +3048,7 @@ var i: Integer; begin { Analyze the workbook and collect all information needed } - ListAllNumFormats(nfdExcel); + ListAllNumFormats; ListAllFills; ListAllBorders;