You've already forked lazarus-ccr
fpspreadsheet: More logical writing strategy for biff number formats. Still issues with reading.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3072 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -54,7 +54,7 @@ begin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write some cells
|
// Write some cells
|
||||||
MyWorksheet.WriteDateTime(0, 20, now, nfShortTime); //1.0);// A1
|
// MyWorksheet.WriteDateTime(0, 20, now, nfShortTime); //1.0);// A1
|
||||||
MyWorksheet.WriteNumber(0, 0, 1.0, nfFixed, 3);// A1
|
MyWorksheet.WriteNumber(0, 0, 1.0, nfFixed, 3);// A1
|
||||||
MyWorksheet.WriteNumber(0, 1, 2.0);// B1
|
MyWorksheet.WriteNumber(0, 1, 2.0);// B1
|
||||||
MyWorksheet.WriteNumber(0, 2, 3.0);// C1
|
MyWorksheet.WriteNumber(0, 2, 3.0);// C1
|
||||||
@ -209,11 +209,9 @@ begin
|
|||||||
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
|
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
|
||||||
|
|
||||||
// Write formatted numbers
|
// Write formatted numbers
|
||||||
number := 12345.67890123456789;
|
// number := 12345.67890123456789;
|
||||||
|
number := 31415.92;
|
||||||
inc(r, 2);
|
inc(r, 2);
|
||||||
MyWorksheet.WriteUTF8Text(r, 1, '12345.67890123456789');
|
|
||||||
MyWorksheet.WriteUTF8Text(r, 2, '-12345.67890123456789');
|
|
||||||
inc(r);
|
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
|
||||||
MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
|
MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
|
||||||
MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
|
MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
|
||||||
@ -250,6 +248,12 @@ begin
|
|||||||
MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
|
MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
|
||||||
MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
|
MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
|
||||||
inc(r,2);
|
inc(r,2);
|
||||||
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 0 dec');
|
||||||
|
MyWorksheet.WriteNumber(r, 1, number, nfSci, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 0);
|
||||||
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
|
||||||
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
|
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
|
||||||
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
|
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
|
||||||
@ -268,6 +272,12 @@ begin
|
|||||||
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
|
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
|
||||||
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
|
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
|
||||||
inc(r);
|
inc(r);
|
||||||
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 0 dec');
|
||||||
|
MyWorksheet.WriteNumber(r, 1, number, nfExp, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 0);
|
||||||
|
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 0);
|
||||||
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
|
||||||
MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
|
MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
|
||||||
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
|
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
|
||||||
@ -285,7 +295,6 @@ begin
|
|||||||
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
|
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
|
||||||
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
|
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
|
||||||
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
|
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
|
||||||
|
|
||||||
inc(r,2);
|
inc(r,2);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
|
||||||
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, 'USD');
|
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, 'USD');
|
||||||
@ -319,6 +328,7 @@ begin
|
|||||||
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
|
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
|
||||||
MyWorksheet.WriteDateTime(r, 2, -number);
|
MyWorksheet.WriteDateTime(r, 2, -number);
|
||||||
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
|
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
|
||||||
|
|
||||||
inc(r, 2);
|
inc(r, 2);
|
||||||
number := 1.333333333;
|
number := 1.333333333;
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
|
||||||
@ -337,14 +347,23 @@ begin
|
|||||||
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
|
||||||
inc(r);
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
|
||||||
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m:s');
|
||||||
|
inc(r);
|
||||||
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:n:s');
|
||||||
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:n:s');
|
||||||
inc(r);
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
|
||||||
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
|
||||||
inc(r);
|
inc(r);
|
||||||
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:nn');
|
||||||
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:nn');
|
||||||
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
|
||||||
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
|
||||||
inc(r);
|
inc(r);
|
||||||
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:n');
|
||||||
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:n');
|
||||||
|
inc(r);
|
||||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
|
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
|
||||||
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
|
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
|
||||||
|
|
||||||
@ -360,7 +379,7 @@ begin
|
|||||||
|
|
||||||
// Set height of rows 0
|
// Set height of rows 0
|
||||||
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
|
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
|
||||||
|
(*
|
||||||
// Creates a new worksheet
|
// Creates a new worksheet
|
||||||
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet2);
|
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet2);
|
||||||
|
|
||||||
@ -371,7 +390,7 @@ begin
|
|||||||
MyWorksheet.WriteUTF8Text(0, 3, Str_Fourth);
|
MyWorksheet.WriteUTF8Text(0, 3, Str_Fourth);
|
||||||
MyWorksheet.WriteTextRotation(0, 0, rt90DegreeClockwiseRotation);
|
MyWorksheet.WriteTextRotation(0, 0, rt90DegreeClockwiseRotation);
|
||||||
MyWorksheet.WriteUsedFormatting(0, 1, [uffBold]);
|
MyWorksheet.WriteUsedFormatting(0, 1, [uffBold]);
|
||||||
|
*)
|
||||||
// Save the spreadsheet to a file
|
// Save the spreadsheet to a file
|
||||||
MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8, true);
|
MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8, true);
|
||||||
MyWorkbook.Free;
|
MyWorkbook.Free;
|
||||||
|
@ -55,6 +55,7 @@ type
|
|||||||
FFormatString: String;
|
FFormatString: String;
|
||||||
FNumFormat: TsNumberFormat;
|
FNumFormat: TsNumberFormat;
|
||||||
FConversionDirection: TsConversionDirection;
|
FConversionDirection: TsConversionDirection;
|
||||||
|
FIsTime: Boolean;
|
||||||
FStatus: Integer;
|
FStatus: Integer;
|
||||||
function GetFormatString: String;
|
function GetFormatString: String;
|
||||||
function GetParsedSectionCount: Integer;
|
function GetParsedSectionCount: Integer;
|
||||||
@ -78,7 +79,8 @@ type
|
|||||||
procedure ScanText;
|
procedure ScanText;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook; const AFormatString: String;
|
constructor Create(AWorkbook: TsWorkbook;
|
||||||
|
const AFormatString: String; ANumFormat: TsNumberFormat;
|
||||||
AConversionDirection: TsConversionDirection = cdToFPSpreadsheet); overload;
|
AConversionDirection: TsConversionDirection = cdToFPSpreadsheet); overload;
|
||||||
constructor Create(AWorkbook: TsWorkbook; const AFormatSections: TsNumFormatSections;
|
constructor Create(AWorkbook: TsWorkbook; const AFormatSections: TsNumFormatSections;
|
||||||
AConversionDirection: TsConversionDirection = cdFromFPSpreadsheet); overload;
|
AConversionDirection: TsConversionDirection = cdFromFPSpreadsheet); overload;
|
||||||
@ -96,7 +98,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
fpsutils;
|
StrUtils, fpsutils;
|
||||||
|
|
||||||
const
|
const
|
||||||
COMPARE_STR: array[TsCompareOperation] of string = (
|
COMPARE_STR: array[TsCompareOperation] of string = (
|
||||||
@ -109,12 +111,14 @@ const
|
|||||||
from a spreadsheet file. The conversion, by default, will go FROM the file TO
|
from a spreadsheet file. The conversion, by default, will go FROM the file TO
|
||||||
the fpspreadsheet procedures. }
|
the fpspreadsheet procedures. }
|
||||||
constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook;
|
constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook;
|
||||||
const AFormatString: String; AConversionDirection: TsConversionDirection = cdToFPSpreadsheet);
|
const AFormatString: String; ANumFormat: TsNumberFormat;
|
||||||
|
AConversionDirection: TsConversionDirection = cdToFPSpreadsheet);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FCreateMethod := 0;
|
FCreateMethod := 0;
|
||||||
FConversionDirection := AConversionDirection;
|
FConversionDirection := AConversionDirection;
|
||||||
FWorkbook := AWorkbook;
|
FWorkbook := AWorkbook;
|
||||||
|
FNumFormat := ANumFormat;
|
||||||
FFormatSettings := DefaultFormatSettings;
|
FFormatSettings := DefaultFormatSettings;
|
||||||
FFormatSettings.DecimalSeparator := '.';
|
FFormatSettings.DecimalSeparator := '.';
|
||||||
FFormatSettings.ThousandSeparator := ',';
|
FFormatSettings.ThousandSeparator := ',';
|
||||||
@ -163,6 +167,7 @@ begin
|
|||||||
Decimals := 0;
|
Decimals := 0;
|
||||||
NumFormat := nfGeneral;
|
NumFormat := nfGeneral;
|
||||||
end;
|
end;
|
||||||
|
FIsTime := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsNumFormatParser.AnalyzeBracket(const AValue: String);
|
procedure TsNumFormatParser.AnalyzeBracket(const AValue: String);
|
||||||
@ -171,6 +176,23 @@ var
|
|||||||
n: Integer;
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
lValue := lowercase(AValue);
|
lValue := lowercase(AValue);
|
||||||
|
// date/time format for interval
|
||||||
|
if (lValue = 'h') or (lValue = 'hh') or (lValue = 'm') or (lValue = 'mm') or
|
||||||
|
(lValue = 's') or (lValue = 'ss') or (lValue = 'n') or (lValue = 'nn')
|
||||||
|
then begin
|
||||||
|
FSections[FCurrSection].FormatString := FSections[FCurrSection].FormatString +
|
||||||
|
'[' + AValue + ']';
|
||||||
|
FSections[FCurrSection].NumFormat := nfTimeInterval;
|
||||||
|
FIsTime := true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if ((lValue = 'n') or (lValue = 'nn')) and (FConversionDirection = cdFromFPSpreadsheet)
|
||||||
|
then begin
|
||||||
|
FSections[FCurrSection].FormatString := FSections[FCurrSection].FormatString +
|
||||||
|
'[' + DupeString('m', Length(lValue)) + ']';
|
||||||
|
FIsTime := true;
|
||||||
|
end
|
||||||
|
else
|
||||||
// Colors
|
// Colors
|
||||||
if lValue = 'red' then
|
if lValue = 'red' then
|
||||||
FSections[FCurrSection].Color := scRed
|
FSections[FCurrSection].Color := scRed
|
||||||
@ -251,7 +273,7 @@ begin
|
|||||||
if FSections[i].FormatString = '' then
|
if FSections[i].FormatString = '' then
|
||||||
FSections[i].NumFormat := nfGeneral;
|
FSections[i].NumFormat := nfGeneral;
|
||||||
|
|
||||||
if (FSections[i].CurrencySymbol <> '') and (FSections[i].NumFormat = nfFixedTh) then
|
if (FSections[i].CurrencySymbol <> '') {and (FSections[i].NumFormat in [nfFixed, nfFixedTh])} then
|
||||||
FSections[i].NumFormat := nfCurrency;
|
FSections[i].NumFormat := nfCurrency;
|
||||||
|
|
||||||
if FSections[i].CompareOperation <> coNotUsed then begin
|
if FSections[i].CompareOperation <> coNotUsed then begin
|
||||||
@ -270,7 +292,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
nfShortDateTime, nfShortDate, nfShortTime, nfShortTimeAM,
|
nfShortDateTime, nfShortDate, nfShortTime, nfShortTimeAM,
|
||||||
nfLongDate, nfLongTime, nfLongTimeAM, nfFmtDateTime:
|
nfLongDate, nfLongTime, nfLongTimeAM, nfTimeInterval, nfFmtDateTime:
|
||||||
try
|
try
|
||||||
s := FormatDateTimeEx(FSections[i].FormatString, now(), FWorkbook.FormatSettings);
|
s := FormatDateTimeEx(FSections[i].FormatString, now(), FWorkbook.FormatSettings);
|
||||||
except
|
except
|
||||||
@ -280,6 +302,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (ns > 1) and (FNumFormat in [nfCurrencyRed, nfCurrencyDashRed]) then
|
||||||
|
FSections[1].Color := scRed;
|
||||||
|
|
||||||
// Extract built-in NumFormat identifier for currency (needs several entries in
|
// Extract built-in NumFormat identifier for currency (needs several entries in
|
||||||
// three sections).
|
// three sections).
|
||||||
if (ns = 3) and
|
if (ns = 3) and
|
||||||
@ -303,6 +328,22 @@ begin
|
|||||||
else
|
else
|
||||||
FNumFormat := FSections[0].NumFormat;
|
FNumFormat := FSections[0].NumFormat;
|
||||||
|
|
||||||
|
// Add colors to section format strings
|
||||||
|
if (FConversionDirection = cdFromFPSpreadsheet) then
|
||||||
|
for i := 0 to High(FSections) do
|
||||||
|
if FSections[i].Color < 8 then
|
||||||
|
FSections[i].FormatString := Format('[%s]%s', [
|
||||||
|
FWorkbook.GetColorName(FSections[i].Color),
|
||||||
|
FSections[i].FormatString
|
||||||
|
])
|
||||||
|
else
|
||||||
|
if FSections[i].Color <> scNotDefined then
|
||||||
|
FSections[i].FormatString := Format('[Color%d]%s', [
|
||||||
|
FSections[i].Color,
|
||||||
|
FSections[i].FormatString
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Construct total format string
|
||||||
if ns = 2 then
|
if ns = 2 then
|
||||||
FFormatString := Format('%s;%s;%s', [
|
FFormatString := Format('%s;%s;%s', [
|
||||||
FSections[0].FormatString,
|
FSections[0].FormatString,
|
||||||
@ -408,6 +449,9 @@ var
|
|||||||
begin
|
begin
|
||||||
FStatus := psOK;
|
FStatus := psOK;
|
||||||
AddSection;
|
AddSection;
|
||||||
|
if AFormatString = '' then
|
||||||
|
exit;
|
||||||
|
|
||||||
FStart := @AFormatString[1];
|
FStart := @AFormatString[1];
|
||||||
FEnd := FStart + Length(AFormatString) - 1;
|
FEnd := FStart + Length(AFormatString) - 1;
|
||||||
FCurrent := FStart;
|
FCurrent := FStart;
|
||||||
@ -415,6 +459,7 @@ begin
|
|||||||
token := FCurrent^;
|
token := FCurrent^;
|
||||||
case token of
|
case token of
|
||||||
'[': ScanBrackets;
|
'[': ScanBrackets;
|
||||||
|
':': if FIsTime then AddChar(':');
|
||||||
';': AddSection;
|
';': AddSection;
|
||||||
else ScanFormat;
|
else ScanFormat;
|
||||||
end;
|
end;
|
||||||
@ -444,6 +489,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Scans a date/time format. Note: fpc and the Excel-standard have slightly
|
||||||
|
different formats which are converted here }
|
||||||
procedure TsNumFormatParser.ScanDateTime;
|
procedure TsNumFormatParser.ScanDateTime;
|
||||||
var
|
var
|
||||||
token: Char;
|
token: Char;
|
||||||
@ -452,55 +499,76 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
nf: TsNumberFormat;
|
nf: TsNumberFormat;
|
||||||
partStr: String;
|
partStr: String;
|
||||||
isTime: Boolean;
|
|
||||||
isAMPM: Boolean;
|
isAMPM: Boolean;
|
||||||
begin
|
begin
|
||||||
done := false;
|
done := false;
|
||||||
s := '';
|
s := '';
|
||||||
isTime := false;
|
|
||||||
isAMPM := false;
|
isAMPM := false;
|
||||||
|
|
||||||
while (FCurrent <= FEnd) and (FStatus = psOK) and (not done) do begin
|
while (FCurrent <= FEnd) and (FStatus = psOK) and (not done) do begin
|
||||||
token := FCurrent^;
|
token := FCurrent^;
|
||||||
case token of
|
case token of
|
||||||
'\':
|
'\': // means that the next character is taken literally
|
||||||
begin
|
begin
|
||||||
inc(FCurrent);
|
inc(FCurrent); // skip the "\"...
|
||||||
token := FCurrent^;
|
token := FCurrent^; // and take the next character
|
||||||
s := s + token;
|
s := s + token;
|
||||||
end;
|
end;
|
||||||
'Y', 'y':
|
'Y', 'y':
|
||||||
begin
|
begin
|
||||||
ScanDateTimeParts(token, token, s);
|
ScanDateTimeParts(token, token, s);
|
||||||
isTime := false;
|
FIsTime := false;
|
||||||
|
end;
|
||||||
|
'M':
|
||||||
|
if FConversionDirection = cdToFPSpreadsheet then
|
||||||
|
ScanDateTimeParts(token, 'm', s)
|
||||||
|
else begin
|
||||||
|
if FIsTime then ScanDateTimeParts(token, 'm', s) else ScanDateTimeParts(token, 'M', s);
|
||||||
|
end;
|
||||||
|
'm':
|
||||||
|
if FConversionDirection = cdToFPSpreadsheet then begin
|
||||||
|
if FIsTime then ScanDateTimeParts(token, 'n', s) else ScanDateTimeParts(token, 'm', s)
|
||||||
|
end else begin
|
||||||
|
if FIsTime then ScanDateTimeParts(token, 'm', s) else ScanDateTimeParts(token, 'M', s);
|
||||||
end;
|
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':
|
'N', 'n':
|
||||||
ScanDateTimeParts(token, 'n', s); // fpc dialect for "minutes"
|
if FConversionDirection = cdToFPSpreadsheet then begin
|
||||||
|
// "n" is not used by file format --> stop scanning date/time
|
||||||
|
done := true;
|
||||||
|
dec(FCurrent);
|
||||||
|
end else
|
||||||
|
// "n", in fpc, stands for "minute".
|
||||||
|
ScanDateTimeParts(token, 'm', s);
|
||||||
'D', 'd':
|
'D', 'd':
|
||||||
begin
|
begin
|
||||||
ScanDateTimeParts(token, token, s);
|
ScanDateTimeParts(token, token, s);
|
||||||
isTime := false;
|
FIsTime := false;
|
||||||
end;
|
end;
|
||||||
'H', 'h':
|
'H', 'h':
|
||||||
begin
|
begin
|
||||||
ScanDateTimeParts(token, token, s);
|
ScanDateTimeParts(token, token, s);
|
||||||
isTime := true;
|
FIsTime := true;
|
||||||
end;
|
end;
|
||||||
'S', 's':
|
'S', 's':
|
||||||
begin
|
begin
|
||||||
ScanDateTimeParts(token, token, s);
|
ScanDateTimeParts(token, token, s);
|
||||||
isTime := true;
|
FIsTime := true;
|
||||||
end;
|
end;
|
||||||
'/', ':', '.', ']', '[', ' ':
|
'/', ':', '.', ']', '[', ' ':
|
||||||
s := s + token;
|
s := s + token;
|
||||||
'0', 'z', 'Z':
|
'0':
|
||||||
ScanDateTimeParts(token, token, s);
|
if FConversionDirection = cdToFPSpreadsheet then
|
||||||
|
ScanDateTimeParts(token, 'z', s)
|
||||||
|
else begin
|
||||||
|
done := true;
|
||||||
|
dec(FCurrent);
|
||||||
|
end;
|
||||||
|
'z', 'Z':
|
||||||
|
if FConversionDirection = cdToFPSpreadsheet then begin
|
||||||
|
done := true;
|
||||||
|
dec(FCurrent);
|
||||||
|
end else
|
||||||
|
ScanDateTimeParts(token, '0', s);
|
||||||
'A', 'a':
|
'A', 'a':
|
||||||
begin
|
begin
|
||||||
ScanAMPM(s);
|
ScanAMPM(s);
|
||||||
@ -530,6 +598,9 @@ begin
|
|||||||
else
|
else
|
||||||
if s = StripAMPM(FWorkbook.FormatSettings.ShortTimeFormat) then
|
if s = StripAMPM(FWorkbook.FormatSettings.ShortTimeFormat) then
|
||||||
nf := IfThen(isAMPM, nfShortTimeAM, nfShortTime)
|
nf := IfThen(isAMPM, nfShortTimeAM, nfShortTime)
|
||||||
|
else
|
||||||
|
if s[1] = '[' then
|
||||||
|
nf := nfTimeInterval
|
||||||
else
|
else
|
||||||
nf := nfFmtDateTime;
|
nf := nfFmtDateTime;
|
||||||
|
|
||||||
@ -590,6 +661,10 @@ begin
|
|||||||
inc(FCurrent);
|
inc(FCurrent);
|
||||||
ScanText;
|
ScanText;
|
||||||
end;
|
end;
|
||||||
|
'(', ')':
|
||||||
|
begin
|
||||||
|
AddChar(token);
|
||||||
|
end;
|
||||||
'0', '#', '.', ',', '-':
|
'0', '#', '.', ',', '-':
|
||||||
ScanNumber;
|
ScanNumber;
|
||||||
'y', 'Y', 'm', 'M', 'd', 'D', 'h', 'N', 'n', 's', '[':
|
'y', 'Y', 'm', 'M', 'd', 'D', 'h', 'N', 'n', 's', '[':
|
||||||
|
@ -379,7 +379,8 @@ type
|
|||||||
|
|
||||||
{ Data manipulation methods - For Cells }
|
{ Data manipulation methods - For Cells }
|
||||||
procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet);
|
procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet);
|
||||||
procedure CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal);
|
procedure CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal); overload;
|
||||||
|
procedure CopyFormat(AFromCell, AToCell: PCell); overload;
|
||||||
function FindCell(ARow, ACol: Cardinal): PCell;
|
function FindCell(ARow, ACol: Cardinal): PCell;
|
||||||
function GetCell(ARow, ACol: Cardinal): PCell;
|
function GetCell(ARow, ACol: Cardinal): PCell;
|
||||||
function GetCellCount: Cardinal;
|
function GetCellCount: Cardinal;
|
||||||
@ -561,24 +562,30 @@ type
|
|||||||
FFirstFormatIndexInFile: Integer;
|
FFirstFormatIndexInFile: Integer;
|
||||||
FNextFormatIndex: Integer;
|
FNextFormatIndex: Integer;
|
||||||
procedure AddBuiltinFormats; virtual;
|
procedure AddBuiltinFormats; virtual;
|
||||||
procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
|
|
||||||
var ANumFormat: TsNumberFormat; var ADecimals: byte;
|
|
||||||
var ACurrencySymbol: String); virtual;
|
|
||||||
procedure RemoveFormat(AIndex: Integer);
|
procedure RemoveFormat(AIndex: Integer);
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook);
|
constructor Create(AWorkbook: TsWorkbook);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function AddFormat(AFormatCell: PCell): Integer; overload;
|
function AddFormat(AFormatCell: PCell): Integer; overload;
|
||||||
function AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
|
function AddFormat(AFormatIndex: Integer; AFormatString: String;
|
||||||
AFormatString: String = ''; ADecimals: Byte = 0;
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 0;
|
||||||
ACurrencySymbol: String = ''): Integer; overload;
|
ACurrencySymbol: String = ''): Integer; overload;
|
||||||
|
function AddFormat(AFormatString: String; ANumFormat: TsNumberFormat;
|
||||||
|
ADecimals: Byte = 0; ACurrencySymbol: String = ''): Integer; overload;
|
||||||
procedure AnalyzeAndAdd(AFormatIndex: Integer; AFormatString: String);
|
procedure AnalyzeAndAdd(AFormatIndex: Integer; AFormatString: String);
|
||||||
procedure Clear;
|
procedure Clear;
|
||||||
|
procedure ConvertAfterReading(AFormatIndex: Integer; var AFormatString: String;
|
||||||
|
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
||||||
|
var ACurrencySymbol: String); virtual;
|
||||||
|
procedure ConvertBeforeWriting(var AFormatString: String;
|
||||||
|
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
||||||
|
var ACurrencySymbol: String); virtual;
|
||||||
procedure Delete(AIndex: Integer);
|
procedure Delete(AIndex: Integer);
|
||||||
function Find(AFormatCell: PCell): integer; overload;
|
function Find(AFormatCell: PCell): integer; overload;
|
||||||
function Find(ANumFormat: TsNumberFormat; AFormatString: String;
|
function Find(ANumFormat: TsNumberFormat; AFormatString: String;
|
||||||
ADecimals: Byte; ACurrencySymbol: String): Integer; overload;
|
ADecimals: Byte; ACurrencySymbol: String): Integer; overload;
|
||||||
function Find(AFormatIndex: Integer): Integer; overload;
|
function Find(AFormatIndex: Integer): Integer; overload;
|
||||||
|
function Find(AFormatString: String): Integer; overload;
|
||||||
function FormatStringForWriting(AIndex: Integer): String; virtual;
|
function FormatStringForWriting(AIndex: Integer): String; virtual;
|
||||||
procedure Sort;
|
procedure Sort;
|
||||||
|
|
||||||
@ -731,6 +738,7 @@ procedure RegisterSpreadFormat(
|
|||||||
AWriterClass: TsSpreadWriterClass;
|
AWriterClass: TsSpreadWriterClass;
|
||||||
AFormat: TsSpreadsheetFormat);
|
AFormat: TsSpreadsheetFormat);
|
||||||
|
|
||||||
|
procedure CopyCellFormat(AFromCell, AToCell: PCell);
|
||||||
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
|
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
|
||||||
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
||||||
|
|
||||||
@ -749,6 +757,7 @@ resourcestring
|
|||||||
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
||||||
lpNoValidNumberFormatString = 'No valid number format string.';
|
lpNoValidNumberFormatString = 'No valid number format string.';
|
||||||
lpNoValidDateTimeFormatString = 'No valid date/time format string.';
|
lpNoValidDateTimeFormatString = 'No valid date/time format string.';
|
||||||
|
lpIllegalNumberFormat = 'Illegal number format.';
|
||||||
lpTRUE = 'TRUE';
|
lpTRUE = 'TRUE';
|
||||||
lpFALSE = 'FALSE';
|
lpFALSE = 'FALSE';
|
||||||
lpErrEmptyIntersection = '#NULL!';
|
lpErrEmptyIntersection = '#NULL!';
|
||||||
@ -875,6 +884,28 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Copies the format of a cell to another one.
|
||||||
|
}
|
||||||
|
procedure CopyCellFormat(AFromCell, AToCell: PCell);
|
||||||
|
begin
|
||||||
|
Assert(AFromCell <> nil);
|
||||||
|
Assert(AToCell <> nil);
|
||||||
|
|
||||||
|
AToCell^.UsedFormattingFields := AFromCell^.UsedFormattingFields;
|
||||||
|
AToCell^.BackgroundColor := AFromCell^.BackgroundColor;
|
||||||
|
AToCell^.Border := AFromCell^.Border;
|
||||||
|
AToCell^.BorderStyles := AFromCell^.BorderStyles;
|
||||||
|
AToCell^.FontIndex := AFromCell^.FontIndex;
|
||||||
|
AToCell^.HorAlignment := AFromCell^.HorAlignment;
|
||||||
|
AToCell^.VertAlignment := AFromCell^.VertAlignment;
|
||||||
|
AToCell^.TextRotation := AFromCell^.TextRotation;
|
||||||
|
AToCell^.NumberFormat := AFromCell^.NumberFormat;
|
||||||
|
AToCell^.NumberFormatStr := AFromCell^.NumberFormatStr;
|
||||||
|
AToCell^.Decimals := AFromCell^.Decimals;
|
||||||
|
AToCell^.CurrencySymbol := AFromCell^.CurrencySymbol;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsWorksheet }
|
{ TsWorksheet }
|
||||||
|
|
||||||
@ -997,29 +1028,19 @@ end;
|
|||||||
{@@
|
{@@
|
||||||
Copies all format parameters from the format cell to another cell.
|
Copies all format parameters from the format cell to another cell.
|
||||||
}
|
}
|
||||||
procedure TsWorksheet.CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal);
|
procedure TsWorksheet.CopyFormat(AFromCell, AToCell: PCell);
|
||||||
var
|
|
||||||
cell: PCell;
|
|
||||||
begin
|
begin
|
||||||
if AFormat = nil then
|
if (AFromCell = nil) or (AToCell = nil) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
cell := GetCell(AToRow, AToCol);
|
CopyCellFormat(AFromCell, AToCell);
|
||||||
cell^.UsedFormattingFields := AFormat^.UsedFormattingFields;
|
ChangedCell(AToCell^.Row, AToCell^.Col);
|
||||||
cell^.BackgroundColor := AFormat^.BackgroundColor;
|
ChangedFont(AToCell^.Row, AToCell^.Col);
|
||||||
cell^.Border := AFormat^.Border;
|
end;
|
||||||
cell^.BorderStyles := AFormat^.BorderStyles;
|
|
||||||
cell^.FontIndex := AFormat^.FontIndex;
|
|
||||||
cell^.HorAlignment := AFormat^.HorAlignment;
|
|
||||||
cell^.VertAlignment := AFormat^.VertAlignment;
|
|
||||||
cell^.TextRotation := AFormat^.TextRotation;
|
|
||||||
cell^.NumberFormat := AFormat^.NumberFormat;
|
|
||||||
cell^.NumberFormatStr := AFormat^.NumberFormatStr;
|
|
||||||
cell^.Decimals := AFormat^.Decimals;
|
|
||||||
cell^.CurrencySymbol := AFormat^.CurrencySymbol;
|
|
||||||
|
|
||||||
ChangedCell(AToRow, AToCol);
|
procedure TsWorksheet.CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal);
|
||||||
ChangedFont(AToRow, AToCol);
|
begin
|
||||||
|
CopyFormat(AFormat, GetCell(AToRow, AToCol));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -1433,6 +1454,9 @@ begin
|
|||||||
if IsDateTimeFormat(AFormat) then
|
if IsDateTimeFormat(AFormat) then
|
||||||
raise Exception.Create(lpInvalidNumberFormat);
|
raise Exception.Create(lpInvalidNumberFormat);
|
||||||
|
|
||||||
|
if AFormat = nfCustom then
|
||||||
|
raise Exception.Create(lpIllegalNumberformat);
|
||||||
|
|
||||||
if AFormat <> nfGeneral then begin
|
if AFormat <> nfGeneral then begin
|
||||||
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
||||||
ACell^.NumberFormat := AFormat;
|
ACell^.NumberFormat := AFormat;
|
||||||
@ -1457,7 +1481,7 @@ var
|
|||||||
parser: TsNumFormatParser;
|
parser: TsNumFormatParser;
|
||||||
nf: TsNumberFormat;
|
nf: TsNumberFormat;
|
||||||
begin
|
begin
|
||||||
parser := TsNumFormatParser.Create(Workbook, AFormatString, cdToFPSpreadsheet);
|
parser := TsNumFormatParser.Create(Workbook, AFormatString, nfCustom, cdToFPSpreadsheet);
|
||||||
try
|
try
|
||||||
// Format string ok?
|
// Format string ok?
|
||||||
if parser.Status <> psOK then
|
if parser.Status <> psOK then
|
||||||
@ -1533,18 +1557,17 @@ end;
|
|||||||
Note: at least Excel xls does not recognize a separate datetime cell type:
|
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
|
a datetime is stored as a (floating point) Number, and the cell is formatted
|
||||||
as a date (either built-in or a custom format).
|
as a date (either built-in or a custom format).
|
||||||
|
|
||||||
Note: custom formats are currently not supported by the writer.
|
|
||||||
}
|
}
|
||||||
procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||||
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
||||||
var
|
var
|
||||||
ACell: PCell;
|
ACell: PCell;
|
||||||
fmt: String;
|
//fmt: String;
|
||||||
parser: TsNumFormatParser;
|
//parser: TsNumFormatParser;
|
||||||
begin
|
begin
|
||||||
if AFormat = nfFmtDateTime then begin
|
if (AFormat in [nfFmtDateTime, nfTimeInterval]) then
|
||||||
AFormatStr := BuildDateTimeFormatString(AFormat, Workbook.FormatSettings, AFormatStr);
|
AFormatStr := BuildDateTimeFormatString(AFormat, Workbook.FormatSettings, AFormatStr);
|
||||||
|
(*
|
||||||
parser := TsNumFormatParser.Create(Workbook, AFormatStr, cdToFPSpreadsheet);
|
parser := TsNumFormatParser.Create(Workbook, AFormatStr, cdToFPSpreadsheet);
|
||||||
try
|
try
|
||||||
// Check that the format string can be reckognized.
|
// Check that the format string can be reckognized.
|
||||||
@ -1558,6 +1581,7 @@ begin
|
|||||||
parser.Free;
|
parser.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
ACell := GetCell(ARow, ACol);
|
ACell := GetCell(ARow, ACol);
|
||||||
ACell^.ContentType := cctDateTime;
|
ACell^.ContentType := cctDateTime;
|
||||||
@ -1579,7 +1603,8 @@ end;
|
|||||||
|
|
||||||
procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte);
|
procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte);
|
||||||
begin
|
begin
|
||||||
if (ACell <> nil) and (ACell^.ContentType = cctNumber) then begin
|
if (ACell <> nil) and (ACell^.ContentType = cctNumber) and (ACell^.NumberFormat <> nfCustom)
|
||||||
|
then begin
|
||||||
ACell^.Decimals := ADecimals;
|
ACell^.Decimals := ADecimals;
|
||||||
ACell^.NumberFormatStr := BuildNumberFormatString(ACell^.NumberFormat,
|
ACell^.NumberFormatStr := BuildNumberFormatString(ACell^.NumberFormat,
|
||||||
FWorkbook.FormatSettings, ADecimals, ACell^.CurrencySymbol);
|
FWorkbook.FormatSettings, ADecimals, ACell^.CurrencySymbol);
|
||||||
@ -2629,27 +2654,43 @@ end;
|
|||||||
|
|
||||||
{ Adds a new number format data to the list and returns the list index of the
|
{ Adds a new number format data to the list and returns the list index of the
|
||||||
new (or present) item. }
|
new (or present) item. }
|
||||||
function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
|
function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer;
|
||||||
AFormatString: String = ''; ADecimals: byte = 0; ACurrencySymbol: String = ''): integer;
|
AFormatString: String; ANumFormat: TsNumberFormat; ADecimals: byte = 0;
|
||||||
|
ACurrencySymbol: String = ''): integer;
|
||||||
var
|
var
|
||||||
item: TsNumFormatData;
|
item: TsNumFormatData;
|
||||||
begin
|
begin
|
||||||
item := TsNumFormatData.Create;
|
item := TsNumFormatData.Create;
|
||||||
item.Index := AFormatIndex;
|
item.Index := AFormatIndex;
|
||||||
item.NumFormat := ANumFormat;
|
item.NumFormat := ANumFormat;
|
||||||
if IsDateTimeFormat(ANumFormat) then
|
if AFormatString = '' then begin
|
||||||
AFormatString := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings,
|
if IsDateTimeFormat(ANumFormat) then
|
||||||
AFormatString)
|
AFormatString := BuildDateTimeFormatString(ANumFormat, Workbook.FormatSettings,
|
||||||
else
|
AFormatString)
|
||||||
if item.NumFormat <> nfCustom then
|
else
|
||||||
AFormatString := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings,
|
if item.NumFormat <> nfCustom then
|
||||||
ADecimals, ACurrencySymbol);
|
AFormatString := BuildNumberFormatString(ANumFormat, Workbook.FormatSettings,
|
||||||
|
ADecimals, ACurrencySymbol);
|
||||||
|
end;
|
||||||
item.FormatString := AFormatString;
|
item.FormatString := AFormatString;
|
||||||
item.Decimals := ADecimals;
|
item.Decimals := ADecimals;
|
||||||
item.CurrencySymbol := ACurrencySymbol;
|
item.CurrencySymbol := ACurrencySymbol;
|
||||||
Result := inherited Add(item);
|
Result := inherited Add(item);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsCustomNumFormatList.AddFormat(AFormatString: String;
|
||||||
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 0;
|
||||||
|
ACurrencySymbol: String = ''): Integer;
|
||||||
|
begin
|
||||||
|
if AFormatString = '' then begin
|
||||||
|
Result := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
Result := AddFormat(FNextFormatIndex, AFormatString, ANumFormat, ADecimals,
|
||||||
|
ACurrencySymbol);
|
||||||
|
inc(FNextFormatIndex);
|
||||||
|
end;
|
||||||
|
|
||||||
function TsCustomNumFormatList.AddFormat(AFormatCell: PCell): Integer;
|
function TsCustomNumFormatList.AddFormat(AFormatCell: PCell): Integer;
|
||||||
var
|
var
|
||||||
item: TsNumFormatData;
|
item: TsNumFormatData;
|
||||||
@ -2661,8 +2702,8 @@ begin
|
|||||||
raise Exception.Create('TsCustomNumFormatList: Error in program logics: You must provide built-in formats first.');
|
raise Exception.Create('TsCustomNumFormatList: Error in program logics: You must provide built-in formats first.');
|
||||||
|
|
||||||
Result := AddFormat(FNextFormatIndex,
|
Result := AddFormat(FNextFormatIndex,
|
||||||
AFormatCell^.NumberFormat,
|
|
||||||
AFormatCell^.NumberFormatStr,
|
AFormatCell^.NumberFormatStr,
|
||||||
|
AFormatCell^.NumberFormat,
|
||||||
AFormatCell^.Decimals,
|
AFormatCell^.Decimals,
|
||||||
AFormatCell^.CurrencySymbol
|
AFormatCell^.CurrencySymbol
|
||||||
);
|
);
|
||||||
@ -2671,25 +2712,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ Adds the builtin format items to the list. The formats must be specified in
|
{ Adds the builtin format items to the list. The formats must be specified in
|
||||||
a way which can be understood by fpc.
|
a way that is compatible with the destination file format. Conversion of the
|
||||||
If fpc and file speak different languages "translation" must be made in
|
formatstrings can be done by calling "ConvertAfterReadung" bzw. "ConvertBeforeWriting".
|
||||||
"Analyze" for reading and "FormatStringForWriting" for writing.
|
"AddBuiltInFormats" must be called before user items are added.
|
||||||
Must be called before user items are added.
|
|
||||||
Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. doesn't save formats <164)
|
Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. doesn't save formats <164)
|
||||||
and must initialize the index of the first user format (FNextFormatIndex)
|
and must initialize the index of the first user format (FNextFormatIndex)
|
||||||
which is automatically incremented when adding user formats. }
|
which is automatically incremented when adding user formats. }
|
||||||
procedure TsCustomNumFormatList.AddBuiltinFormats;
|
procedure TsCustomNumFormatList.AddBuiltinFormats;
|
||||||
begin
|
begin
|
||||||
// must be overridden
|
// must be overridden - see xlscommon as an example.
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Takes the format string (AFormatString) as it is read from the file and
|
{ Takes the format string (AFormatString) as it is read from the file and
|
||||||
extracts the number format type (ANumFormat) and the number of decimals
|
extracts the number format type and the number of decimals out of it for use by
|
||||||
(ADecimals) out of it for use by fpc.
|
fpc. The method also converts the format string to a form that can be used
|
||||||
If the format string cannot be directly handled by fpc it has to be transformed
|
by fpc's FormatDateTime and FormatFloat. This conversion should be done in an
|
||||||
to make it compatible. Can be done in overridden versions which know more
|
overridden method which known more about the details of the spreadsheet file
|
||||||
about the structure of the string in the actual file format. }
|
format. }
|
||||||
procedure TsCustomNumFormatList.Analyze(AFormatIndex: Integer;
|
procedure TsCustomNumFormatList.ConvertAfterReading(AFormatIndex: Integer;
|
||||||
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
||||||
var ADecimals: Byte; var ACurrencySymbol: String);
|
var ADecimals: Byte; var ACurrencySymbol: String);
|
||||||
var
|
var
|
||||||
@ -2697,6 +2737,7 @@ var
|
|||||||
fmt: String;
|
fmt: String;
|
||||||
lFormatData: TsNumFormatData;
|
lFormatData: TsNumFormatData;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
nf: TsNumberFormat;
|
||||||
begin
|
begin
|
||||||
i := Find(AFormatIndex);
|
i := Find(AFormatIndex);
|
||||||
if i > 0 then begin
|
if i > 0 then begin
|
||||||
@ -2704,16 +2745,42 @@ begin
|
|||||||
fmt := lFormatData.FormatString;
|
fmt := lFormatData.FormatString;
|
||||||
end else
|
end else
|
||||||
fmt := AFormatString;
|
fmt := AFormatString;
|
||||||
|
nf := nfGeneral; // not used here.
|
||||||
|
|
||||||
parser := TsNumFormatParser.Create(Workbook, fmt, cdToFPSpreadsheet);
|
// Analyzes the format string and tries to convert it to fpSpreadsheet format.
|
||||||
|
parser := TsNumFormatParser.Create(Workbook, fmt, nf, cdToFPSpreadsheet);
|
||||||
try
|
try
|
||||||
if parser.Status = psOK then begin
|
if parser.Status = psOK then begin
|
||||||
ANumFormat := parser.Builtin_NumFormat;
|
ANumFormat := parser.Builtin_NumFormat;
|
||||||
AFormatString := parser.FormatString;
|
AFormatString := parser.FormatString; // This is the converted string.
|
||||||
|
{
|
||||||
if not (parser.Builtin_NumFormat in [nfCustom, nfFmtDateTime]) then begin
|
if not (parser.Builtin_NumFormat in [nfCustom, nfFmtDateTime]) then begin
|
||||||
ADecimals := parser.ParsedSections[0].Decimals;
|
ADecimals := parser.ParsedSections[0].Decimals;
|
||||||
ACurrencySymbol := parser.ParsedSections[0].CurrencySymbol;
|
ACurrencySymbol := parser.ParsedSections[0].CurrencySymbol;
|
||||||
end;
|
end;
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
parser.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Is called before collection all number formats of the spreadsheet and before
|
||||||
|
writing to file. Its purpose is to convert the format string as used by fpc
|
||||||
|
to a format compatible with the spreadsheet file format. }
|
||||||
|
procedure TsCustomNumFormatList.ConvertBeforeWriting(var AFormatString: String;
|
||||||
|
var ANumFormat: TsNumberFormat; var ADecimals: Byte; var ACurrencySymbol: String);
|
||||||
|
var
|
||||||
|
parser: TsNumFormatParser;
|
||||||
|
fmt: String;
|
||||||
|
begin
|
||||||
|
parser := TsNumFormatParser.Create(Workbook, AFormatString, ANumFormat, cdFromFPSpreadsheet);
|
||||||
|
try
|
||||||
|
if parser.Status = psOK then begin
|
||||||
|
AFormatString := parser.FormatString;
|
||||||
|
ANumFormat := parser.Builtin_NumFormat;
|
||||||
|
ADecimals := parser.ParsedSections[0].Decimals;
|
||||||
|
ACurrencySymbol := parser.ParsedSections[0].CurrencySymbol;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
parser.Free;
|
parser.Free;
|
||||||
@ -2842,11 +2909,11 @@ begin
|
|||||||
if Find(AFormatIndex) > -1 then
|
if Find(AFormatIndex) > -1 then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// Analyze the format string and extract information for internal formatting
|
// Analyze & convert the format string, extract infos for internal formatting
|
||||||
Analyze(AFormatIndex, AFormatString, nf, decs, currsym);
|
ConvertAfterReading(AFormatIndex, AFormatString, nf, decs, currsym);
|
||||||
|
|
||||||
// Add the new item
|
// Add the new item
|
||||||
AddFormat(AFormatIndex, nf, AFormatString, decs, currSym);
|
AddFormat(AFormatIndex, AFormatString, nf, decs, currSym);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Clears the list and frees memory occupied by the format items. }
|
{ Clears the list and frees memory occupied by the format items. }
|
||||||
@ -2967,6 +3034,20 @@ begin
|
|||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Finds the item with the given format string and returns its index in the
|
||||||
|
format list. }
|
||||||
|
function TsCustomNumFormatList.Find(AFormatString: String): integer;
|
||||||
|
var
|
||||||
|
item: TsNumFormatData;
|
||||||
|
begin
|
||||||
|
for Result := 0 to Count-1 do begin
|
||||||
|
item := Items[Result];
|
||||||
|
if item.FormatString = AFormatString then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
Result := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Determines the format string to be written into the spreadsheet file.
|
{ Determines the format string to be written into the spreadsheet file.
|
||||||
Needs to be overridden if the format strings are different from the fpc
|
Needs to be overridden if the format strings are different from the fpc
|
||||||
convention. }
|
convention. }
|
||||||
@ -3155,7 +3236,7 @@ begin
|
|||||||
if (FFormattingStyles[i].Decimals <> AFormat^.Decimals) then Continue;
|
if (FFormattingStyles[i].Decimals <> AFormat^.Decimals) then Continue;
|
||||||
if (FFormattingStyles[i].CurrencySymbol <> AFormat^.CurrencySymbol) then Continue;
|
if (FFormattingStyles[i].CurrencySymbol <> AFormat^.CurrencySymbol) then Continue;
|
||||||
end;
|
end;
|
||||||
nfShortDate, nfLongDate, nfShortDateTime, nfShortTime, nfLongTime,
|
nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
|
||||||
nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
|
nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
|
||||||
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
|
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
|
||||||
end;
|
end;
|
||||||
@ -3173,6 +3254,10 @@ end;
|
|||||||
format of the writer, here is the place to apply replacements.
|
format of the writer, here is the place to apply replacements.
|
||||||
Must be overridden by descendants. See BIFF2 }
|
Must be overridden by descendants. See BIFF2 }
|
||||||
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
|
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
|
||||||
|
begin
|
||||||
|
// to be overridden
|
||||||
|
end;
|
||||||
|
(*
|
||||||
var
|
var
|
||||||
isLong, isAMPM, isInterval: Boolean;
|
isLong, isAMPM, isInterval: Boolean;
|
||||||
decs: Byte;
|
decs: Byte;
|
||||||
@ -3182,7 +3267,7 @@ begin
|
|||||||
// if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
|
// if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
|
||||||
ACell^.Decimals := decs;
|
ACell^.Decimals := decs;
|
||||||
end;
|
end;
|
||||||
end;
|
end; *)
|
||||||
|
|
||||||
{ Each descendent should define its own default formats, if any.
|
{ Each descendent should define its own default formats, if any.
|
||||||
Always add the normal, unformatted style first to speed things up. }
|
Always add the normal, unformatted style first to speed things up. }
|
||||||
@ -3210,6 +3295,26 @@ begin
|
|||||||
Len := Length(FFormattingStyles);
|
Len := Length(FFormattingStyles);
|
||||||
SetLength(FFormattingStyles, Len+1);
|
SetLength(FFormattingStyles, Len+1);
|
||||||
FFormattingStyles[Len] := ACell^;
|
FFormattingStyles[Len] := ACell^;
|
||||||
|
|
||||||
|
// Some built-in number formats do not write the format string to the cell
|
||||||
|
// But the FormattingStyles need it for comparison later. --> Add the format string.
|
||||||
|
if IsDateTimeFormat(FFormattingStyles[Len].NumberFormat) then
|
||||||
|
FFormattingStyles[Len].NumberFormatStr := BuildDateTimeFormatString(
|
||||||
|
FFormattingStyles[Len].NumberFormat,
|
||||||
|
Workbook.FormatSettings,
|
||||||
|
FFormattingStyles[Len].NumberFormatStr
|
||||||
|
)
|
||||||
|
else
|
||||||
|
if FFormattingStyles[Len].NumberFormat <> nfCustom then
|
||||||
|
FFormattingstyles[Len].NumberFormatStr := BuildNumberFormatString(
|
||||||
|
FFormattingStyles[Len].NumberFormat,
|
||||||
|
Workbook.FormatSettings,
|
||||||
|
FFormattingStyles[Len].Decimals,
|
||||||
|
FFormattingStyles[Len].CurrencySymbol
|
||||||
|
);
|
||||||
|
|
||||||
|
// We store the index of the XF record that will be assigned to this style in
|
||||||
|
// the "row" of the style. Will be needed when writing the XF record.
|
||||||
FFormattingStyles[Len].Row := NextXFIndex;
|
FFormattingStyles[Len].Row := NextXFIndex;
|
||||||
Inc(NextXFIndex);
|
Inc(NextXFIndex);
|
||||||
end;
|
end;
|
||||||
@ -3220,12 +3325,24 @@ var
|
|||||||
begin
|
begin
|
||||||
SetLength(FFormattingStyles, 0);
|
SetLength(FFormattingStyles, 0);
|
||||||
|
|
||||||
|
// Add default styles which are required to be there by the destination file
|
||||||
AddDefaultFormats();
|
AddDefaultFormats();
|
||||||
|
|
||||||
|
// Iterate through all cells and collect the individual styles
|
||||||
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
||||||
begin
|
|
||||||
IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllFormattingStylesCallback);
|
IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllFormattingStylesCallback);
|
||||||
end;
|
|
||||||
|
// Convert the numberformats of the collected styles to be compatible with the destination file
|
||||||
|
for i:=0 to High(FFormattingStyles) do
|
||||||
|
if (FFormattingStyles[i].NumberFormatStr <> '') and
|
||||||
|
(FFormattingStyles[i].NumberFormat <> nfCustom) // don't touch custom formatstrings!
|
||||||
|
then
|
||||||
|
FNumFormatList.ConvertBeforeWriting(
|
||||||
|
FFormattingStyles[i].NumberFormatStr,
|
||||||
|
FFormattingStyles[i].NumberFormat,
|
||||||
|
FFormattingStyles[i].Decimals,
|
||||||
|
FFormattingStyles[i].CurrencySymbol
|
||||||
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -3233,10 +3350,34 @@ end;
|
|||||||
it does not yet exist in the list.
|
it does not yet exist in the list.
|
||||||
}
|
}
|
||||||
procedure TsCustomSpreadWriter.ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
|
procedure TsCustomSpreadWriter.ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
|
||||||
|
var
|
||||||
|
fmt: string;
|
||||||
|
nf: TsNumberFormat;
|
||||||
|
decs: Byte;
|
||||||
|
cs: String;
|
||||||
begin
|
begin
|
||||||
FixFormat(ACell);
|
if ACell^.NumberFormat = nfGeneral then
|
||||||
if FNumFormatList.Find(ACell) = -1 then
|
exit;
|
||||||
FNumFormatList.AddFormat(ACell);
|
|
||||||
|
// The builtin format list is in "file syntax", but the format string of the
|
||||||
|
// cells are in "fpc syntax". Therefore, before seeking, we have to convert
|
||||||
|
// the format string of the cell to "file syntax".
|
||||||
|
fmt := ACell^.NumberFormatStr;
|
||||||
|
nf := ACell^.NumberFormat;
|
||||||
|
decs := ACell^.Decimals;
|
||||||
|
cs := ACell^.CurrencySymbol;
|
||||||
|
if (nf <> nfCustom) then begin
|
||||||
|
if IsDateTimeFormat(nf) then
|
||||||
|
fmt := BuildDateTimeFormatString(nf, Workbook.FormatSettings, fmt)
|
||||||
|
else
|
||||||
|
fmt := BuildNumberFormatString(nf, Workbook.FormatSettings, decs, cs);
|
||||||
|
FNumFormatList.ConvertBeforeWriting(fmt, nf, decs, cs);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Seek the format string in the current number format list.
|
||||||
|
// If not found add the format to the list.
|
||||||
|
if FNumFormatList.Find(fmt) = -1 then
|
||||||
|
FNumFormatList.AddFormat(fmt, nf, decs, cs);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -3265,7 +3406,7 @@ begin
|
|||||||
ResPos := -1;
|
ResPos := -1;
|
||||||
SetLength(Result, 0);
|
SetLength(Result, 0);
|
||||||
|
|
||||||
// The formula needs to start with a =
|
// The formula needs to start with a "=" character.
|
||||||
if AFormula.FormulaStr[1] <> '=' then raise Exception.Create('Formula doesn''t start with =');
|
if AFormula.FormulaStr[1] <> '=' then raise Exception.Create('Formula doesn''t start with =');
|
||||||
|
|
||||||
StrPos := 2;
|
StrPos := 2;
|
||||||
|
@ -84,6 +84,7 @@ function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat;
|
|||||||
const AFormatSettings: TFormatSettings; AFormatString: String = ''): String;
|
const AFormatSettings: TFormatSettings; AFormatString: String = ''): String;
|
||||||
function StripAMPM(const ATimeFormatString: String): String;
|
function StripAMPM(const ATimeFormatString: String): String;
|
||||||
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
||||||
|
function AddIntervalBrackets(AFormatString: String): String;
|
||||||
|
|
||||||
function SciFloat(AValue: Double; ADecimals: Byte): String;
|
function SciFloat(AValue: Double; ADecimals: Byte): String;
|
||||||
//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
|
//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
|
||||||
@ -517,7 +518,7 @@ end;
|
|||||||
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := AFormat in [nfFmtDateTime, nfShortDateTime, nfShortDate, nfLongDate,
|
Result := AFormat in [nfFmtDateTime, nfShortDateTime, nfShortDate, nfLongDate,
|
||||||
nfShortTime. nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval];
|
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval];
|
||||||
end;
|
end;
|
||||||
(*
|
(*
|
||||||
{ This simple parsing procedure of the Excel format string checks for a fixed
|
{ This simple parsing procedure of the Excel format string checks for a fixed
|
||||||
@ -685,7 +686,7 @@ begin
|
|||||||
if ph > 0 then IsSci := true;
|
if ph > 0 then IsSci := true;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
*)
|
|
||||||
{ IsDateFormat checks if the format string s corresponds to a date format }
|
{ IsDateFormat checks if the format string s corresponds to a date format }
|
||||||
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
|
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
|
||||||
begin
|
begin
|
||||||
@ -767,6 +768,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
{ Builds a date/time format string from the numberformat code. If the format code
|
{ 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
|
is nfFmtDateTime the given AFormatString is used. AFormatString can use the
|
||||||
@ -776,6 +778,7 @@ function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat;
|
|||||||
const AFormatSettings: TFormatSettings; AFormatString: String = '') : string;
|
const AFormatSettings: TFormatSettings; AFormatString: String = '') : string;
|
||||||
var
|
var
|
||||||
fmt: String;
|
fmt: String;
|
||||||
|
am, pm: String;
|
||||||
begin
|
begin
|
||||||
case ANumberFormat of
|
case ANumberFormat of
|
||||||
nfFmtDateTime:
|
nfFmtDateTime:
|
||||||
@ -789,31 +792,38 @@ begin
|
|||||||
end;
|
end;
|
||||||
nfShortDateTime:
|
nfShortDateTime:
|
||||||
Result := AFormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
|
Result := AFormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
|
||||||
|
// In the DefaultFormatSettings this is: d/m/y hh:nn
|
||||||
nfShortDate:
|
nfShortDate:
|
||||||
Result := AFormatSettings.ShortDateFormat;
|
Result := AFormatSettings.ShortDateFormat; // --> d/m/y
|
||||||
nfLongDate:
|
nfLongDate:
|
||||||
Result := AFormatSettings.LongDateFormat;
|
Result := AFormatSettings.LongDateFormat; // --> dd mm yyyy
|
||||||
nfShortTime:
|
nfShortTime:
|
||||||
Result := StripAMPM(AFormatSettings.ShortTimeFormat);
|
Result := StripAMPM(AFormatSettings.ShortTimeFormat); // --> hh:nn
|
||||||
nfLongTime:
|
nfLongTime:
|
||||||
Result := StripAMPM(AFormatSettings.LongTimeFormat);
|
Result := StripAMPM(AFormatSettings.LongTimeFormat); // --> hh:nn:ss
|
||||||
nfShortTimeAM:
|
nfShortTimeAM:
|
||||||
begin
|
begin // --> hh:nn AM/PM
|
||||||
Result := AFormatSettings.ShortTimeFormat;
|
Result := AFormatSettings.ShortTimeFormat;
|
||||||
if pos('a', lowercase(AFormatSettings.ShortTimeFormat)) = 0 then
|
if (pos('a', lowercase(AFormatSettings.ShortTimeFormat)) = 0) then begin
|
||||||
Result := Format('%s %s/%s', [Result, AFormatSettings.TimeAMString, AFormatSettings.TimePMString]);
|
am := IfThen(AFormatSettings.TimeAMString = '', 'AM', AFormatSettings.TimeAMString);
|
||||||
|
pm := IfThen(AFormatSettings.TimePMString = '', 'PM', AFormatSettings.TimePMString);
|
||||||
|
Result := Format('%s %s/%s', [Result, am, pm]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
nfLongTimeAM:
|
nfLongTimeAM: // --> hh:nn:ss AM/PM
|
||||||
begin
|
begin
|
||||||
Result := AFormatSettings.LongTimeFormat;
|
Result := AFormatSettings.LongTimeFormat;
|
||||||
if pos('a', lowercase(AFormatSettings.LongTimeFormat)) = 0 then
|
if pos('a', lowercase(AFormatSettings.LongTimeFormat)) = 0 then begin
|
||||||
Result := Format('%s %s/%s', [Result, AFormatSettings.TimeAMString, AFormatSettings.TimePMString]);
|
am := IfThen(AFormatSettings.TimeAMString = '', 'AM', AFormatSettings.TimeAMString);
|
||||||
|
pm := IfThen(AFormatSettings.TimePMString = '', 'PM', AFormatSettings.TimePMString);
|
||||||
|
Result := Format('%s %s/%s', [Result, am, pm]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
nfTimeInterval:
|
nfTimeInterval: // --> [h]:nn:ss
|
||||||
if AFormatString = '' then
|
if AFormatString = '' then
|
||||||
Result := '[h]:mm:ss'
|
Result := '[h]:mm:ss'
|
||||||
else
|
else
|
||||||
Result := AFormatString;
|
Result := AddIntervalBrackets(AFormatString);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -886,13 +896,16 @@ begin
|
|||||||
else Result := Result + ';#,##0' + decs + '-';
|
else Result := Result + ';#,##0' + decs + '-';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if ANumberFormat in [nfCurrency, nfCurrencyRed] then begin
|
if ANumberFormat in [nfCurrency, nfCurrencyRed] then
|
||||||
|
Result := Result +';' + Format(POS_FMT[cf], ['0' + decs, ACurrencySymbol])
|
||||||
|
{
|
||||||
Result := Result + ';0' + decs;
|
Result := Result + ';0' + decs;
|
||||||
if cf in [2,3] then
|
if cf in [2,3] then
|
||||||
Result := Format('%s "%s"', [Result, ACurrencySymbol])
|
Result := Format('%s "%s"', [Result, ACurrencySymbol])
|
||||||
else
|
else
|
||||||
Result := Format('%s"%s"', [Result, ACurrencySymbol]);
|
Result := Format('%s"%s"', [Result, ACurrencySymbol]);
|
||||||
end else
|
}
|
||||||
|
else
|
||||||
Result := Result + ';-';
|
Result := Result + ';-';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -928,6 +941,26 @@ begin
|
|||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ The given format string is assumed to be for time intervals, i.e. its first
|
||||||
|
time symbol must be enclosed by square brackets. Checks if this is true, and
|
||||||
|
adds the brackes if not. }
|
||||||
|
function AddIntervalBrackets(AFormatString: String): String;
|
||||||
|
var
|
||||||
|
p: Integer;
|
||||||
|
s1, s2: String;
|
||||||
|
begin
|
||||||
|
if AFormatString[1] = '[' then
|
||||||
|
Result := AFormatString
|
||||||
|
else begin
|
||||||
|
p := pos(':', AFormatString);
|
||||||
|
if p <> 0 then begin
|
||||||
|
s1 := copy(AFormatString, 1, p-1);
|
||||||
|
s2 := copy(AFormatString, p, Length(AFormatString));
|
||||||
|
Result := Format('[%s]%s', [s1, s2]);
|
||||||
|
end else
|
||||||
|
Result := Format('[%s]', [AFormatString]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Formats the number AValue in "scientific" format with the given number of
|
{ Formats the number AValue in "scientific" format with the given number of
|
||||||
decimals. "Scientific" is the same as "exponential", but with exponents rounded
|
decimals. "Scientific" is the same as "exponential", but with exponents rounded
|
||||||
|
@ -44,7 +44,7 @@ type
|
|||||||
procedure AddBuiltinFormats; override;
|
procedure AddBuiltinFormats; override;
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook);
|
constructor Create(AWorkbook: TsWorkbook);
|
||||||
function FormatStringForWriting(AIndex: Integer): String; override;
|
// function FormatStringForWriting(AIndex: Integer): String; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsSpreadBIFF2Reader }
|
{ TsSpreadBIFF2Reader }
|
||||||
@ -173,33 +173,34 @@ end;
|
|||||||
|
|
||||||
procedure TsBIFF2NumFormatList.AddBuiltinFormats;
|
procedure TsBIFF2NumFormatList.AddBuiltinFormats;
|
||||||
begin
|
begin
|
||||||
AddFormat( 0, nfGeneral);
|
AddFormat( 0, '', nfGeneral);
|
||||||
AddFormat( 1, nfFixed, '0', 0);
|
AddFormat( 1, '0', nfFixed, 0);
|
||||||
AddFormat( 2, nfFixed, '0.00', 2);
|
AddFormat( 2, '0.00', nfFixed, 2);
|
||||||
AddFormat( 3, nfFixedTh, '#,##0', 0);
|
AddFormat( 3, '#,##0', nfFixedTh, 0);
|
||||||
AddFormat( 4, nfFixedTh, '#,##0.00', 2);
|
AddFormat( 4, '#,##0.00', nfFixedTh, 2);
|
||||||
AddFormat( 5, nfFixedTh, '"$"#,##0_);("$"#,##0)', 0);
|
AddFormat( 5, '"$"#,##0_);("$"#,##0)', nfCurrency, 0);
|
||||||
AddFormat( 6, nfFixedTh, '"$"#,##0_);[Red]("$"#,##0)', 2);
|
AddFormat( 6, '"$"#,##0_);[Red]("$"#,##0)', nfCurrencyRed, 2);
|
||||||
AddFormat( 7, nfFixedTh, '"$"#,##0.00_);("$"#,##0.00)', 0);
|
AddFormat( 7, '"$"#,##0.00_);("$"#,##0.00)', nfCurrency, 0);
|
||||||
AddFormat( 8, nfFixedTh, '"$"#,##0.00_);[Red]("$"#,##0.00)', 2);
|
AddFormat( 8, '"$"#,##0.00_);[Red]("$"#,##0.00)', nfCurrency, 2);
|
||||||
AddFormat( 9, nfPercentage, '0%', 0);
|
AddFormat( 9, '0%', nfPercentage, 0);
|
||||||
AddFormat(10, nfPercentage, '0.00%', 2);
|
AddFormat(10, '0.00%', nfPercentage, 2);
|
||||||
AddFormat(11, nfExp, '0.00E+00', 2);
|
AddFormat(11, '0.00E+00', nfExp, 2);
|
||||||
AddFormat(12, nfShortDate);
|
AddFormat(12, 'M/D/YY', nfShortDate);
|
||||||
AddFormat(13, nfLongDate);
|
AddFormat(13, 'D-MMM-YY', nfLongDate);
|
||||||
AddFormat(14, nfFmtDateTime, 'd-mmm');
|
AddFormat(14, 'D-MMM', nfFmtDateTime);
|
||||||
AddFormat(15, nfFmtDateTime, 'mmm-yy');
|
AddFormat(15, 'MMM-YY', nfFmtDateTime);
|
||||||
AddFormat(16, nfShortTimeAM);
|
AddFormat(16, 'h:mm AM/PM', nfShortTimeAM);
|
||||||
AddFormat(17, nfLongTimeAM);
|
AddFormat(17, 'h:mm:ss AM/PM', nfLongTimeAM);
|
||||||
AddFormat(18, nfShortTime);
|
AddFormat(18, 'h:mm', nfShortTime);
|
||||||
AddFormat(19, nfLongTime);
|
AddFormat(19, 'h:mm:ss', nfLongTime);
|
||||||
AddFormat(20, nfShortDateTime);
|
AddFormat(20, 'M/D/YY h:mm', nfShortDateTime);
|
||||||
|
|
||||||
FFirstFormatIndexInFile := 0; // BIFF2 stores built-in formats to file.
|
FFirstFormatIndexInFile := 0; // BIFF2 stores built-in formats to file.
|
||||||
FNextFormatIndex := 21; // not needed - there are not user-defined formats
|
FNextFormatIndex := 21; // not needed - there are not user-defined formats
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Creates formatting strings that are written into the file. }
|
{ Creates formatting strings that are written into the file. }
|
||||||
|
(*
|
||||||
function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
||||||
var
|
var
|
||||||
ds, ts, cs: string;
|
ds, ts, cs: string;
|
||||||
@ -231,7 +232,7 @@ begin
|
|||||||
20: Result := 'm/d/yy h:mm';
|
20: Result := 'm/d/yy h:mm';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
{ TsSpreadBIFF2Reader }
|
{ TsSpreadBIFF2Reader }
|
||||||
|
|
||||||
|
@ -348,11 +348,14 @@ type
|
|||||||
TsBIFFNumFormatList = class(TsCustomNumFormatList)
|
TsBIFFNumFormatList = class(TsCustomNumFormatList)
|
||||||
protected
|
protected
|
||||||
procedure AddBuiltinFormats; override;
|
procedure AddBuiltinFormats; override;
|
||||||
procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
|
{
|
||||||
|
procedure ConvertAfterReading(AFormatIndex: Integer; var AFormatString: String;
|
||||||
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
||||||
var ACurrencySymbol: String); override;
|
var ACurrencySymbol: String); override;
|
||||||
|
procedure ConvertBeforeWriting(var AFormatString: String); override;
|
||||||
|
}
|
||||||
public
|
public
|
||||||
function FormatStringForWriting(AIndex: Integer): String; override;
|
// function FormatStringForWriting(AIndex: Integer): String; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TsSpreadBIFFReader }
|
{ TsSpreadBIFFReader }
|
||||||
@ -535,50 +538,50 @@ end;
|
|||||||
|
|
||||||
{ TsBIFFNumFormatList }
|
{ TsBIFFNumFormatList }
|
||||||
|
|
||||||
{ These are the built-in number formats as used by fpc. Before writing to file
|
{ These are the built-in number formats as expected in the biff spreadsheet file.
|
||||||
some code will be modified to become compatible with Excel
|
In BIFF5+ they are not written to file but they are used for lookup of the
|
||||||
(--> FormatStringForWriting) }
|
number format that Excel used. They have to be converted to fpspreadsheet format. }
|
||||||
procedure TsBIFFNumFormatList.AddBuiltinFormats;
|
procedure TsBIFFNumFormatList.AddBuiltinFormats;
|
||||||
var
|
var
|
||||||
cs: String;
|
cs: String;
|
||||||
begin
|
begin
|
||||||
cs := DefaultFormatSettings.CurrencyString;
|
cs := Workbook.FormatSettings.CurrencyString;
|
||||||
|
|
||||||
AddFormat( 0, nfGeneral);
|
AddFormat( 0, '', nfGeneral);
|
||||||
AddFormat( 1, nfFixed, '0', 0);
|
AddFormat( 1, '0', nfFixed, 0);
|
||||||
AddFormat( 2, nfFixed, '0.00', 2);
|
AddFormat( 2, '0.00', nfFixed, 2);
|
||||||
AddFormat( 3, nfFixedTh, '#,##0', 0);
|
AddFormat( 3, '#,##0', nfFixedTh, 0);
|
||||||
AddFormat( 4, nfFixedTh, '#,##0.00', 2);
|
AddFormat( 4, '#,##0.00', nfFixedTh, 2);
|
||||||
AddFormat( 5, nfCurrency, '', 0);
|
AddFormat( 5, '"'+cs+'"#,##0_);("'+cs+'"#,##0)', nfCurrency, 0);
|
||||||
AddFormat( 6, nfCurrencyRed, '', 0); // negative numbers in red
|
AddFormat( 6, '"'+cs+'"#,##0_);[Red]("'+cs+'"#,##0)', nfCurrencyRed, 0);
|
||||||
AddFormat( 7, nfCurrency, '', 2);
|
AddFormat( 7, '"'+cs+'"#,##0.00_);("'+cs+'"#,##0.00)', nfCurrency, 2);
|
||||||
AddFormat( 8, nfCurrencyRed, '', 2);
|
AddFormat( 8, '"'+cs+'"#,##0.00_);[Red]("'+cs+'"#,##0.00)', nfCurrencyRed, 2);
|
||||||
AddFormat( 9, nfPercentage, '0%', 0);
|
AddFormat( 9, '0%', nfPercentage, 0);
|
||||||
AddFormat(10, nfPercentage, '0.00%', 2);
|
AddFormat(10, '0.00%', nfPercentage, 2);
|
||||||
AddFormat(11, nfExp, '0.00E+00', 2);
|
AddFormat(11, '0.00E+00', nfExp, 2);
|
||||||
// fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
|
// fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
|
||||||
AddFormat(14, nfShortDate);
|
AddFormat(14, 'M/D/YY', nfShortDate);
|
||||||
AddFormat(15, nfLongDate);
|
AddFormat(15, 'D-MMM-YY', nfLongDate);
|
||||||
AddFormat(16, nfFmtDateTime, 'd/mmm');
|
AddFormat(16, 'D-MMM', nfFmtDateTime);
|
||||||
AddFormat(17, nfFmtDateTime, 'mmm/yy');
|
AddFormat(17, 'MMM-YY', nfFmtDateTime);
|
||||||
AddFormat(18, nfShortTimeAM);
|
AddFormat(18, 'h:mm AM/PM', nfShortTimeAM);
|
||||||
AddFormat(19, nfLongTimeAM);
|
AddFormat(19, 'h:mm:ss AM/PM', nfLongTimeAM);
|
||||||
AddFormat(20, nfShortTime);
|
AddFormat(20, 'h:mm', nfShortTime);
|
||||||
AddFormat(21, nfLongTime);
|
AddFormat(21, 'h:mm:ss', nfLongTime);
|
||||||
AddFormat(22, nfShortDateTime);
|
AddFormat(22, 'M/D/YY h:mm', nfShortDateTime);
|
||||||
// 23..36 not supported
|
// 23..36 not supported
|
||||||
AddFormat(37, nfCurrency, '', 0);
|
AddFormat(37, '_(#,##0_);(#,##0)', nfCurrency, 0);
|
||||||
AddFormat(38, nfCurrencyRed, '', 0);
|
AddFormat(38, '_(#,##0_);[Red](#,##0)', nfCurrencyRed, 0);
|
||||||
AddFormat(39, nfCurrency, '', 2);
|
AddFormat(39, '_(#,##0.00_);(#,##0.00)', nfCurrency, 2);
|
||||||
AddFormat(40, nfCurrencyRed, '', 2);
|
AddFormat(40, '_(#,##0.00_);[Red](#,##0.00)', nfCurrencyRed, 2);
|
||||||
AddFormat(41, nfCurrencyDash, '', 0);
|
AddFormat(41, '_("'+cs+'"* #,##0_);_("'+cs+'"* (#,##0);_("'+cs+'"* "-"_);_(@_)', nfCurrencyDash, 0);
|
||||||
AddFormat(42, nfCurrencyDashRed, '', 0);
|
AddFormat(42, '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)', nfCurrencyDash, 0);
|
||||||
AddFormat(43, nfCurrencyDash, '', 2);
|
AddFormat(43, '_("'+cs+'"* #,##0.00_);_("'+cs+'"* (#,##0.00);_("'+cs+'"* "-"??_);_(@_)', nfCurrencyDash, 2);
|
||||||
AddFormat(44, nfCurrencyDashRed, '', 2);
|
AddFormat(44, '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)', nfCurrencyDash, 2);
|
||||||
AddFormat(45, nfFmtDateTime, 'nn:ss');
|
AddFormat(45, 'mm:ss', nfFmtDateTime);
|
||||||
AddFormat(46, nfTimeInterval, '[h]:nn:ss');
|
AddFormat(46, '[h]:mm:ss', nfTimeInterval);
|
||||||
AddFormat(47, nfFmtDateTime, 'nn:ss.z'); // z will be replaced by 0 later
|
AddFormat(47, 'mm:ss.0', nfFmtDateTime);
|
||||||
AddFormat(48, nfSci, '##0.0E+00', 1);
|
AddFormat(48, '##0.0E+00', nfSci, 1);
|
||||||
// 49 ("Text") not supported
|
// 49 ("Text") not supported
|
||||||
|
|
||||||
// All indexes from 0 to 163 are reserved for built-in formats.
|
// All indexes from 0 to 163 are reserved for built-in formats.
|
||||||
@ -586,7 +589,7 @@ begin
|
|||||||
FFirstFormatIndexInFile := 164;
|
FFirstFormatIndexInFile := 164;
|
||||||
FNextFormatIndex := 164;
|
FNextFormatIndex := 164;
|
||||||
end;
|
end;
|
||||||
|
(*
|
||||||
{ Considers some Excel specialities for format detection.
|
{ Considers some Excel specialities for format detection.
|
||||||
The output values will be passed to fpc. }
|
The output values will be passed to fpc. }
|
||||||
procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
|
procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
|
||||||
@ -600,7 +603,7 @@ var
|
|||||||
}
|
}
|
||||||
begin
|
begin
|
||||||
|
|
||||||
(*
|
{
|
||||||
AFormatString := 'hh:mm:ss.0 AM/PM'; //"€" #,##.0;[red]"$" -#,##.000;-';
|
AFormatString := 'hh:mm:ss.0 AM/PM'; //"€" #,##.0;[red]"$" -#,##.000;-';
|
||||||
|
|
||||||
parser := TsNumFormatParser.Create(Workbook, AFormatString);
|
parser := TsNumFormatParser.Create(Workbook, AFormatString);
|
||||||
@ -620,7 +623,7 @@ begin
|
|||||||
finally
|
finally
|
||||||
parser.Free;
|
parser.Free;
|
||||||
end;
|
end;
|
||||||
*)
|
}
|
||||||
|
|
||||||
fmt := Lowercase(AFormatString);
|
fmt := Lowercase(AFormatString);
|
||||||
{ Check the built-in formats first:
|
{ Check the built-in formats first:
|
||||||
@ -664,7 +667,8 @@ begin
|
|||||||
|
|
||||||
inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals, ACurrencySymbol);
|
inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals, ACurrencySymbol);
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
(*
|
||||||
{ Creates formatting strings that are written into the file. }
|
{ Creates formatting strings that are written into the file. }
|
||||||
function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
||||||
var
|
var
|
||||||
@ -712,7 +716,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
{ TsSpreadBIFFReader }
|
{ TsSpreadBIFFReader }
|
||||||
|
|
||||||
@ -2039,6 +2043,7 @@ procedure TsSpreadBIFFWriter.WriteXFIndex(AStream: TStream; ACell: PCell);
|
|||||||
var
|
var
|
||||||
lIndex: Integer;
|
lIndex: Integer;
|
||||||
lXFIndex: Word;
|
lXFIndex: Word;
|
||||||
|
lCell: TCell;
|
||||||
begin
|
begin
|
||||||
// First try the fast methods for default formats
|
// First try the fast methods for default formats
|
||||||
if ACell^.UsedFormattingFields = [] then begin
|
if ACell^.UsedFormattingFields = [] then begin
|
||||||
@ -2047,7 +2052,22 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// If not, then we need to search in the list of dynamic formats
|
// If not, then we need to search in the list of dynamic formats
|
||||||
lIndex := FindFormattingInList(ACell);
|
// But we have to consider that the number formats of the cell is in fpc syntax,
|
||||||
|
// but the number format list of the writer is in Excel syntax.
|
||||||
|
lCell := ACell^;
|
||||||
|
// CopyCellFormat(ACell, @lCell);
|
||||||
|
with lCell do begin
|
||||||
|
if NumberFormat <> nfCustom then begin
|
||||||
|
if IsDateTimeFormat(NumberFormat) then
|
||||||
|
NumberFormatStr := BuildDateTimeFormatString(NumberFormat,
|
||||||
|
Workbook.FormatSettings, NumberFormatStr)
|
||||||
|
else
|
||||||
|
NumberFormatStr := BuildNumberFormatString(NumberFormat,
|
||||||
|
Workbook.FormatSettings, Decimals, CurrencySymbol);
|
||||||
|
NumFormatList.ConvertBeforeWriting(NumberFormatStr, NumberFormat, Decimals, CurrencyString);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
lIndex := FindFormattingInList(@lCell);
|
||||||
|
|
||||||
// Carefully check the index
|
// Carefully check the index
|
||||||
if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then
|
if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then
|
||||||
|
Reference in New Issue
Block a user