You've already forked lazarus-ccr
fpspreadsheet: Integrate number format parser into fpspreadsheet. Some regressions in format detection...
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3068 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -29,7 +29,8 @@ var
|
||||
number: Double;
|
||||
lCell: PCell;
|
||||
lCol: TCol;
|
||||
i, r: Integer;
|
||||
i: Integer;
|
||||
r: Integer = 10;
|
||||
begin
|
||||
MyDir := ExtractFilePath(ParamStr(0));
|
||||
|
||||
@ -53,7 +54,7 @@ begin
|
||||
}
|
||||
|
||||
// Write some cells
|
||||
// MyWorksheet.WriteNumber(0, 0, 1.0);// A1
|
||||
MyWorksheet.WriteDateTime(0, 20, now, nfShortTime); //1.0);// A1
|
||||
MyWorksheet.WriteNumber(0, 0, 1.0, nfFixed, 3);// A1
|
||||
MyWorksheet.WriteNumber(0, 1, 2.0);// B1
|
||||
MyWorksheet.WriteNumber(0, 2, 3.0);// C1
|
||||
@ -206,10 +207,6 @@ begin
|
||||
inc(r);
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
|
||||
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
|
||||
// NOTE: The upper option "MSZ" = "mm:ss.z" should result only in 1 decimal.
|
||||
// This is true for writing, but in reading always 3 decimals are displayed.
|
||||
// This is due to fpc's SysUtile.FormatDateTime which does not distinguish
|
||||
// both cases.
|
||||
|
||||
// Write formatted numbers
|
||||
number := 12345.67890123456789;
|
||||
@ -252,7 +249,6 @@ begin
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
|
||||
MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
|
||||
MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
|
||||
|
||||
inc(r,2);
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
|
||||
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
|
||||
|
@ -137,8 +137,7 @@
|
||||
<Unit2>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<UnitName Value="fpspreadsheet"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<EditorIndex Value="5"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="132"/>
|
||||
<CursorPos X="16" Y="164"/>
|
||||
@ -148,7 +147,7 @@
|
||||
<Unit3>
|
||||
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
|
||||
<UnitName Value="fpspreadsheetgrid"/>
|
||||
<EditorIndex Value="8"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="636"/>
|
||||
<CursorPos X="20" Y="647"/>
|
||||
@ -286,10 +285,11 @@
|
||||
<Unit20>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<UnitName Value="xlscommon"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="4"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="1181"/>
|
||||
<CursorPos X="31" Y="1194"/>
|
||||
<TopLine Value="650"/>
|
||||
<CursorPos X="16" Y="662"/>
|
||||
<UsageCount Value="88"/>
|
||||
<Bookmarks Count="1">
|
||||
<Item0 X="41" Y="1209" ID="1"/>
|
||||
@ -577,143 +577,139 @@
|
||||
</Unit57>
|
||||
<Unit58>
|
||||
<Filename Value="d:\lazarus-svn\fpc\2.6.2\source\rtl\objpas\sysutils\dati.inc"/>
|
||||
<EditorIndex Value="5"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="890"/>
|
||||
<CursorPos X="16" Y="796"/>
|
||||
<UsageCount Value="15"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit58>
|
||||
<Unit59>
|
||||
<Filename Value="d:\lazarus-svn\fpc\2.6.2\source\rtl\objpas\sysutils\sysinth.inc"/>
|
||||
<EditorIndex Value="7"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="36"/>
|
||||
<CursorPos X="5" Y="43"/>
|
||||
<UsageCount Value="13"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit59>
|
||||
</Units>
|
||||
<JumpHistory Count="30" HistoryIndex="29">
|
||||
<Position1>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Caret Line="164" Column="60" TopLine="132"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="164" Column="60" TopLine="132"/>
|
||||
<Caret Line="1511" Column="15" TopLine="1478"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="1511" Column="15" TopLine="1478"/>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1170" Column="36" TopLine="1170"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1170" Column="36" TopLine="1170"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Caret Line="940" Column="14" TopLine="908"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="940" Column="14" TopLine="908"/>
|
||||
<Caret Line="960" Column="14" TopLine="928"/>
|
||||
</Position6>
|
||||
<Position7>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="960" Column="14" TopLine="928"/>
|
||||
<Caret Line="1013" Column="14" TopLine="982"/>
|
||||
</Position7>
|
||||
<Position8>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1013" Column="14" TopLine="982"/>
|
||||
<Caret Line="1059" Column="14" TopLine="1027"/>
|
||||
</Position8>
|
||||
<Position9>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1059" Column="14" TopLine="1027"/>
|
||||
<Caret Line="1081" Column="41" TopLine="1049"/>
|
||||
</Position9>
|
||||
<Position10>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1081" Column="41" TopLine="1049"/>
|
||||
<Caret Line="1089" Column="43" TopLine="1057"/>
|
||||
</Position10>
|
||||
<Position11>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1089" Column="43" TopLine="1057"/>
|
||||
<Caret Line="1093" Column="14" TopLine="1061"/>
|
||||
</Position11>
|
||||
<Position12>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1093" Column="14" TopLine="1061"/>
|
||||
<Caret Line="1157" Column="14" TopLine="1126"/>
|
||||
</Position12>
|
||||
<Position13>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1157" Column="14" TopLine="1126"/>
|
||||
<Caret Line="1197" Column="20" TopLine="1177"/>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1197" Column="20" TopLine="1177"/>
|
||||
<Caret Line="403" Column="16" TopLine="397"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="403" Column="16" TopLine="397"/>
|
||||
<Caret Line="924" Column="14" TopLine="893"/>
|
||||
</Position15>
|
||||
<Position16>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="924" Column="14" TopLine="893"/>
|
||||
<Caret Line="413" Column="19" TopLine="402"/>
|
||||
</Position16>
|
||||
<Position17>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="413" Column="19" TopLine="402"/>
|
||||
<Caret Line="414" Column="33" TopLine="388"/>
|
||||
</Position17>
|
||||
<Position18>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="414" Column="33" TopLine="388"/>
|
||||
<Caret Line="854" Column="39" TopLine="825"/>
|
||||
</Position18>
|
||||
<Position19>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="854" Column="39" TopLine="825"/>
|
||||
<Caret Line="672" Column="1" TopLine="648"/>
|
||||
</Position19>
|
||||
<Position20>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="672" Column="1" TopLine="648"/>
|
||||
<Caret Line="870" Column="1" TopLine="832"/>
|
||||
</Position20>
|
||||
<Position21>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="870" Column="1" TopLine="832"/>
|
||||
<Caret Line="867" Column="24" TopLine="848"/>
|
||||
</Position21>
|
||||
<Position22>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="867" Column="24" TopLine="848"/>
|
||||
<Caret Line="926" Column="34" TopLine="907"/>
|
||||
</Position22>
|
||||
<Position23>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="926" Column="34" TopLine="907"/>
|
||||
<Caret Line="956" Column="1" TopLine="937"/>
|
||||
</Position23>
|
||||
<Position24>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="956" Column="1" TopLine="937"/>
|
||||
<Caret Line="1024" Column="63" TopLine="1006"/>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1024" Column="63" TopLine="1006"/>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="1478" Column="48" TopLine="1478"/>
|
||||
</Position25>
|
||||
<Position26>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="1478" Column="48" TopLine="1478"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position26>
|
||||
<Position27>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1058" Column="9" TopLine="1039"/>
|
||||
</Position27>
|
||||
<Position28>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1058" Column="9" TopLine="1039"/>
|
||||
<Caret Line="1055" Column="44" TopLine="1039"/>
|
||||
</Position28>
|
||||
<Position29>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1055" Column="44" TopLine="1039"/>
|
||||
<Caret Line="1135" Column="22" TopLine="1120"/>
|
||||
</Position29>
|
||||
<Position30>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1135" Column="22" TopLine="1120"/>
|
||||
<Filename Value="..\..\fpspreadsheet.pas"/>
|
||||
<Caret Line="164" Column="16" TopLine="132"/>
|
||||
</Position30>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
@ -743,15 +739,6 @@
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<BreakPoints Count="1">
|
||||
<Item1>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="..\..\xlscommon.pas"/>
|
||||
<Line Value="664"/>
|
||||
</Item1>
|
||||
</BreakPoints>
|
||||
<Watches Count="2">
|
||||
<Item1>
|
||||
<Expression Value="recordtype"/>
|
||||
|
@ -27,6 +27,8 @@ type
|
||||
coEqual, coNotEqual, coLess, coGreater, coLessEqual, coGreaterEqual
|
||||
);
|
||||
|
||||
TsConversionDirection = (cdToFPSpreadsheet, cdFromFPSpreadsheet);
|
||||
|
||||
TsNumFormatSection = record
|
||||
FormatString: String;
|
||||
CompareOperation: TsCompareOperation;
|
||||
@ -38,17 +40,23 @@ type
|
||||
NumFormat: TsNumberFormat;
|
||||
end;
|
||||
|
||||
TsNumFormatSections = array of TsNumFormatSection;
|
||||
|
||||
TsNumFormatParser = class
|
||||
private
|
||||
FCreateMethod: Byte;
|
||||
FWorkbook: TsWorkbook;
|
||||
FCurrent: PChar;
|
||||
FStart: PChar;
|
||||
FEnd: PChar;
|
||||
FCurrSection: Integer;
|
||||
FSections: array of TsNumFormatSection;
|
||||
FSections: TsNumFormatSections;
|
||||
FFormatSettings: TFormatSettings;
|
||||
FFormatString: String;
|
||||
FNumFormat: TsNumberFormat;
|
||||
FConversionDirection: TsConversionDirection;
|
||||
FStatus: Integer;
|
||||
function GetFormatString: String;
|
||||
function GetParsedSectionCount: Integer;
|
||||
function GetParsedSections(AIndex: Integer): TsNumFormatSection;
|
||||
|
||||
@ -58,6 +66,8 @@ type
|
||||
procedure AnalyzeBracket(const AValue: String);
|
||||
procedure AnalyzeText(const AValue: String);
|
||||
procedure CheckSections;
|
||||
function CreateFormatStringFromSection(ASection: Integer): String; virtual;
|
||||
function CreateFormatStringFromSections: String;
|
||||
procedure Parse(const AFormatString: String);
|
||||
procedure ScanAMPM(var s: String);
|
||||
procedure ScanBrackets;
|
||||
@ -68,9 +78,16 @@ type
|
||||
procedure ScanText;
|
||||
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook; const AFormatString: String);
|
||||
constructor Create(AWorkbook: TsWorkbook; const AFormatString: String;
|
||||
AConversionDirection: TsConversionDirection = cdToFPSpreadsheet); overload;
|
||||
constructor Create(AWorkbook: TsWorkbook; const AFormatSections: TsNumFormatSections;
|
||||
AConversionDirection: TsConversionDirection = cdFromFPSpreadsheet); overload;
|
||||
destructor Destroy; override;
|
||||
property FormatString: String read FFormatString;
|
||||
procedure CopySections(const FromSections: TsNumFormatSections;
|
||||
var ToSections: TsNumFormatSections);
|
||||
procedure CopySectionsTo(var ADestination: TsNumFormatSections);
|
||||
property Builtin_NumFormat: TsNumberFormat read FNumFormat;
|
||||
property FormatString: String read GetFormatString;
|
||||
property ParsedSectionCount: Integer read GetParsedSectionCount;
|
||||
property ParsedSections[AIndex: Integer]: TsNumFormatSection read GetParsedSections;
|
||||
property Status: Integer read FStatus;
|
||||
@ -88,10 +105,15 @@ const
|
||||
|
||||
{ TsNumFormatParser }
|
||||
|
||||
{ Creates a number format parser for analyzing a formatstring that has been read
|
||||
from a spreadsheet file. The conversion, by default, will go FROM the file TO
|
||||
the fpspreadsheet procedures. }
|
||||
constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook;
|
||||
const AFormatString: String);
|
||||
const AFormatString: String; AConversionDirection: TsConversionDirection = cdToFPSpreadsheet);
|
||||
begin
|
||||
inherited Create;
|
||||
FCreateMethod := 0;
|
||||
FConversionDirection := AConversionDirection;
|
||||
FWorkbook := AWorkbook;
|
||||
FFormatSettings := DefaultFormatSettings;
|
||||
FFormatSettings.DecimalSeparator := '.';
|
||||
@ -99,6 +121,22 @@ begin
|
||||
Parse(AFormatString);
|
||||
end;
|
||||
|
||||
{ Creates a number format parser to create a format string from the individual
|
||||
format sections given in "AFormatSections". It is assumed by default that the
|
||||
format string will be written to file. Therefore, it can contain features of
|
||||
the destination file format and, in general, will not work if called by
|
||||
fpspreadsheet. }
|
||||
constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook;
|
||||
const AFormatSections: TsNumFormatSections;
|
||||
AConversionDirection: TsConversionDirection = cdFromFPSpreadsheet);
|
||||
begin
|
||||
inherited Create;
|
||||
FCreateMethod := 1;
|
||||
FConversionDirection := AConversionDirection;
|
||||
FWorkbook := AWorkbook;
|
||||
CopySections(AFormatSections, FSections);
|
||||
end;
|
||||
|
||||
destructor TsNumFormatParser.Destroy;
|
||||
begin
|
||||
FSections := nil;
|
||||
@ -119,7 +157,7 @@ begin
|
||||
FormatString := '';
|
||||
CompareOperation := coNotUsed;
|
||||
CompareValue := 0.0;
|
||||
Color := scBlack;
|
||||
Color := scNotDefined;
|
||||
CountryCode := '';
|
||||
CurrencySymbol := '';
|
||||
Decimals := 0;
|
||||
@ -221,6 +259,7 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Check format strings
|
||||
case FSections[i].NumFormat of
|
||||
nfGeneral, nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci, nfCurrency:
|
||||
try
|
||||
@ -241,6 +280,29 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Extract built-in NumFormat identifier for currency (needs several entries in
|
||||
// three sections).
|
||||
if (ns = 3) and
|
||||
(FSections[0].NumFormat = nfCurrency) and
|
||||
(FSections[1].NumFormat = nfCurrency) and
|
||||
(FSections[2].NumFormat = nfCurrency)
|
||||
then begin
|
||||
if ((FSections[2].FormatString = '-') or (FSections[2].FormatString = '"-"')) then begin
|
||||
if (FSections[1].Color = scRed) then
|
||||
FNumFormat := nfCurrencyDashRed
|
||||
else
|
||||
FNumFormat := nfCurrencyDash;
|
||||
end else begin
|
||||
if (FSections[1].Color = scRed) then
|
||||
FNumFormat := nfCurrencyRed;
|
||||
end;
|
||||
end else
|
||||
// If there are other multi-section formatstrings they must be a custom format
|
||||
if (ns > 1) then
|
||||
FNumFormat := nfCustom
|
||||
else
|
||||
FNumFormat := FSections[0].NumFormat;
|
||||
|
||||
if ns = 2 then
|
||||
FFormatString := Format('%s;%s;%s', [
|
||||
FSections[0].FormatString,
|
||||
@ -256,33 +318,79 @@ begin
|
||||
FStatus := psErrNoUsableFormat;
|
||||
end;
|
||||
|
||||
{
|
||||
function TsNumFormatParser.GetNumFormat: TsNumberFormat;
|
||||
procedure TsNumFormatParser.CopySections(
|
||||
const FromSections: TsNumFormatSections; var ToSections: TsNumformatSections);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if FStatus <> psOK then
|
||||
Result := nfGeneral
|
||||
else
|
||||
if (FSections[0].NumFormat = nfCurrency) and (FSections[1].NumFormat = nfCurrency) and
|
||||
(FSections[2].NumFormat = nfCurrency)
|
||||
then begin
|
||||
if (FSections[1].Color = scNotDefined) then begin
|
||||
if (FSections[2].FormatString = '-') then
|
||||
Result := nfCurrencyDash
|
||||
else
|
||||
Result := nfCurrency;
|
||||
end else
|
||||
if FSections[1].Color = scRed then begin
|
||||
if (FSections[2].Formatstring = '-') then
|
||||
Result := nfCurrencyDashRed
|
||||
else
|
||||
Result := nfCurrencyRed;
|
||||
end;
|
||||
end else
|
||||
Result := FSections[0].NumFormat;
|
||||
SetLength(ToSections, Length(FromSections));
|
||||
for i:= 0 to High(FromSections) do begin
|
||||
ToSections[i].FormatString := FromSections[i].FormatString;
|
||||
ToSections[i].CompareOperation := FromSections[i].CompareOperation;
|
||||
ToSections[i].CompareValue := FromSections[i].CompareValue;
|
||||
ToSections[i].Color := FromSections[i].Color;
|
||||
ToSections[i].CurrencySymbol := FromSections[i].CurrencySymbol;
|
||||
ToSections[i].Decimals := FromSections[i].Decimals;
|
||||
ToSections[i].NumFormat := FromSections[i].NumFormat;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsNumFormatParser.CopySectionsTo(var ADestination: TsNumFormatSections);
|
||||
begin
|
||||
CopySections(FSections, ADestination);
|
||||
end;
|
||||
|
||||
function TsNumFormatParser.CreateFormatStringFromSections: String;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
if Length(FSections) = 0 then
|
||||
Result := ''
|
||||
else begin
|
||||
Result := CreateFormatStringFromSection(0);
|
||||
for i:=1 to High(FSections) do
|
||||
Result := Result + ';' + CreateFormatStringFromSection(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TsNumFormatParser.CreateFormatStringFromSection(ASection: Integer): String;
|
||||
begin
|
||||
with FSections[ASection] do
|
||||
if (NumFormat = nfFmtDateTime) or (NumFormat = nfCustom) then begin
|
||||
Result := FormatString;
|
||||
exit;
|
||||
end;
|
||||
|
||||
Result := BuildNumberFormatString(FSections[ASection].NumFormat,
|
||||
FWorkbook.FormatSettings,
|
||||
FSections[ASection].Decimals,
|
||||
FSections[ASection].CurrencySymbol
|
||||
);
|
||||
if FConversionDirection = cdFromFPSpreadsheet then begin
|
||||
// This is typical of Excel, but is valid for all others as well.
|
||||
// Override if you need to change
|
||||
if FSections[ASection].Color < 8 then
|
||||
Result := Format('[%s]%s', [FWorkbook.GetColorName(FSections[ASection].Color), Result])
|
||||
else
|
||||
if FSections[ASection].Color < scNotDefined then
|
||||
Result := Format('[Color%d]%s', [FSections[ASection].Color, Result]);
|
||||
|
||||
if FSections[ASection].CompareOperation <> coNotUsed then
|
||||
Result := Format('[%s%g]%s', [
|
||||
COMPARE_STR[FSections[ASection].CompareOperation],
|
||||
FSections[ASection].CompareValue,
|
||||
Result
|
||||
]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TsNumFormatParser.GetFormatString: String;
|
||||
begin
|
||||
case FCreateMethod of
|
||||
0: Result := FFormatString;
|
||||
1: Result := CreateFormatStringFromSections;
|
||||
end;
|
||||
end;
|
||||
}
|
||||
|
||||
function TsNumFormatParser.GetParsedSectionCount: Integer;
|
||||
begin
|
||||
@ -355,74 +463,77 @@ begin
|
||||
while (FCurrent <= FEnd) and (FStatus = psOK) and (not done) do begin
|
||||
token := FCurrent^;
|
||||
case token of
|
||||
'\' : begin
|
||||
inc(FCurrent);
|
||||
token := FCurrent^;
|
||||
s := s + token;
|
||||
end;
|
||||
'Y', 'y' : begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := false;
|
||||
end;
|
||||
'M', 'm' : if isTime then // help fpc to separate "month" and "minute"
|
||||
ScanDateTimeParts(token, 'n', s)
|
||||
else // both "month" and "minute" work in fpc to some degree
|
||||
ScanDateTimeParts(token, token, s);
|
||||
'D', 'd' : begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := false;
|
||||
end;
|
||||
'H', 'h' : begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := true;
|
||||
end;
|
||||
'S', 's' : begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := true;
|
||||
end;
|
||||
'/', ':', '.', ']', '[', ' '
|
||||
: s := s + token;
|
||||
'0' : ScanDateTimeParts(token, 'z', s);
|
||||
'A', 'a' : begin
|
||||
ScanAMPM(s);
|
||||
isAMPM := true;
|
||||
end;
|
||||
else begin
|
||||
done := true;
|
||||
dec(FCurrent);
|
||||
// char pointer must be at end of date/time mask.
|
||||
end;
|
||||
'\':
|
||||
begin
|
||||
inc(FCurrent);
|
||||
token := FCurrent^;
|
||||
s := s + token;
|
||||
end;
|
||||
'Y', 'y':
|
||||
begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := false;
|
||||
end;
|
||||
'M', 'm':
|
||||
ScanDateTimeParts(token, token, s);
|
||||
{if isTime then // help fpc to separate "month" and "minute"
|
||||
ScanDateTimeParts(token, 'n', s)
|
||||
else // both "month" and "minute" work in fpc to some degree
|
||||
ScanDateTimeParts(token, token, s);}
|
||||
'N', 'n':
|
||||
ScanDateTimeParts(token, 'n', s); // fpc dialect for "minutes"
|
||||
'D', 'd':
|
||||
begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := false;
|
||||
end;
|
||||
'H', 'h':
|
||||
begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := true;
|
||||
end;
|
||||
'S', 's':
|
||||
begin
|
||||
ScanDateTimeParts(token, token, s);
|
||||
isTime := true;
|
||||
end;
|
||||
'/', ':', '.', ']', '[', ' ':
|
||||
s := s + token;
|
||||
'0', 'z', 'Z':
|
||||
ScanDateTimeParts(token, token, s);
|
||||
'A', 'a':
|
||||
begin
|
||||
ScanAMPM(s);
|
||||
isAMPM := true;
|
||||
end;
|
||||
else
|
||||
begin
|
||||
done := true;
|
||||
dec(FCurrent);
|
||||
// char pointer must be at end of date/time mask.
|
||||
end;
|
||||
end;
|
||||
if not done then inc(FCurrent);
|
||||
end;
|
||||
|
||||
FSections[FCurrSection].FormatString := FSections[FCurrSection].FormatString + s;
|
||||
s := FSections[FCurrSection].FormatString;
|
||||
if s <> '' then begin
|
||||
if s = FWorkbook.FormatSettings.LongDateFormat then
|
||||
nf := nfLongDate
|
||||
else
|
||||
if s = FWorkbook.FormatSettings.ShortDateFormat then
|
||||
nf := nfShortDate
|
||||
else
|
||||
if s = StripAMPM(FWorkbook.FormatSettings.LongTimeFormat) then
|
||||
nf := IfThen(isAMPM, nfLongTimeAM, nfLongTime)
|
||||
else
|
||||
if s = StripAMPM(FWorkbook.FormatSettings.ShortTimeFormat) then
|
||||
nf := IfThen(isAMPM, nfShortTimeAM, nfShortTime)
|
||||
else
|
||||
nf := nfFmtDateTime;
|
||||
|
||||
// Check format
|
||||
try
|
||||
if s <> '' then begin
|
||||
FormatDateTime(s, now);
|
||||
// !!!! MODIFY TO USE EXTENDED SYNTAX !!!!!
|
||||
|
||||
if s = FWorkbook.FormatSettings.LongDateFormat then
|
||||
nf := nfLongDate
|
||||
else
|
||||
if s = FWorkbook.FormatSettings.ShortDateFormat then
|
||||
nf := nfShortDate
|
||||
else
|
||||
if s = FWorkbook.FormatSettings.LongTimeFormat then
|
||||
nf := nfLongTime
|
||||
else
|
||||
if s = FWorkbook.FormatSettings.ShortTimeFormat then
|
||||
nf := nfShortTime
|
||||
else
|
||||
nf := nfFmtDateTime;
|
||||
FSections[FCurrSection].NumFormat := nf;
|
||||
end;
|
||||
|
||||
except
|
||||
FStatus := psErrNoValidDateTimeFormat;
|
||||
FSections[FCurrSection].NumFormat := nf;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -470,21 +581,27 @@ begin
|
||||
token := FCurrent^;
|
||||
case token of
|
||||
// Strip Excel's formatting symbols
|
||||
'\', '*' : ;
|
||||
'_' : inc(FCurrent);
|
||||
'"' : begin
|
||||
inc(FCurrent);
|
||||
ScanText;
|
||||
end;
|
||||
'0', '#', '.', ',', '-': ScanNumber;
|
||||
'y', 'Y', 'm', 'M',
|
||||
'd', 'D', 'h', 's', '[': ScanDateTime;
|
||||
' ' : AddChar(token);
|
||||
';' : begin
|
||||
done := true;
|
||||
dec(FCurrent);
|
||||
// Cursor must stay on the ";"
|
||||
end;
|
||||
'\', '*':
|
||||
;
|
||||
'_':
|
||||
inc(FCurrent);
|
||||
'"':
|
||||
begin
|
||||
inc(FCurrent);
|
||||
ScanText;
|
||||
end;
|
||||
'0', '#', '.', ',', '-':
|
||||
ScanNumber;
|
||||
'y', 'Y', 'm', 'M', 'd', 'D', 'h', 'N', 'n', 's', '[':
|
||||
ScanDateTime;
|
||||
' ':
|
||||
AddChar(token);
|
||||
';':
|
||||
begin
|
||||
done := true;
|
||||
dec(FCurrent);
|
||||
// Cursor must stay on the ";"
|
||||
end;
|
||||
end;
|
||||
if not done then inc(FCurrent);
|
||||
end;
|
||||
|
@ -184,7 +184,7 @@ end;
|
||||
procedure TsSpreadOpenDocReader.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
function TsSpreadOpenDocReader.GetAttrValue(ANode : TDOMNode; AAttrName : string) : string;
|
||||
@ -471,7 +471,7 @@ end;
|
||||
procedure TsSpreadOpenDocWriter.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocWriter.WriteMimetype;
|
||||
|
@ -362,16 +362,21 @@ type
|
||||
FOnChangeCell: TsCellEvent;
|
||||
FOnChangeFont: TsCellEvent;
|
||||
procedure RemoveCallback(data, arg: pointer);
|
||||
|
||||
protected
|
||||
procedure ChangedCell(ARow, ACol: Cardinal);
|
||||
procedure ChangedFont(ARow, ACol: Cardinal);
|
||||
|
||||
public
|
||||
Name: string;
|
||||
|
||||
{ Base methods }
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
|
||||
{ Utils }
|
||||
class function CellPosToText(ARow, ACol: Cardinal): string;
|
||||
|
||||
{ Data manipulation methods - For Cells }
|
||||
procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet);
|
||||
procedure CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal);
|
||||
@ -390,35 +395,25 @@ type
|
||||
function ReadUsedFormatting(ARow, ACol: Cardinal): TsUsedFormattingFields;
|
||||
function ReadBackgroundColor(ARow, ACol: Cardinal): TsColor;
|
||||
procedure RemoveAllCells;
|
||||
|
||||
{ Writing of values }
|
||||
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
||||
procedure WriteBlank(ARow, ACol: Cardinal);
|
||||
procedure WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
|
||||
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
||||
procedure WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
|
||||
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
|
||||
ACurrencySymbol: String = ''); overload;
|
||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||
AFormatString: String); overload;
|
||||
procedure WriteBlank(ARow, ACol: Cardinal);
|
||||
procedure WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
|
||||
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
||||
procedure WriteDecimals(ARow, ACol: Cardinal; ADecimals: byte); overload;
|
||||
procedure WriteDecimals(ACell: PCell; ADecimals: Byte); overload;
|
||||
procedure WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
|
||||
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
||||
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
|
||||
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
||||
|
||||
{ Writing of cell attributes }
|
||||
procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
|
||||
const AFormatString: String = '');
|
||||
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
||||
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
||||
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
|
||||
function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
||||
function WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
||||
function WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
||||
function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer;
|
||||
procedure WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation);
|
||||
procedure WriteUsedFormatting(ARow, ACol: Cardinal; AUsedFormatting: TsUsedFormattingFields);
|
||||
procedure WriteBackgroundColor(ARow, ACol: Cardinal; AColor: TsColor);
|
||||
|
||||
procedure WriteBorderColor(ARow, ACol: Cardinal; ABorder: TsCellBorder; AColor: TsColor);
|
||||
procedure WriteBorderLineStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
|
||||
ALineStyle: TsLineStyle);
|
||||
@ -428,9 +423,31 @@ type
|
||||
procedure WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
|
||||
ALineStyle: TsLineStyle; AColor: TsColor); overload;
|
||||
procedure WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles);
|
||||
|
||||
procedure WriteDecimals(ARow, ACol: Cardinal; ADecimals: byte); overload;
|
||||
procedure WriteDecimals(ACell: PCell; ADecimals: Byte); overload;
|
||||
|
||||
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
||||
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
||||
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
|
||||
function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
||||
function WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
||||
function WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
||||
function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer;
|
||||
|
||||
procedure WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
|
||||
|
||||
procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
|
||||
const AFormatString: String = '');
|
||||
|
||||
procedure WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation);
|
||||
|
||||
procedure WriteUsedFormatting(ARow, ACol: Cardinal; AUsedFormatting: TsUsedFormattingFields);
|
||||
|
||||
procedure WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment);
|
||||
|
||||
procedure WriteWordwrap(ARow, ACol: Cardinal; AValue: boolean);
|
||||
|
||||
{ Data manipulation methods - For Rows and Cols }
|
||||
function FindRow(ARow: Cardinal): PRow;
|
||||
function FindCol(ACol: Cardinal): PCol;
|
||||
@ -442,11 +459,13 @@ type
|
||||
procedure WriteRowHeight(ARow: Cardinal; AHeight: Single);
|
||||
procedure WriteColInfo(ACol: Cardinal; AData: TCol);
|
||||
procedure WriteColWidth(ACol: Cardinal; AWidth: Single);
|
||||
|
||||
{ Properties }
|
||||
property Cells: TAVLTree read FCells;
|
||||
property Cols: TIndexedAVLTree read FCols;
|
||||
property Rows: TIndexedAVLTree read FRows;
|
||||
property Workbook: TsWorkbook read FWorkbook;
|
||||
|
||||
// These are properties to interface to fpspreadsheetgrid.
|
||||
property Options: TsSheetOptions read FOptions write FOptions;
|
||||
property LeftPaneWidth: Integer read FLeftPaneWidth write FLeftPaneWidth;
|
||||
@ -547,7 +566,7 @@ type
|
||||
var ACurrencySymbol: String); virtual;
|
||||
procedure RemoveFormat(AIndex: Integer);
|
||||
public
|
||||
constructor Create;
|
||||
constructor Create(AWorkbook: TsWorkbook);
|
||||
destructor Destroy; override;
|
||||
function AddFormat(AFormatCell: PCell): Integer; overload;
|
||||
function AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
|
||||
@ -718,7 +737,7 @@ procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
||||
implementation
|
||||
|
||||
uses
|
||||
Math, StrUtils, fpsutils;
|
||||
Math, StrUtils, fpsUtils, fpsNumFormatParser;
|
||||
|
||||
{ Translatable strings }
|
||||
resourcestring
|
||||
@ -727,6 +746,9 @@ resourcestring
|
||||
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
|
||||
lpUnknownSpreadsheetFormat = 'unknown format';
|
||||
lpInvalidFontIndex = 'Invalid font index';
|
||||
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
||||
lpNoValidNumberFormatString = 'No valid number format string.';
|
||||
lpNoValidDateTimeFormatString = 'No valid date/time format string.';
|
||||
lpTRUE = 'TRUE';
|
||||
lpFALSE = 'FALSE';
|
||||
lpErrEmptyIntersection = '#NULL!';
|
||||
@ -1407,14 +1429,19 @@ begin
|
||||
ACell^.ContentType := cctNumber;
|
||||
ACell^.NumberValue := ANumber;
|
||||
ACell^.Decimals := ADecimals;
|
||||
|
||||
if IsDateTimeFormat(AFormat) then
|
||||
raise Exception.Create(lpInvalidNumberFormat);
|
||||
|
||||
if AFormat <> nfGeneral then begin
|
||||
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||
ACell^.NumberFormat := AFormat;
|
||||
ACell^.Decimals := ADecimals;
|
||||
ACell^.CurrencySymbol := ACurrencySymbol;
|
||||
ACell^.NumberFormatStr := BuildNumFormatString(ACell^.NumberFormat,
|
||||
ACell^.NumberFormatStr := BuildNumberFormatString(ACell^.NumberFormat,
|
||||
Workbook.FormatSettings, ADecimals, ACurrencySymbol);
|
||||
end;
|
||||
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
@ -1427,13 +1454,32 @@ procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: Double;
|
||||
AFormatString: String);
|
||||
var
|
||||
ACell: PCell;
|
||||
parser: TsNumFormatParser;
|
||||
nf: TsNumberFormat;
|
||||
begin
|
||||
parser := TsNumFormatParser.Create(Workbook, AFormatString, cdToFPSpreadsheet);
|
||||
try
|
||||
// Format string ok?
|
||||
if parser.Status <> psOK then
|
||||
raise Exception.Create(lpNoValidNumberFormatString);
|
||||
if IsDateTimeFormat(parser.Builtin_NumFormat)
|
||||
then raise Exception.Create(lpInvalidNumberFormat);
|
||||
// If format string matches a built-in format use its format identifier,
|
||||
// All this is considered when calling Builtin_NumFormat of the parser.
|
||||
nf := parser.Builtin_NumFormat;
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
|
||||
ACell := GetCell(ARow, ACol);
|
||||
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||
ACell^.ContentType := cctNumber;
|
||||
ACell^.NumberValue := ANumber;
|
||||
ACell^.NumberFormat := nfCustom;
|
||||
ACell^.NumberFormat := nf;
|
||||
ACell^.NumberFormatStr := AFormatString;
|
||||
ACell^.Decimals := 0;
|
||||
ACell^.CurrencySymbol := '';
|
||||
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
@ -1482,6 +1528,7 @@ end;
|
||||
Must follow the rules for "FormatDateTime", or use
|
||||
"dm" as abbreviation for "d/mmm", "my" for "mmm/yy",
|
||||
"ms" for "nn:ss", "msz" for "nn:ss.z" (optional)
|
||||
or use any other free format (at your own risk...)
|
||||
|
||||
Note: at least Excel xls does not recognize a separate datetime cell type:
|
||||
a datetime is stored as a (floating point) Number, and the cell is formatted
|
||||
@ -1494,9 +1541,25 @@ procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||
var
|
||||
ACell: PCell;
|
||||
fmt: String;
|
||||
parser: TsNumFormatParser;
|
||||
begin
|
||||
ACell := GetCell(ARow, ACol);
|
||||
if AFormat = nfFmtDateTime then begin
|
||||
AFormatStr := BuildDateTimeFormatString(AFormat, Workbook.FormatSettings, AFormatStr);
|
||||
parser := TsNumFormatParser.Create(Workbook, AFormatStr, cdToFPSpreadsheet);
|
||||
try
|
||||
// Check that the format string can be reckognized.
|
||||
if parser.Status <> psOK then
|
||||
raise Exception.Create(lpNoValidNumberFormatString);
|
||||
// Check that the format string belongs to date/time values
|
||||
if not (IsDateTimeFormat(parser.Builtin_NumFormat) or (parser.Builtin_NumFormat = nfFmtDateTime))
|
||||
then raise Exception.Create(lpNoValidDateTimeFormatString);
|
||||
AFormatStr := parser.FormatString;
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
ACell := GetCell(ARow, ACol);
|
||||
ACell^.ContentType := cctDateTime;
|
||||
ACell^.DateTimeValue := AValue;
|
||||
// Date/time is actually a number field in Excel.
|
||||
@ -1504,34 +1567,8 @@ begin
|
||||
// The user can choose another date format if he wants to
|
||||
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||
ACell^.NumberFormat := AFormat;
|
||||
case AFormat of
|
||||
nfShortDateTime:
|
||||
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
|
||||
nfShortDate:
|
||||
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat;
|
||||
nfLongDate:
|
||||
ACell^.NumberFormatStr := 'dd/mmm/yyyy';
|
||||
nfShortTime:
|
||||
ACell^.NumberFormatStr := 't';
|
||||
nfLongTime:
|
||||
ACell^.NumberFormatStr := 'tt';
|
||||
nfShortTimeAM:
|
||||
ACell^.NumberFormatStr := 'hh:nn AM/PM';
|
||||
nfLongTimeAM:
|
||||
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 := 'nn:ss'
|
||||
else if fmt = 'msz' then ACell^.NumberFormatStr := 'nn:ss.z'
|
||||
else ACell^.NumberFormatStr := AFormatStr;
|
||||
end;
|
||||
nfTimeInterval:
|
||||
if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:nn:ss'
|
||||
else ACell^.NumberFormatStr := AFormatStr;
|
||||
end;
|
||||
ACell^.NumberFormatStr := AFormatStr;
|
||||
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
@ -1544,7 +1581,7 @@ procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte);
|
||||
begin
|
||||
if (ACell <> nil) and (ACell^.ContentType = cctNumber) then begin
|
||||
ACell^.Decimals := ADecimals;
|
||||
ACell^.NumberFormatStr := BuildNumFormatString(ACell^.NumberFormat,
|
||||
ACell^.NumberFormatStr := BuildNumberFormatString(ACell^.NumberFormat,
|
||||
FWorkbook.FormatSettings, ADecimals, ACell^.CurrencySymbol);
|
||||
ChangedCell(ACell^.Row, ACell^.Col);
|
||||
end;
|
||||
@ -1603,7 +1640,7 @@ begin
|
||||
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||
ACell^.NumberFormat := ANumberFormat;
|
||||
if (AFormatString = '') then
|
||||
ACell^.NumberFormatStr := BuildNumFormatString(ANumberFormat,
|
||||
ACell^.NumberFormatStr := BuildNumberFormatString(ANumberFormat,
|
||||
Workbook.FormatSettings, ACell^.Decimals, ACell^.CurrencySymbol)
|
||||
else
|
||||
ACell^.NumberFormatStr := AFormatString;
|
||||
@ -2577,9 +2614,10 @@ end;
|
||||
|
||||
{ TsCustomNumFormatList }
|
||||
|
||||
constructor TsCustomNumFormatList.Create;
|
||||
constructor TsCustomNumFormatList.Create(AWorkbook: TsWorkbook);
|
||||
begin
|
||||
inherited Create;
|
||||
FWorkbook := AWorkbook;
|
||||
AddBuiltinFormats;
|
||||
end;
|
||||
|
||||
@ -2599,6 +2637,13 @@ begin
|
||||
item := TsNumFormatData.Create;
|
||||
item.Index := AFormatIndex;
|
||||
item.NumFormat := ANumFormat;
|
||||
if IsDateTimeFormat(ANumFormat) then
|
||||
AFormatString := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings,
|
||||
AFormatString)
|
||||
else
|
||||
if item.NumFormat <> nfCustom then
|
||||
AFormatString := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings,
|
||||
ADecimals, ACurrencySymbol);
|
||||
item.FormatString := AFormatString;
|
||||
item.Decimals := ADecimals;
|
||||
item.CurrencySymbol := ACurrencySymbol;
|
||||
@ -2644,6 +2689,38 @@ end;
|
||||
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: Byte; var ACurrencySymbol: String);
|
||||
var
|
||||
parser: TsNumFormatParser;
|
||||
fmt: String;
|
||||
lFormatData: TsNumFormatData;
|
||||
i: Integer;
|
||||
begin
|
||||
i := Find(AFormatIndex);
|
||||
if i > 0 then begin
|
||||
lFormatData := Items[i];
|
||||
fmt := lFormatData.FormatString;
|
||||
end else
|
||||
fmt := AFormatString;
|
||||
|
||||
parser := TsNumFormatParser.Create(Workbook, fmt, cdToFPSpreadsheet);
|
||||
try
|
||||
if parser.Status = psOK then begin
|
||||
ANumFormat := parser.Builtin_NumFormat;
|
||||
AFormatString := parser.FormatString;
|
||||
if not (parser.Builtin_NumFormat in [nfCustom, nfFmtDateTime]) then begin
|
||||
ADecimals := parser.ParsedSections[0].Decimals;
|
||||
ACurrencySymbol := parser.ParsedSections[0].CurrencySymbol;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
(*
|
||||
procedure TsCustomNumFormatList.Analyze(AFormatIndex: Integer;
|
||||
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
||||
var ADecimals: Byte; var ACurrencySymbol: String);
|
||||
@ -2749,6 +2826,7 @@ begin
|
||||
ANumFormat := nfCustom;
|
||||
end;
|
||||
end;
|
||||
*)
|
||||
|
||||
{ Called from the reader when a format item has been read from the file.
|
||||
Determines the numFormat type, format string etc and stores the format in the
|
||||
@ -2816,8 +2894,8 @@ begin
|
||||
item := Items[Result];
|
||||
if (item <> nil) and (item.NumFormat = ANumFormat) then
|
||||
exit;
|
||||
end
|
||||
else
|
||||
end;
|
||||
|
||||
if (ANumFormat = nfFmtDateTime) then begin
|
||||
fmt := lowercase(AFormatString);
|
||||
for Result := 0 to Count-1 do begin
|
||||
@ -2847,9 +2925,10 @@ begin
|
||||
if fmt = lowercase(item.FormatString) then
|
||||
exit;
|
||||
end;
|
||||
end else
|
||||
end;
|
||||
|
||||
// Check only the format string for nfCustom.
|
||||
if (ANumFormat = nfCustom) then begin
|
||||
if (ANumFormat = nfCustom) then
|
||||
for Result := 0 to Count-1 do begin
|
||||
item := Items[Result];
|
||||
if (item <> nil)
|
||||
@ -2858,7 +2937,7 @@ begin
|
||||
then
|
||||
exit;
|
||||
end;
|
||||
end else
|
||||
|
||||
// The other formats can carry additional information
|
||||
for Result := 0 to Count-1 do begin
|
||||
item := Items[Result];
|
||||
@ -3099,7 +3178,8 @@ var
|
||||
decs: Byte;
|
||||
begin
|
||||
if ACell^.NumberFormat = nfFmtDateTime then begin
|
||||
if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
|
||||
decs := CountDecs(ACell^.NumberFormatStr, ['0', 'z', 'Z']);
|
||||
// if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
|
||||
ACell^.Decimals := decs;
|
||||
end;
|
||||
end;
|
||||
|
@ -17,6 +17,7 @@ uses
|
||||
// Exported types
|
||||
type
|
||||
TsSelectionDirection = (fpsVerticalSelection, fpsHorizontalSelection);
|
||||
TsDecsChars = set of char;
|
||||
|
||||
const
|
||||
// Date formatting string for unambiguous date/time display as strings
|
||||
@ -60,19 +61,29 @@ function UTF8TextToXMLText(AText: ansistring): ansistring;
|
||||
function TwipsToMillimeters(AValue: Integer): Single;
|
||||
function MillimetersToTwips(AValue: Single): Integer;
|
||||
|
||||
function IfThen(ACondition: Boolean; AValue1,AValue2: TsNumberFormat): TsNumberFormat; overload;
|
||||
|
||||
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
||||
(*
|
||||
function IsCurrencyFormat(s: String; out Decimals: Byte; out CurrSymbol: String;
|
||||
out IsCurrencyRedFmt, IsCurrencyDashFmt: Boolean): Boolean;
|
||||
function IsExpNumberFormat(s: String; out Decimals: Byte; out IsSci: Boolean): Boolean;
|
||||
function IsFixedNumberFormat(s: String; out Decimals: Byte): Boolean;
|
||||
function IsPercentNumberFormat(s: String; out Decimals: Byte): Boolean;
|
||||
function IsThousandSepNumberFormat(s: String; out Decimals: Byte): Boolean;
|
||||
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
|
||||
function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
|
||||
out SecDecimals: Byte): Boolean;
|
||||
|
||||
function BuildNumFormatString(ANumberFormat: TsNumberFormat;
|
||||
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
|
||||
{function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
|
||||
out SecDecimals: Byte): Boolean;
|
||||
*)
|
||||
|
||||
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
||||
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
||||
ACurrencySymbol: String = '?'): String;
|
||||
function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat;
|
||||
const AFormatSettings: TFormatSettings; AFormatString: String = ''): String;
|
||||
function StripAMPM(const ATimeFormatString: String): String;
|
||||
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
||||
|
||||
function SciFloat(AValue: Double; ADecimals: Byte): String;
|
||||
//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
|
||||
@ -494,8 +505,21 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{ Returns either AValue1 or AValue2, depending on the condition.
|
||||
For reduciton of typing... }
|
||||
function IfThen(ACondition: Boolean; AValue1, AValue2: TsNumberFormat): TsNumberFormat;
|
||||
begin
|
||||
if ACondition then Result := AValue1 else Result := AValue2;
|
||||
end;
|
||||
|
||||
{ Format checking procedures }
|
||||
|
||||
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
||||
begin
|
||||
Result := AFormat in [nfFmtDateTime, nfShortDateTime, nfShortDate, nfLongDate,
|
||||
nfShortTime. nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval];
|
||||
end;
|
||||
(*
|
||||
{ This simple parsing procedure of the Excel format string checks for a fixed
|
||||
float format s, i.e. s can be '0', '0.00', '000', '0,000', and returns the
|
||||
number of decimals, i.e. number of zeros behind the decimal point }
|
||||
@ -661,7 +685,7 @@ begin
|
||||
if ph > 0 then IsSci := true;
|
||||
end;
|
||||
end;
|
||||
|
||||
*)
|
||||
{ IsDateFormat checks if the format string s corresponds to a date format }
|
||||
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
|
||||
begin
|
||||
@ -744,9 +768,58 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Builds a number format string from the numberformat code and the count of
|
||||
decimals. }
|
||||
function BuildNumFormatString(ANumberFormat: TsNumberFormat;
|
||||
{ Builds a date/time format string from the numberformat code. If the format code
|
||||
is nfFmtDateTime the given AFormatString is used. AFormatString can use the
|
||||
abbreviations "dm" (for "d/mmm"), "my" (for "mmm/yy"), "ms" (for "mm:ss")
|
||||
and "msz" (for "mm:ss.z"). }
|
||||
function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat;
|
||||
const AFormatSettings: TFormatSettings; AFormatString: String = '') : string;
|
||||
var
|
||||
fmt: String;
|
||||
begin
|
||||
case ANumberFormat of
|
||||
nfFmtDateTime:
|
||||
begin
|
||||
fmt := lowercase(AFormatString);
|
||||
if (fmt = 'dm') then Result := 'd/mmm'
|
||||
else if (fmt = 'my') then Result := 'mmm/yy'
|
||||
else if (fmt = 'ms') then Result := 'nn:ss'
|
||||
else if (fmt = 'msz') then Result := 'nn:ss.z'
|
||||
else Result := AFormatString;
|
||||
end;
|
||||
nfShortDateTime:
|
||||
Result := AFormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
|
||||
nfShortDate:
|
||||
Result := AFormatSettings.ShortDateFormat;
|
||||
nfLongDate:
|
||||
Result := AFormatSettings.LongDateFormat;
|
||||
nfShortTime:
|
||||
Result := StripAMPM(AFormatSettings.ShortTimeFormat);
|
||||
nfLongTime:
|
||||
Result := StripAMPM(AFormatSettings.LongTimeFormat);
|
||||
nfShortTimeAM:
|
||||
begin
|
||||
Result := AFormatSettings.ShortTimeFormat;
|
||||
if pos('a', lowercase(AFormatSettings.ShortTimeFormat)) = 0 then
|
||||
Result := Format('%s %s/%s', [Result, AFormatSettings.TimeAMString, AFormatSettings.TimePMString]);
|
||||
end;
|
||||
nfLongTimeAM:
|
||||
begin
|
||||
Result := AFormatSettings.LongTimeFormat;
|
||||
if pos('a', lowercase(AFormatSettings.LongTimeFormat)) = 0 then
|
||||
Result := Format('%s %s/%s', [Result, AFormatSettings.TimeAMString, AFormatSettings.TimePMString]);
|
||||
end;
|
||||
nfTimeInterval:
|
||||
if AFormatString = '' then
|
||||
Result := '[h]:mm:ss'
|
||||
else
|
||||
Result := AFormatString;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Builds a number format string from the numberformat code, the count of
|
||||
decimals, and the currencysymbol (if not empty). }
|
||||
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
||||
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
||||
ACurrencySymbol: String = '?'): String;
|
||||
const
|
||||
@ -778,6 +851,7 @@ var
|
||||
decs: String;
|
||||
cf, ncf: Byte;
|
||||
begin
|
||||
Result := '';
|
||||
cf := AFormatSettings.CurrencyFormat;
|
||||
ncf := AFormatSettings.NegCurrFormat;
|
||||
if ADecimals = -1 then ADecimals := AFormatSettings.CurrencyDecimals;
|
||||
@ -824,6 +898,37 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function StripAMPM(const ATimeFormatString: String): String;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
i := 1;
|
||||
while i <= Length(ATimeFormatString) do begin
|
||||
if ATimeFormatString[i] in ['a', 'A'] then begin
|
||||
inc(i);
|
||||
while (i <= Length(ATimeFormatString)) and (ATimeFormatString[i] in ['p', 'P', 'm', 'M', '/']) do
|
||||
inc(i);
|
||||
end else
|
||||
Result := Result + ATimeFormatString[i];
|
||||
inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
for i:=Length(AFormatString) downto 1 do begin
|
||||
if AFormatString[i] in ADecChars then inc(Result);
|
||||
if AFormatString[i] = '.' then exit;
|
||||
end;
|
||||
// Comes to this point when there is no decimal separtor.
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
|
||||
{ Formats the number AValue in "scientific" format with the given number of
|
||||
decimals. "Scientific" is the same as "exponential", but with exponents rounded
|
||||
to multiples of 3 (like for "kilo" - "Mega" - "Giga" etc.). }
|
||||
|
@ -352,7 +352,7 @@ end;
|
||||
procedure TsWikiTableWriter.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsWikiTableNumFormatList.Create;
|
||||
FNumFormatList := TsWikiTableNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
procedure TsWikiTableWriter.WriteToStrings(AStrings: TStrings);
|
||||
|
@ -43,7 +43,7 @@ type
|
||||
protected
|
||||
procedure AddBuiltinFormats; override;
|
||||
public
|
||||
constructor Create;
|
||||
constructor Create(AWorkbook: TsWorkbook);
|
||||
function FormatStringForWriting(AIndex: Integer): String; override;
|
||||
end;
|
||||
|
||||
@ -166,9 +166,9 @@ const
|
||||
|
||||
{ TsBIFF2NumFormatList }
|
||||
|
||||
constructor TsBIFF2NumFormatList.Create;
|
||||
constructor TsBIFF2NumFormatList.Create(AWorkbook: TsWorkbook);
|
||||
begin
|
||||
inherited Create;
|
||||
inherited Create(AWorkbook);
|
||||
end;
|
||||
|
||||
procedure TsBIFF2NumFormatList.AddBuiltinFormats;
|
||||
@ -283,7 +283,7 @@ end;
|
||||
procedure TsSpreadBIFF2Reader.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsBIFF2NumFormatList.Create;
|
||||
FNumFormatList := TsBIFF2NumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
{ Extracts the number format data from an XF record indexed by AXFIndex.
|
||||
@ -701,7 +701,7 @@ end;
|
||||
procedure TsSpreadBIFF2Writer.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsBIFF2NumFormatList.Create;
|
||||
FNumFormatList := TsBIFF2NumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
function TsSpreadBIFF2Writer.FindXFIndex(ACell: PCell): Word;
|
||||
|
@ -593,13 +593,15 @@ procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
|
||||
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
||||
var ADecimals: Byte; var ACurrencySymbol: String);
|
||||
var
|
||||
parser: TsNumFormatParser;
|
||||
fmt: String;
|
||||
{
|
||||
parser: TsNumFormatParser;
|
||||
sections: TsNumFormatSections;
|
||||
}
|
||||
begin
|
||||
|
||||
{
|
||||
AFormatString := 'hh:mm AM/PM'; //"€" #,##.0;[red]"$" -#,##.000;-';
|
||||
|
||||
(*
|
||||
AFormatString := 'hh:mm:ss.0 AM/PM'; //"€" #,##.0;[red]"$" -#,##.000;-';
|
||||
|
||||
parser := TsNumFormatParser.Create(Workbook, AFormatString);
|
||||
try
|
||||
@ -607,10 +609,18 @@ begin
|
||||
ANumFormat := parser.ParsedSections[0].NumFormat;
|
||||
ADecimals := parser.ParsedSections[0].Decimals;
|
||||
ACurrencySymbol := parser.ParsedSections[0].CurrencySymbol;
|
||||
parser.CopySectionsTo(sections);
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
}
|
||||
|
||||
parser := TsNumFormatParser.Create(Workbook, sections);
|
||||
try
|
||||
fmt := parser.FormatString;
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
*)
|
||||
|
||||
fmt := Lowercase(AFormatString);
|
||||
{ Check the built-in formats first:
|
||||
@ -660,6 +670,18 @@ function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
||||
var
|
||||
item: TsNumFormatData;
|
||||
i: Integer;
|
||||
|
||||
procedure FixN(var s: String);
|
||||
// The minutes in short time formats are coded by "n" in fpc, but Excel wants "m".
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=1 to Length(s) do
|
||||
case s[i] of
|
||||
'n', 'N': s[i] := 'm'; // no "M" which will be interpreted as "Month"
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := inherited FormatStringForWriting(AIndex);
|
||||
item := Items[AIndex];
|
||||
@ -670,15 +692,19 @@ begin
|
||||
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;
|
||||
FixN(Result);
|
||||
end;
|
||||
nfTimeInterval:
|
||||
// Time interval format string could still be without square brackets
|
||||
// if added by user.
|
||||
// We check here for safety and add the brackets if not there.
|
||||
MakeTimeIntervalMask(item.FormatString, Result);
|
||||
begin
|
||||
// Time interval format string could still be without square brackets
|
||||
// if added by user.
|
||||
// We check here for safety and add the brackets if not there.
|
||||
MakeTimeIntervalMask(item.FormatString, Result);
|
||||
FixN(Result);
|
||||
end;
|
||||
nfShortTime, nfShortTimeAM, nfLongTime, nfLongTimeAM:
|
||||
FixN(Result);
|
||||
nfCurrencyRed, nfCurrencyDashRed:
|
||||
begin
|
||||
i := Pos(';', item.FormatString);
|
||||
@ -765,7 +791,7 @@ end;
|
||||
procedure TsSpreadBIFFReader.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsBIFFNumFormatList.Create;
|
||||
FNumFormatList := TsBIFFNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
{ Extracts a number out of an RK value.
|
||||
@ -812,9 +838,11 @@ procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
|
||||
decs: Byte;
|
||||
i: Integer;
|
||||
begin
|
||||
if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
|
||||
decs := CountDecs(ANumberFormatStr, ['0', 'z', 'Z']);
|
||||
{ if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
|
||||
and (decs > 0)
|
||||
then
|
||||
then }
|
||||
if decs > 0 then
|
||||
for i:= Length(ANumberFormatStr) downto 1 do
|
||||
case ANumberFormatStr[i] of
|
||||
'0': ANumberFormatStr[i] := 'z';
|
||||
@ -1361,7 +1389,7 @@ end;
|
||||
procedure TsSpreadBIFFWriter.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsBIFFNumFormatList.Create;
|
||||
FNumFormatList := TsBIFFNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
|
||||
@ -1679,19 +1707,16 @@ end;
|
||||
procedure TsSpreadBIFFWriter.WriteFormats(AStream: TStream);
|
||||
var
|
||||
i: Integer;
|
||||
|
||||
item: TsNumFormatData;
|
||||
|
||||
begin
|
||||
ListAllNumFormats;
|
||||
|
||||
item := NumFormatList[20];
|
||||
|
||||
i := NumFormatList.Find(NumFormatList.FirstFormatIndexInFile);
|
||||
if i > -1 then
|
||||
while i < NumFormatList.Count do begin
|
||||
if NumFormatList[i] <> nil then
|
||||
WriteFormat(AStream, NumFormatList[i], i);
|
||||
item := NumFormatList[i];
|
||||
if item <> nil then begin
|
||||
WriteFormat(AStream, item, i);
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
end;
|
||||
|
@ -393,7 +393,7 @@ end;
|
||||
procedure TsSpreadOOXMLWriter.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsOOXMLNumFormatList.Create;
|
||||
FNumFormatList := TsOOXMLNumFormatList.Create(Workbook);
|
||||
end;
|
||||
|
||||
{
|
||||
|
Reference in New Issue
Block a user