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
This commit is contained in:
wp_xxyyzz
2014-06-15 22:27:46 +00:00
parent bba6d27241
commit 144f4dd25b
2 changed files with 156 additions and 13 deletions

View File

@ -25,10 +25,9 @@ const
{ TsNumFormatParser } { TsNumFormatParser }
type type
TsNumFormatDialect = (nfdDefault, nfdExcel, nfdOther); TsNumFormatDialect = (nfdDefault, nfdExcel);
// nfdDefault is the dialect used by fpc, // nfdDefault is the dialect used by fpc,
// nfdExcel is the dialect used by Excel // nfdExcel is the dialect used by Excel
// nfdOther is used when writing xml for ods files. Separate implementation needed.
TsCompareOperation = (coNotUsed, TsCompareOperation = (coNotUsed,
coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual
@ -69,13 +68,11 @@ type
TsNumFormatParser = class TsNumFormatParser = class
private private
FCreateMethod: Byte; FCreateMethod: Byte;
FWorkbook: TsWorkbook;
FToken: Char; FToken: Char;
FCurrent: PChar; FCurrent: PChar;
FStart: PChar; FStart: PChar;
FEnd: PChar; FEnd: PChar;
FCurrSection: Integer; FCurrSection: Integer;
FSections: TsNumFormatSections;
FStatus: Integer; FStatus: Integer;
function GetCurrencySymbol: String; function GetCurrencySymbol: String;
function GetDecimals: byte; function GetDecimals: byte;
@ -86,6 +83,9 @@ type
procedure SetDecimals(AValue: Byte); procedure SetDecimals(AValue: Byte);
protected protected
FWorkbook: TsWorkbook;
FSections: TsNumFormatSections;
{ Administration while scanning } { Administration while scanning }
procedure AddElement(AToken: TsNumFormatToken; AText: String); overload; procedure AddElement(AToken: TsNumFormatToken; AText: String); overload;
procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer); overload; procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer); overload;
@ -275,13 +275,11 @@ end;
{ Creates a formatstring for all sections. { Creates a formatstring for all sections.
Note: this implementation is only valid for the fpc and Excel dialects of 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; function TsNumFormatParser.BuildFormatString(ADialect: TsNumFormatDialect): String;
var var
i: Integer; i: Integer;
begin begin
if ADialect = nfdOther then
raise Exception.Create('nfdOther cannot be used in TsNumFormatParser.BuildFormatString');
if Length(FSections) > 0 then begin if Length(FSections) > 0 then begin
Result := BuildFormatStringFromSection(0, ADialect); Result := BuildFormatStringFromSection(0, ADialect);
for i := 1 to High(FSections) do for i := 1 to High(FSections) do
@ -291,8 +289,7 @@ begin
end; end;
{ Creates a format string for the given section. This implementation covers { Creates a format string for the given section. This implementation covers
the formatstring dialects of fpc (nfdDefault) and Excel (nfdExcel). the formatstring dialects of fpc (nfdDefault) and Excel (nfdExcel). }
Needs to be overridden for xml. }
function TsNumFormatParser.BuildFormatStringFromSection(ASection: Integer; function TsNumFormatParser.BuildFormatStringFromSection(ASection: Integer;
ADialect: TsNumFormatDialect): String; ADialect: TsNumFormatDialect): String;
var var
@ -301,9 +298,6 @@ var
begin begin
Result := ''; Result := '';
if ADialect = nfdOther then
raise Exception.Create('nfdOther cannot be used in TsNumFormatParser.BuildFormatString');
if (ASection < 0) and (ASection >= GetParsedSectionCount) then if (ASection < 0) and (ASection >= GetParsedSectionCount) then
exit; exit;
for i := 0 to High(FSections[ASection].Elements) do begin for i := 0 to High(FSections[ASection].Elements) do begin

View File

@ -39,7 +39,7 @@ uses
fpspreadsheet, fpspreadsheet,
laz2_xmlread, laz2_DOM, laz2_xmlread, laz2_DOM,
AVL_Tree, math, dateutils, AVL_Tree, math, dateutils,
fpsutils; fpsutils, fpsNumFormatParser;
type type
TDateMode=( TDateMode=(
@ -49,12 +49,22 @@ type
); );
{ TsSpreadOpenDocNumFormatList } { TsSpreadOpenDocNumFormatList }
TsSpreadOpenDocNumFormatList = class(TsCustomNumFormatList) TsSpreadOpenDocNumFormatList = class(TsCustomNumFormatList)
protected protected
procedure AddBuiltinFormats; override; procedure AddBuiltinFormats; override;
public public
end; 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 }
TsSpreadOpenDocReader = class(TsCustomSpreadReader) TsSpreadOpenDocReader = class(TsCustomSpreadReader)
@ -117,6 +127,7 @@ type
// Routines to write parts of files // Routines to write parts of files
function WriteCellStylesXMLAsString: string; function WriteCellStylesXMLAsString: string;
function WriteColStylesXMLAsString: String; function WriteColStylesXMLAsString: String;
function WriteNumFormatsXMLAsString: String;
function WriteRowStylesXMLAsString: String; function WriteRowStylesXMLAsString: String;
function WriteColumnsXMLAsString(ASheet: TsWorksheet): String; function WriteColumnsXMLAsString(ASheet: TsWorksheet): String;
@ -290,6 +301,105 @@ begin
end; 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 +
' <style:map ' +
'style:apply-style-name="' + fmtName + 'P0" ' +
'style:condition="value()>=0" />' + LineEnding; // >= 0
3: sStyleMap := AIndent +
' <style:map '+
'style:apply-style-name="' + fmtName + 'P0" ' + // > 0
'style:condition="value()>0" />' + LineEnding + AIndent +
' <style:map '+
'style:apply-style-name="' + fmtName + 'P1" ' + // < 0
'style:condition="value()<0" />' + 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 + '<style:text-properties fo:color="' + ColorToHTMLColorStr(clr) + '" />' + 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 +
'<number:number-style style:name="' + fmtName + '">' + LineEnding +
sColor + AIndent +
' <number:number ' +
'number:min-integer-digits="1" ' + sGrouping +
'number:decimal-places="' + IntToStr(decs) +
'" />' + LineEnding +
sStylemap + AIndent +
'</number:number-style>' + LineEnding;
exit;
end;
end;
// nfPercentage
if IsTokenAt(nftPercent, ASection, next) and (next+1 = Length(Elements))
then begin
Result := AIndent +
'<number:percentage-style style:name="' + fmtName + '">' + LineEnding +
sColor + AIndent +
' <number:number ' +
'number:min-integer-digits="1" ' + sGrouping +
'number:decimal-places="' + IntToStr(decs) +
'" />' + LineEnding + AIndent +
' <number:text>%</number:text>' + LineEnding +
sStyleMap + AIndent +
'</number:percentage-style>' + LineEnding;
exit;
end;
end;
// ... more to follow...
end;
{ TsSpreadOpenDocReader } { TsSpreadOpenDocReader }
constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook); constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook);
@ -1905,11 +2015,14 @@ var
lCellStylesCode: string; lCellStylesCode: string;
lColStylesCode: String; lColStylesCode: String;
lRowStylesCode: String; lRowStylesCode: String;
lNumFmtCode: String;
begin begin
ListAllColumnStyles; ListAllColumnStyles;
ListAllRowStyles; ListAllRowStyles;
ListAllFormattingStyles; ListAllFormattingStyles;
lNumFmtCode := WriteNumFormatsXMLAsString;
lColStylesCode := WriteColStylesXMLAsString; lColStylesCode := WriteColStylesXMLAsString;
if lColStylesCode = '' then lColStylesCode := if lColStylesCode = '' then lColStylesCode :=
' <style:style style:name="co1" style:family="table-column">' + LineEnding + ' <style:style style:name="co1" style:family="table-column">' + LineEnding +
@ -1956,6 +2069,7 @@ begin
// Automatic styles // Automatic styles
' <office:automatic-styles>' + LineEnding + ' <office:automatic-styles>' + LineEnding +
lNumFmtCode +
lColStylesCode + lColStylesCode +
lRowStylesCode + lRowStylesCode +
' <style:style style:name="ta1" style:family="table" style:master-page-name="Default">' + LineEnding + ' <style:style style:name="ta1" style:family="table" style:master-page-name="Default">' + LineEnding +
@ -2138,6 +2252,41 @@ begin
end; end;
end; end;
function TsSpreadOpenDocWriter.WriteNumFormatsXMLAsString: String;
var
i: Integer;
numFmtXML: String;
parser: TsSpreadOpenDocNumFormatParser;
begin
{
<number:number-style style:name="N2">
<number:number number:decimal-places="2" number:min-integer-digits="1" />
</number:number-style>
' <number:number-style style:name="N2">
<number:number number:min-integer-digits="1" number:grouping="true" number:decimal-places="2"/>
</number:number-style>
' <number:number-style style:name="N2">
<number:number number:decimal-places="2" number:min-integer-digits="1" />
</number:number-style>
}
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; function TsSpreadOpenDocWriter.WriteRowsAndCellsXMLAsString(ASheet: TsWorksheet): String;
var var
r, rr: Cardinal; // row index in sheet r, rr: Cardinal; // row index in sheet