fpspreadsheet: Writing of number formats for xlsx (date/time not working yet)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3318 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-07-14 20:47:53 +00:00
parent 9607fc8e88
commit 3f292f5e99
2 changed files with 127 additions and 23 deletions

View File

@ -5172,7 +5172,7 @@ end;
ConvertBeforeWriting in order to convert the fpc format strings to the dialect ConvertBeforeWriting in order to convert the fpc format strings to the dialect
used in the file. used in the file.
@param AIndex The number format at this item is considered. @param AIndex Index of the format item under consideration.
@return String of formatting codes that will be written to the file. } @return String of formatting codes that will be written to the file. }
function TsCustomNumFormatList.FormatStringForWriting(AIndex: Integer): String; function TsCustomNumFormatList.FormatStringForWriting(AIndex: Integer): String;
var var

View File

@ -44,15 +44,10 @@ type
{ TsOOXMLFormatList } { TsOOXMLFormatList }
TsOOXMLNumFormatList = class(TsCustomNumFormatList) TsOOXMLNumFormatList = class(TsCustomNumFormatList)
protected protected
{
procedure AddBuiltinFormats; override; procedure AddBuiltinFormats; override;
procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
var ANumFormat: TsNumberFormat; var ADecimals: Word); override;
}
public public
{ procedure ConvertBeforeWriting(var AFormatString: String;
function FormatStringForWriting(AIndex: Integer): String; override; var ANumFormat: TsNumberFormat); override;
}
end; end;
{ TsSpreadOOXMLWriter } { TsSpreadOOXMLWriter }
@ -79,6 +74,7 @@ type
procedure WriteBorderList(AStream: TStream); procedure WriteBorderList(AStream: TStream);
procedure WriteFillList(AStream: TStream); procedure WriteFillList(AStream: TStream);
procedure WriteFontList(AStream: TStream); procedure WriteFontList(AStream: TStream);
procedure WriteNumFormatList(AStream: TStream);
procedure WriteStyleList(AStream: TStream; ANodeName: String); procedure WriteStyleList(AStream: TStream; ANodeName: String);
protected protected
{ Streams with the contents of files } { Streams with the contents of files }
@ -115,7 +111,7 @@ type
implementation implementation
uses uses
variants; variants, fpsNumFormatParser;
const const
{ OOXML general XML constants } { OOXML general XML constants }
@ -157,6 +153,81 @@ const
MIME_STRINGS = MIME_SPREADML + '.sharedStrings+xml'; MIME_STRINGS = MIME_SPREADML + '.sharedStrings+xml';
{ TsOOXMLNumFormatList }
{ These are the built-in number formats as expected in the biff spreadsheet file.
Identical to BIFF8. These formats are not written to file but they are used
for lookup of the number format that Excel used. They are specified here in
fpc dialect. }
procedure TsOOXMLNumFormatList.AddBuiltinFormats;
var
fs: TFormatSettings;
cs: String;
begin
fs := Workbook.FormatSettings;
cs := AnsiToUTF8(Workbook.FormatSettings.CurrencyString);
AddFormat( 0, '', nfGeneral);
AddFormat( 1, '0', nfFixed);
AddFormat( 2, '0.00', nfFixed);
AddFormat( 3, '#,##0', nfFixedTh);
AddFormat( 4, '#,##0.00', nfFixedTh);
AddFormat( 5, '"'+cs+'"#,##0_);("'+cs+'"#,##0)', nfCurrency);
AddFormat( 6, '"'+cs+'"#,##0_);[Red]("'+cs+'"#,##0)', nfCurrencyRed);
AddFormat( 7, '"'+cs+'"#,##0.00_);("'+cs+'"#,##0.00)', nfCurrency);
AddFormat( 8, '"'+cs+'"#,##0.00_);[Red]("'+cs+'"#,##0.00)', nfCurrencyRed);
AddFormat( 9, '0%', nfPercentage);
AddFormat(10, '0.00%', nfPercentage);
AddFormat(11, '0.00E+00', nfExp);
// fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
AddFormat(14, fs.ShortDateFormat, nfShortDate); // 'M/D/YY'
AddFormat(15, fs.LongDateFormat, nfLongDate); // 'D-MMM-YY'
AddFormat(16, 'd/mmm', nfCustom); // 'D-MMM'
AddFormat(17, 'mmm/yy', nfCustom); // 'MMM-YY'
AddFormat(18, AddAMPM(fs.ShortTimeFormat, fs), nfShortTimeAM); // 'h:mm AM/PM'
AddFormat(19, AddAMPM(fs.LongTimeFormat, fs), nfLongTimeAM); // 'h:mm:ss AM/PM'
AddFormat(20, fs.ShortTimeFormat, nfShortTime); // 'h:mm'
AddFormat(21, fs.LongTimeFormat, nfLongTime); // 'h:mm:ss'
AddFormat(22, fs.ShortDateFormat + ' ' + fs.ShortTimeFormat, nfShortDateTime); // 'M/D/YY h:mm' (localized)
// 23..36 not supported
AddFormat(37, '_(#,##0_);(#,##0)', nfCurrency);
AddFormat(38, '_(#,##0_);[Red](#,##0)', nfCurrencyRed);
AddFormat(39, '_(#,##0.00_);(#,##0.00)', nfCurrency);
AddFormat(40, '_(#,##0.00_);[Red](#,##0.00)', nfCurrencyRed);
AddFormat(41, '_("'+cs+'"* #,##0_);_("'+cs+'"* (#,##0);_("'+cs+'"* "-"_);_(@_)', nfCustom);
AddFormat(42, '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)', nfCustom);
AddFormat(43, '_("'+cs+'"* #,##0.00_);_("'+cs+'"* (#,##0.00);_("'+cs+'"* "-"??_);_(@_)', nfCustom);
AddFormat(44, '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)', nfCustom);
AddFormat(45, 'nn:ss', nfCustom);
AddFormat(46, '[h]:nn:ss', nfTimeInterval);
AddFormat(47, 'nn:ss.z', nfCustom);
AddFormat(48, '##0.0E+00', nfCustom);
// 49 ("Text") not supported
// All indexes from 0 to 163 are reserved for built-in formats.
// The first user-defined format starts at 164.
FFirstFormatIndexInFile := 164;
FNextFormatIndex := 164;
end;
procedure TsOOXMLNumFormatList.ConvertBeforeWriting(var AFormatString: String;
var ANumFormat: TsNumberFormat);
var
parser: TsNumFormatParser;
begin
parser := TsNumFormatParser.Create(Workbook, AFormatString, ANumFormat);
try
if parser.Status = psOK then begin
// For writing, we have to convert the fpc format string to Excel dialect
AFormatString := parser.FormatString[nfdExcel];
ANumFormat := parser.NumFormat;
end;
finally
parser.Free;
end;
end;
{ TsSpreadOOXMLWriter } { TsSpreadOOXMLWriter }
{ Adds built-in styles: { Adds built-in styles:
@ -452,6 +523,38 @@ begin
'</fonts>'); '</fonts>');
end; end;
{ Writes all number formats to the stream. Saving starts at the item with the
FirstFormatIndexInFile. }
procedure TsSpreadOOXMLWriter.WriteNumFormatList(AStream: TStream);
var
i: Integer;
item: TsNumFormatData;
s: String;
n: Integer;
fmt: String;
begin
s := '';
n := 0;
i := NumFormatList.FindByIndex(NumFormatList.FirstFormatIndexInFile);
if i > -1 then begin
while i < NumFormatList.Count do begin
item := NumFormatList[i];
if item <> nil then begin
s := s + Format('<numFmt numFmtId="%d" formatCode="%s" />',
[item.Index, UTF8TextToXMLText(NumFormatList.FormatStringForWriting(i))]);
inc(n);
end;
inc(i);
end;
if n > 0 then
AppendToStream(AStream, Format(
'<numFmts count="%d">', [n]),
s,
'</numFmts>'
);
end;
end;
{ Writes the style list which the writer has collected in FFormattingStyles. } { Writes the style list which the writer has collected in FFormattingStyles. }
procedure TsSpreadOOXMLWriter.WriteStyleList(AStream: TStream; ANodeName: String); procedure TsSpreadOOXMLWriter.WriteStyleList(AStream: TStream; ANodeName: String);
var var
@ -461,6 +564,7 @@ var
numFmtId: Integer; numFmtId: Integer;
fillId: Integer; fillId: Integer;
borderId: Integer; borderId: Integer;
idx: Integer;
begin begin
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<%s count="%d">', [ANodeName, Length(FFormattingStyles)])); '<%s count="%d">', [ANodeName, Length(FFormattingStyles)]));
@ -470,8 +574,13 @@ begin
sAlign := ''; sAlign := '';
{ Number format } { Number format }
numFmtId := 0; if (uffNumberFormat in styleCell.UsedFormattingFields) then begin
s := s + Format('numFmtId="%d" ', [numFmtId]); idx := NumFormatList.FindFormatOf(@styleCell);
if idx > -1 then begin
numFmtID := NumFormatList[idx].Index;
s := s + Format('numFmtId="%d" applyNumberFormat="1" ', [numFmtId]);
end;
end;
{ Font } { Font }
fontId := 0; fontId := 0;
@ -586,6 +695,9 @@ begin
AppendToStream(FSStyles, Format( AppendToStream(FSStyles, Format(
'<styleSheet xmlns="%s">', [SCHEMAS_SPREADML])); '<styleSheet xmlns="%s">', [SCHEMAS_SPREADML]));
// Number formats
WriteNumFormatList(FSStyles);
// Fonts // Fonts
WriteFontList(FSStyles); WriteFontList(FSStyles);
@ -594,16 +706,7 @@ begin
// Borders // Borders
WriteBorderList(FSStyles); WriteBorderList(FSStyles);
{
AppendToStream(FSStyles,
'<borders count="1">');
AppendToStream(FSStyles,
'<border>',
'<left /><right /><top /><bottom /><diagonal />',
'</border>');
AppendToStream(FSStyles,
'</borders>');
}
// Style records // Style records
AppendToStream(FSStyles, AppendToStream(FSStyles,
'<cellStyleXfs count="1">', '<cellStyleXfs count="1">',
@ -1088,13 +1191,14 @@ procedure TsSpreadOOXMLWriter.WriteNumber(AStream: TStream; const ARow,
var var
CellPosText: String; CellPosText: String;
CellValueText: String; CellValueText: String;
//S: String; lStyleIndex: Integer;
begin begin
Unused(AStream, ACell); Unused(AStream, ACell);
CellPosText := TsWorksheet.CellPosToText(ARow, ACol); CellPosText := TsWorksheet.CellPosToText(ARow, ACol);
CellValueText := Format('%g', [AValue], FPointSeparatorSettings); CellValueText := Format('%g', [AValue], FPointSeparatorSettings);
lStyleIndex := GetStyleIndex(ACell);
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<c r="%s" s="0" t="n"><v>%s</v></c>', [CellPosText, CellValueText])); '<c r="%s" s="%d" t="n"><v>%s</v></c>', [CellPosText, lStyleIndex, CellValueText]));
end; end;
{******************************************************************* {*******************************************************************