From 144f4dd25b6f5aee4dc39fd1b01b3235339e12a2 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Sun, 15 Jun 2014 22:27:46 +0000 Subject: [PATCH] fpspreadsheet: Beginning to extend to number format parser for xml strings (for ods). Not finished, yet. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3170 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpspreadsheet/fpsnumformatparser.pas | 18 +-- components/fpspreadsheet/fpsopendocument.pas | 151 +++++++++++++++++- 2 files changed, 156 insertions(+), 13 deletions(-) diff --git a/components/fpspreadsheet/fpsnumformatparser.pas b/components/fpspreadsheet/fpsnumformatparser.pas index 5063d26dc..9775756e2 100644 --- a/components/fpspreadsheet/fpsnumformatparser.pas +++ b/components/fpspreadsheet/fpsnumformatparser.pas @@ -25,10 +25,9 @@ const { TsNumFormatParser } type - TsNumFormatDialect = (nfdDefault, nfdExcel, nfdOther); + TsNumFormatDialect = (nfdDefault, nfdExcel); // nfdDefault is the dialect used by fpc, // nfdExcel is the dialect used by Excel - // nfdOther is used when writing xml for ods files. Separate implementation needed. TsCompareOperation = (coNotUsed, coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual @@ -69,13 +68,11 @@ type TsNumFormatParser = class private FCreateMethod: Byte; - FWorkbook: TsWorkbook; FToken: Char; FCurrent: PChar; FStart: PChar; FEnd: PChar; FCurrSection: Integer; - FSections: TsNumFormatSections; FStatus: Integer; function GetCurrencySymbol: String; function GetDecimals: byte; @@ -86,6 +83,9 @@ type procedure SetDecimals(AValue: Byte); protected + FWorkbook: TsWorkbook; + FSections: TsNumFormatSections; + { Administration while scanning } procedure AddElement(AToken: TsNumFormatToken; AText: String); overload; procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer); overload; @@ -275,13 +275,11 @@ end; { Creates a formatstring for all sections. Note: this implementation is only valid for the fpc and Excel dialects of - format string. Needs to be overridden for xml. } + format string. } function TsNumFormatParser.BuildFormatString(ADialect: TsNumFormatDialect): String; var i: Integer; begin - if ADialect = nfdOther then - raise Exception.Create('nfdOther cannot be used in TsNumFormatParser.BuildFormatString'); if Length(FSections) > 0 then begin Result := BuildFormatStringFromSection(0, ADialect); for i := 1 to High(FSections) do @@ -291,8 +289,7 @@ begin end; { Creates a format string for the given section. This implementation covers - the formatstring dialects of fpc (nfdDefault) and Excel (nfdExcel). - Needs to be overridden for xml. } + the formatstring dialects of fpc (nfdDefault) and Excel (nfdExcel). } function TsNumFormatParser.BuildFormatStringFromSection(ASection: Integer; ADialect: TsNumFormatDialect): String; var @@ -301,9 +298,6 @@ var begin Result := ''; - if ADialect = nfdOther then - raise Exception.Create('nfdOther cannot be used in TsNumFormatParser.BuildFormatString'); - if (ASection < 0) and (ASection >= GetParsedSectionCount) then exit; for i := 0 to High(FSections[ASection].Elements) do begin diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index bdc36c78e..877dc8c0d 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -39,7 +39,7 @@ uses fpspreadsheet, laz2_xmlread, laz2_DOM, AVL_Tree, math, dateutils, - fpsutils; + fpsutils, fpsNumFormatParser; type TDateMode=( @@ -49,12 +49,22 @@ type ); { TsSpreadOpenDocNumFormatList } + TsSpreadOpenDocNumFormatList = class(TsCustomNumFormatList) protected procedure AddBuiltinFormats; override; public end; + { TsSpreadOpenDocNumFormatParser } + TsSpreadOpenDocNumFormatParser = class(TsNumFormatParser) + protected + function BuildXMLAsStringFromSection(ASection: Integer; AIndent: String; + AFormatNo: Integer): String; + public + function BuildXMLAsString(AIndent: String; AFormatNo: Integer): String; + end; + { TsSpreadOpenDocReader } TsSpreadOpenDocReader = class(TsCustomSpreadReader) @@ -117,6 +127,7 @@ type // Routines to write parts of files function WriteCellStylesXMLAsString: string; function WriteColStylesXMLAsString: String; + function WriteNumFormatsXMLAsString: String; function WriteRowStylesXMLAsString: String; function WriteColumnsXMLAsString(ASheet: TsWorksheet): String; @@ -290,6 +301,105 @@ begin end; +{ TsSpreadOpenDocNumFormatParser } + +function TsSpreadOpenDocNumFormatParser.BuildXMLAsString(AIndent: String; + AFormatNo: Integer): String; +var + i, ns: Integer; +begin + Result := ''; + for i := Length(FSections)-1 downto 0 do + Result := Result + BuildXMLAsStringFromSection(i, AIndent, AFormatNo); +end; + +function TsSpreadOpenDocNumFormatParser.BuildXMLAsStringFromSection( + ASection: Integer; AIndent: String; AFormatNo: Integer): String; +var + nf : TsNumberFormat; + decs: Byte; + next: Integer; + sGrouping: String; + sColor: String; + sStyleMap: String; + ns: Integer; + fmtName: String; + clr: TsColorvalue; +begin + Result := ''; + sGrouping := ''; + sColor := ''; + sStyleMap := ''; + fmtName := Format('N%d', [AFormatNo]); + + ns := Length(FSections); + if (ns > 1) then begin + if (ASection = ns - 1) then + case ns of + 2: sStyleMap := AIndent + + ' ' + LineEnding; // >= 0 + 3: sStyleMap := AIndent + + ' 0 + 'style:condition="value()>0" />' + LineEnding + AIndent + + ' ' + LineEnding; + else + raise Exception.Create('At most 3 format sections allowed.'); + end + else + fmtName := fmtName + 'P' + IntToStr(ASection); + end; + + with FSections[ASection] do begin + next := 0; + if IsTokenAt(nftColor, ASection, 0) then begin + clr := FWorkbook.GetPaletteColor(Elements[0].IntValue); + sColor := AIndent + '' + LineEnding; + next := 1; + end; + if IsNumberAt(ASection, next, nf, decs, next) then begin + if nf = nfFixedTh then + sGrouping := 'number:grouping="true" '; + + // nfFixed, nfFixedTh + if (next = Length(Elements)) then begin + Result := AIndent + + '' + LineEnding + + sColor + AIndent + + ' ' + LineEnding + + sStylemap + AIndent + + '' + LineEnding; + exit; + end; + end; + + // nfPercentage + if IsTokenAt(nftPercent, ASection, next) and (next+1 = Length(Elements)) + then begin + Result := AIndent + + '' + LineEnding + + sColor + AIndent + + ' ' + LineEnding + AIndent + + ' %' + LineEnding + + sStyleMap + AIndent + + '' + LineEnding; + exit; + end; + end; + + // ... more to follow... +end; + { TsSpreadOpenDocReader } constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook); @@ -1905,11 +2015,14 @@ var lCellStylesCode: string; lColStylesCode: String; lRowStylesCode: String; + lNumFmtCode: String; begin ListAllColumnStyles; ListAllRowStyles; ListAllFormattingStyles; + lNumFmtCode := WriteNumFormatsXMLAsString; + lColStylesCode := WriteColStylesXMLAsString; if lColStylesCode = '' then lColStylesCode := ' ' + LineEnding + @@ -1956,6 +2069,7 @@ begin // Automatic styles ' ' + LineEnding + + lNumFmtCode + lColStylesCode + lRowStylesCode + ' ' + LineEnding + @@ -2138,6 +2252,41 @@ begin end; end; +function TsSpreadOpenDocWriter.WriteNumFormatsXMLAsString: String; +var + i: Integer; + numFmtXML: String; + parser: TsSpreadOpenDocNumFormatParser; +begin +{ + + + + +' + + + +' + + +} + Result := ''; + + ListAllNumFormats; + + for i:=0 to FNumFormatList.Count-1 do begin + parser := TsSpreadOpenDocNumFormatParser.Create(Workbook, FNumFormatList.Items[i].FormatString); + try + numFmtXML := parser.BuildXMLAsString(' ', 1000+i); //120+i); // Don't know where the user numbers start... + if numFmtXML <> '' then + Result := Result + numFmtXML; + finally + parser.Free; + end; + end; +end; + function TsSpreadOpenDocWriter.WriteRowsAndCellsXMLAsString(ASheet: TsWorksheet): String; var r, rr: Cardinal; // row index in sheet