You've already forked lazarus-ccr
fpspreadsheet: Bug fixes for biff2 reading/writing for number formats
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3075 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -43,7 +43,7 @@ begin
|
||||
MyWorksheet.LeftPaneWidth := 1;
|
||||
MyWorksheet.TopPaneHeight := 3;
|
||||
}
|
||||
|
||||
(*
|
||||
// Write some number cells
|
||||
MyWorksheet.WriteNumber(0, 0, 1.0);
|
||||
MyWorksheet.WriteUsedFormatting(0, 0, [uffBold, uffNumberFormat]);
|
||||
@ -82,7 +82,7 @@ begin
|
||||
MyWorksheet.WriteUTF8Text(1, 1, 'Second');
|
||||
MyWorksheet.WriteUTF8Text(1, 2, 'Third');
|
||||
MyWorksheet.WriteUTF8Text(1, 3, 'Fourth');
|
||||
|
||||
*)
|
||||
// Write current date/time
|
||||
MyWorksheet.WriteDateTime(2, 0, now);
|
||||
|
||||
@ -267,7 +267,6 @@ begin
|
||||
MyWorksheet.WriteFontColor(r, 3, scGray);
|
||||
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
|
||||
MyWorksheet.WriteFontColor(r, 4, scGray);
|
||||
|
||||
inc(r,2);
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
|
||||
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, '$');
|
||||
@ -288,7 +287,6 @@ begin
|
||||
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDashRed, 0, 'USD');
|
||||
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDashRed, 0, 'USD');
|
||||
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDashRed, 0, 'USD');
|
||||
|
||||
inc(r, 2);
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
|
||||
MyWorksheet.WriteNumber(r, 1, number);
|
||||
|
@ -55,7 +55,6 @@ begin
|
||||
}
|
||||
|
||||
// Write some cells
|
||||
// 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
|
||||
@ -133,7 +132,7 @@ begin
|
||||
MyWorksheet.WriteFont(8, 3, 'Courier New', 12, [fssUnderline], scBlue);
|
||||
MyWorksheet.WriteBackgroundColor(8, 3, scYellow);
|
||||
|
||||
(*
|
||||
{
|
||||
// Uncomment this to test large XLS files
|
||||
for i := 50 to 1000 do
|
||||
begin
|
||||
@ -142,7 +141,7 @@ begin
|
||||
// MyWorksheet.WriteUTF8Text(i, 2, ParamStr(0));
|
||||
MyWorksheet.WriteUTF8Text(i, 3, ParamStr(0));
|
||||
end;
|
||||
*)
|
||||
}
|
||||
|
||||
// Write the formula E1 = A1 + B1
|
||||
SetLength(MyRPNFormula, 3);
|
||||
|
@ -550,11 +550,17 @@ begin
|
||||
if FIsTime then ScanDateTimeParts(token, 'm', s) else ScanDateTimeParts(token, 'M', s);
|
||||
end;
|
||||
'm':
|
||||
if FConversionDirection = cdToFPSpreadsheet then
|
||||
ScanDateTimeParts(token, 'n', s)
|
||||
else
|
||||
ScanDateTimeParts(token, 'm', s);
|
||||
{
|
||||
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;
|
||||
}
|
||||
'N', 'n':
|
||||
if FConversionDirection = cdToFPSpreadsheet then begin
|
||||
// "n" is not used by file format --> stop scanning date/time
|
||||
|
@ -581,11 +581,11 @@ type
|
||||
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
||||
var ACurrencySymbol: String); virtual;
|
||||
procedure Delete(AIndex: Integer);
|
||||
function Find(AFormatCell: PCell): integer; overload;
|
||||
function Find(ANumFormat: TsNumberFormat; AFormatString: String;
|
||||
ADecimals: Byte; ACurrencySymbol: String): Integer; overload;
|
||||
function Find(AFormatIndex: Integer): Integer; overload;
|
||||
function Find(AFormatString: String): Integer; overload;
|
||||
function FindFormatOf(AFormatCell: PCell): integer; virtual;
|
||||
function FormatStringForWriting(AIndex: Integer): String; virtual;
|
||||
procedure Sort;
|
||||
|
||||
@ -642,7 +642,7 @@ type
|
||||
function FindFormattingInList(AFormat: PCell): Integer;
|
||||
procedure FixFormat(ACell: PCell); virtual;
|
||||
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
|
||||
procedure ListAllFormattingStyles;
|
||||
procedure ListAllFormattingStyles; virtual;
|
||||
procedure ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
|
||||
procedure ListAllNumFormats; virtual;
|
||||
{ Helpers for writing }
|
||||
@ -999,11 +999,6 @@ procedure TsWorksheet.CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal;
|
||||
AFromWorksheet: TsWorksheet);
|
||||
var
|
||||
lSrcCell, lDestCell: PCell;
|
||||
{
|
||||
lCurStr: String;
|
||||
lCurUsedFormatting: TsUsedFormattingFields;
|
||||
lCurColor: TsColor;
|
||||
}
|
||||
begin
|
||||
lSrcCell := AFromWorksheet.FindCell(AFromRow, AFromCol);
|
||||
lDestCell := GetCell(AToRow, AToCol);
|
||||
@ -1564,26 +1559,9 @@ procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
||||
var
|
||||
ACell: PCell;
|
||||
//fmt: String;
|
||||
//parser: TsNumFormatParser;
|
||||
begin
|
||||
if (AFormat in [nfFmtDateTime, nfTimeInterval]) then
|
||||
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;
|
||||
@ -2268,9 +2246,7 @@ end;
|
||||
It is added to the end of the list of worksheets
|
||||
|
||||
@param AName The name of the new worksheet
|
||||
|
||||
@return The instace of the newly created worksheet
|
||||
|
||||
@see TsWorkbook
|
||||
}
|
||||
function TsWorkbook.AddWorksheet(AName: string): TsWorksheet;
|
||||
@ -2790,114 +2766,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
(*
|
||||
procedure TsCustomNumFormatList.Analyze(AFormatIndex: Integer;
|
||||
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
||||
var ADecimals: Byte; var ACurrencySymbol: String);
|
||||
const
|
||||
SHORT_LONG_DATE: array[boolean] of TsNumberFormat = (
|
||||
nfShortDate, nfLongDate
|
||||
);
|
||||
AMPM_SHORT_LONG_TIME: array[boolean, boolean] of TsNumberFormat = (
|
||||
(nfShortTime, nfLongTime),
|
||||
(nfShortTimeAM, nfLongTimeAM)
|
||||
);
|
||||
EXP_SCI: array[boolean] of TsNumberFormat = (
|
||||
nfExp, nfSci
|
||||
);
|
||||
CURR_FMT: array[boolean, boolean] of TsNumberFormat = (
|
||||
(nfCurrency, nfCurrencyDash),
|
||||
(nfCurrencyRed, nfCurrencyDashRed)
|
||||
);
|
||||
var
|
||||
decs: Word;
|
||||
isAMPM: Boolean;
|
||||
isLongTime: Boolean;
|
||||
isLongDate: Boolean;
|
||||
isInterval: Boolean;
|
||||
isSci: Boolean;
|
||||
isTime, isDate: Boolean;
|
||||
isCurrRed, isCurrDash: Boolean;
|
||||
lFormatData: TsNumFormatData;
|
||||
i: Integer;
|
||||
fmt: String;
|
||||
begin
|
||||
{ Check the built-in formats first }
|
||||
i := Find(AFormatIndex);
|
||||
if i > 0 then begin
|
||||
lFormatData := Items[i];
|
||||
case lFormatData.NumFormat of
|
||||
nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
|
||||
begin
|
||||
ANumFormat := lFormatData.NumFormat;
|
||||
AFormatString := lFormatData.FormatString;
|
||||
ADecimals := lFormatData.Decimals;
|
||||
exit;
|
||||
end;
|
||||
nfShortDateTime, nfShortDate, nfLongDate,
|
||||
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM, nfTimeInterval:
|
||||
begin
|
||||
ANumFormat := lFormatData.NumFormat;
|
||||
AFormatString := lFormatData.FormatString;
|
||||
ADecimals := 0;
|
||||
exit;
|
||||
end;
|
||||
nfFmtDateTime:
|
||||
begin
|
||||
ANumFormat := lFormatData.NumFormat;
|
||||
AFormatString := lFormatData.FormatString;
|
||||
IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
|
||||
exit;
|
||||
end;
|
||||
nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed:
|
||||
begin
|
||||
ANumFormat := lFormatData.NumFormat;
|
||||
AFormatString := lFormatData.FormatString;
|
||||
ADecimals := lFormatData.Decimals;
|
||||
ACurrencySymbol := lFormatData.CurrencySymbol;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Then check the non-standard formats. There is a chance that they may not be
|
||||
reckognized correctly... }
|
||||
ANumFormat := nfGeneral;
|
||||
if IsPercentNumberFormat(AFormatString, ADecimals) then
|
||||
ANumFormat := nfPercentage
|
||||
else
|
||||
if IsExpNumberFormat(AFormatstring, ADecimals, isSci) then
|
||||
ANumFormat := EXP_SCI[isSci]
|
||||
else
|
||||
if IsThousandSepNumberFormat(AFormatString, ADecimals) then
|
||||
ANumFormat := nfFixedTh
|
||||
else
|
||||
if IsFixedNumberFormat(AFormatString, ADecimals) then
|
||||
ANumFormat := nfFixed
|
||||
else
|
||||
if IsCurrencyFormat(AFormatString, ADecimals, ACurrencySymbol, isCurrRed, isCurrDash) then
|
||||
ANumFormat := CURR_FMT[isCurrRed, isCurrDash]
|
||||
else begin
|
||||
isTime := IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
|
||||
isDate := IsDateFormat(AFormatString, isLongDate);
|
||||
if isInterval then
|
||||
ANumFormat := nfTimeInterval
|
||||
else
|
||||
if isDate and isTime then
|
||||
ANumFormat := nfShortDateTime
|
||||
else if isDate then
|
||||
ANumFormat := SHORT_LONG_DATE[isLongDate]
|
||||
else if isTime then begin
|
||||
if (ADecimals > 0) and (not isAMPM) then
|
||||
ANumFormat := nfFmtDateTime
|
||||
else
|
||||
ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
|
||||
end
|
||||
else if AFormatString <> '' then
|
||||
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
|
||||
list. If necessary, the format string has to be made compatible with fpc
|
||||
@ -2936,17 +2804,6 @@ begin
|
||||
Delete(AIndex);
|
||||
end;
|
||||
|
||||
{ Determines whether the format attributed to the given cell is already
|
||||
contained in the list and returns its list index. }
|
||||
function TsCustomNumFormatList.Find(AFormatCell: PCell): integer;
|
||||
begin
|
||||
if AFormatCell = nil then
|
||||
Result := -1
|
||||
else
|
||||
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr,
|
||||
AFormatCell^.Decimals, AFormatCell^.CurrencySymbol);
|
||||
end;
|
||||
|
||||
{ Seeks a format item with the given properties and returns its list index,
|
||||
or -1 if not found. }
|
||||
function TsCustomNumFormatList.Find(ANumFormat: TsNumberFormat;
|
||||
@ -2956,17 +2813,6 @@ var
|
||||
fmt: String;
|
||||
itemfmt: String;
|
||||
begin
|
||||
(*
|
||||
// These are pre-defined formats - no need to check format string & decimals
|
||||
if ANumFormat in [ nfGeneral, nfShortDateTime, nfShortDate, nfLongDate,
|
||||
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM ]
|
||||
then
|
||||
for Result := 0 to Count-1 do begin
|
||||
item := Items[Result];
|
||||
if (item <> nil) and (item.NumFormat = ANumFormat) then
|
||||
exit;
|
||||
end;
|
||||
*)
|
||||
if (ANumFormat = nfFmtDateTime) then begin
|
||||
fmt := lowercase(AFormatString);
|
||||
for Result := Count-1 downto 0 do begin
|
||||
@ -3054,6 +2900,17 @@ begin
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
{ Determines whether the format attributed to the given cell is already
|
||||
contained in the list and returns its list index. }
|
||||
function TsCustomNumFormatList.FindFormatOf(AFormatCell: PCell): integer;
|
||||
begin
|
||||
if AFormatCell = nil then
|
||||
Result := -1
|
||||
else
|
||||
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr,
|
||||
AFormatCell^.Decimals, AFormatCell^.CurrencySymbol);
|
||||
end;
|
||||
|
||||
{ Determines the format string to be written into the spreadsheet file.
|
||||
Needs to be overridden if the format strings are different from the fpc
|
||||
convention. }
|
||||
@ -3263,17 +3120,6 @@ procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
|
||||
begin
|
||||
// to be overridden
|
||||
end;
|
||||
(*
|
||||
var
|
||||
isLong, isAMPM, isInterval: Boolean;
|
||||
decs: Byte;
|
||||
begin
|
||||
if ACell^.NumberFormat = nfFmtDateTime then begin
|
||||
decs := CountDecs(ACell^.NumberFormatStr, ['0', 'z', 'Z']);
|
||||
// if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
|
||||
ACell^.Decimals := decs;
|
||||
end;
|
||||
end; *)
|
||||
|
||||
{ Each descendent should define its own default formats, if any.
|
||||
Always add the normal, unformatted style first to speed things up. }
|
||||
@ -3442,42 +3288,7 @@ begin
|
||||
Inc(StrPos);
|
||||
end;
|
||||
end;
|
||||
(*
|
||||
function TsCustomSpreadWriter.FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): string;
|
||||
{ We use RGB bytes here, but please note that these are physically written
|
||||
to XLS file as ABGR (where A is 0) }
|
||||
begin
|
||||
|
||||
case AColor of
|
||||
scBlack: Result := '000000';
|
||||
scWhite: Result := 'FFFFFF';
|
||||
scRed: Result := 'FF0000';
|
||||
scGREEN: Result := '00FF00';
|
||||
scBLUE: Result := '0000FF';
|
||||
scYELLOW: Result := 'FFFF00';
|
||||
scMAGENTA: Result := 'FF00FF';
|
||||
scCYAN: Result := '00FFFF';
|
||||
scDarkRed: Result := '800000';
|
||||
scDarkGreen:Result := '008000';
|
||||
scDarkBlue: Result := '000080';
|
||||
scOLIVE: Result := '808000';
|
||||
scPURPLE: Result := '800080';
|
||||
scTEAL: Result := '008080';
|
||||
scSilver: Result := 'C0C0C0';
|
||||
scGrey: Result := '808080';
|
||||
//
|
||||
scGrey10pct:Result := 'E6E6E6';
|
||||
scGrey20pct:Result := 'CCCCCC';
|
||||
scOrange: Result := 'FFA500';
|
||||
scDarkBrown:Result := 'A0522D';
|
||||
scBrown: Result := 'CD853F';
|
||||
scBeige: Result := 'F5F5DC';
|
||||
scWheat: Result := 'F5DEB3';
|
||||
//
|
||||
scRGBCOLOR: Result := Format('%x%x%x', [ARGBColor.Red div $100, ARGBColor.Green div $100, ARGBColor.Blue div $100]);
|
||||
end;
|
||||
end;
|
||||
*)
|
||||
{@@
|
||||
Helper function for the spreadsheet writers.
|
||||
|
||||
@ -3812,3 +3623,32 @@ finalization
|
||||
|
||||
end.
|
||||
|
||||
{ Strategy for handling of number formats:
|
||||
|
||||
Problem:
|
||||
For number formats, fpspreadsheet uses a syntax which is slightly different from
|
||||
the syntax that Excel uses in the xls files. Moreover, the file syntax can be
|
||||
different from file type to file type (biff2, for example, allows only a few
|
||||
predefined formats, while the number of allowed formats is unlimited (?) for
|
||||
biff8.
|
||||
|
||||
Number format handling in fpspreadsheet is implemented with the following
|
||||
concept in mind:
|
||||
|
||||
- Formats written into TsWorksheet cells always follow the fpspreadsheet syntax.
|
||||
The exception is for the format nfCustom for which the format strings are
|
||||
left untouched.
|
||||
|
||||
- For writing, the writer creates a TsNumFormatList which stores all formats
|
||||
in file syntax.
|
||||
- The built-in formats of the file types are coded in the file syntax.
|
||||
- The method "ConvertBeforeWriting" converts the cell formats from the
|
||||
fpspreadsheet to the file syntax.
|
||||
|
||||
- For reading, the reader creates another TsNumFormatList.
|
||||
- The built-in formats of the file types are coded again in file syntax.
|
||||
- The formats read from the file are added in file syntax.
|
||||
- After reading, the formats are converted to fpspreadsheet syntax
|
||||
("ConvertAfterReading").
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,12 @@ type
|
||||
TsBIFF2NumFormatList = class(TsCustomNumFormatList)
|
||||
protected
|
||||
procedure AddBuiltinFormats; override;
|
||||
procedure ConvertBeforeWriting(var AFormatString: String;
|
||||
var ANumFormat: TsNumberFormat; var ADecimals: Byte; var ACurrencySymbol: String); override;
|
||||
function FindFormatOf(AFormatCell: PCell): Integer; override;
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook);
|
||||
// function FormatStringForWriting(AIndex: Integer): String; override;
|
||||
function FormatStringForWriting(AIndex: Integer): String; override;
|
||||
end;
|
||||
|
||||
{ TsSpreadBIFF2Reader }
|
||||
@ -82,7 +85,7 @@ type
|
||||
|
||||
TsSpreadBIFF2Writer = class(TsSpreadBIFFWriter)
|
||||
private
|
||||
function FindXFIndex(ACell: PCell): Word;
|
||||
function FindXFIndex(ACell: PCell): Word;
|
||||
{ Record writing methods }
|
||||
procedure WriteBOF(AStream: TStream);
|
||||
procedure WriteCellFormatting(AStream: TStream; ACell: PCell; XFIndex: Word);
|
||||
@ -100,7 +103,7 @@ type
|
||||
procedure WriteXFRecords(AStream: TStream);
|
||||
protected
|
||||
procedure CreateNumFormatList; override;
|
||||
procedure FixFormat(ACell: PCell); override;
|
||||
procedure ListAllFormattingStyles; override;
|
||||
procedure ListAllNumFormats; override;
|
||||
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override;
|
||||
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
|
||||
@ -172,19 +175,24 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsBIFF2NumFormatList.AddBuiltinFormats;
|
||||
var
|
||||
ds, ts, cs: string;
|
||||
begin
|
||||
ds := DefaultFormatSettings.DecimalSeparator;
|
||||
ts := DefaultFormatSettings.ThousandSeparator;
|
||||
cs := DefaultFormatSettings.CurrencyString;
|
||||
AddFormat( 0, '', nfGeneral);
|
||||
AddFormat( 1, '0', nfFixed, 0);
|
||||
AddFormat( 2, '0.00', nfFixed, 2);
|
||||
AddFormat( 3, '#,##0', nfFixedTh, 0);
|
||||
AddFormat( 4, '#,##0.00', nfFixedTh, 2);
|
||||
AddFormat( 5, '"$"#,##0_);("$"#,##0)', nfCurrency, 0);
|
||||
AddFormat( 6, '"$"#,##0_);[Red]("$"#,##0)', nfCurrencyRed, 2);
|
||||
AddFormat( 7, '"$"#,##0.00_);("$"#,##0.00)', nfCurrency, 0);
|
||||
AddFormat( 8, '"$"#,##0.00_);[Red]("$"#,##0.00)', nfCurrency, 2);
|
||||
AddFormat( 2, '0'+ds+'00', nfFixed, 2); // 0.00
|
||||
AddFormat( 3, '#'+ts+'##0', nfFixedTh, 0); // #,##0
|
||||
AddFormat( 4, '#'+ts+'##0'+ds+'00', nfFixedTh, 2); // #,##0.00
|
||||
AddFormat( 5, UTF8ToAnsi('"'+cs+'"#'+ts+'##0_);("'+cs+'"#'+ts+'##0)'), nfCurrency, 0);
|
||||
AddFormat( 6, UTF8ToAnsi('"'+cs+'"#'+ts+'##0_);[Red]("'+cs+'"#'+ts+'##0)'), nfCurrencyRed, 2);
|
||||
AddFormat( 7, UTF8ToAnsi('"'+cs+'"#'+ts+'##0'+ds+'00_);("'+cs+'"#'+ts+'##0'+ds+'00)'), nfCurrency, 0);
|
||||
AddFormat( 8, UTF8ToAnsi('"'+cs+'"#'+ts+'##0'+ds+'00_);[Red]("'+cs+'"#'+ts+'##0'+ds+'00)'), nfCurrency, 2);
|
||||
AddFormat( 9, '0%', nfPercentage, 0);
|
||||
AddFormat(10, '0.00%', nfPercentage, 2);
|
||||
AddFormat(11, '0.00E+00', nfExp, 2);
|
||||
AddFormat(10, '0'+ds+'00%', nfPercentage, 2);
|
||||
AddFormat(11, '0'+ds+'00E+00', nfExp, 2);
|
||||
AddFormat(12, 'M/D/YY', nfShortDate);
|
||||
AddFormat(13, 'D-MMM-YY', nfLongDate);
|
||||
AddFormat(14, 'D-MMM', nfFmtDateTime);
|
||||
@ -199,40 +207,126 @@ begin
|
||||
FNextFormatIndex := 21; // not needed - there are not user-defined formats
|
||||
end;
|
||||
|
||||
{ Creates formatting strings that are written into the file. }
|
||||
(*
|
||||
function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
||||
|
||||
procedure TsBIFF2NumFormatList.ConvertBeforeWriting(var AFormatString: String;
|
||||
var ANumFormat: TsNumberFormat; var ADecimals: Byte; var ACurrencySymbol: String);
|
||||
var
|
||||
ds, ts, cs: string;
|
||||
fmt: String;
|
||||
begin
|
||||
ds := DefaultFormatSettings.DecimalSeparator;
|
||||
ts := DefaultFormatSettings.ThousandSeparator;
|
||||
cs := DefaultFormatSettings.CurrencyString;
|
||||
case AIndex of
|
||||
0: Result := 'General';
|
||||
1: Result := '0';
|
||||
2: Result := '0' + ds + '00'; // 0.00
|
||||
3: Result := '#' + ts + '#0'; // #,##0
|
||||
4: Result := '#' + ts + '#0' + ds + '0'; // #,##0.00
|
||||
5: Result := UTF8ToAnsi(Format('"%s"#%s##0_);("%s"#%s##0)', [cs, ts, cs, ts]));
|
||||
6: Result := UTF8ToAnsi(Format('"%s"#%s##0_);[Red]("%s"#%s##0)', [cs, ts, cs, ts]));
|
||||
7: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
|
||||
8: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);[Red]("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
|
||||
9: Result := '0%';
|
||||
10: Result := '0' + ds + '00%'; // 0.00%
|
||||
11: Result := '0' + ds + '00E+00'; // 0.00E+00
|
||||
12: Result := 'm/d/yy';
|
||||
13: Result := 'd-mmm-yy';
|
||||
14: Result := 'd-mmm';
|
||||
15: Result := 'mmm-yy';
|
||||
16: Result := 'h:mm AM/PM';
|
||||
17: Result := 'h:mm:ss AM/PM';
|
||||
18: Result := 'h:mm';
|
||||
19: Result := 'h:mm:ss';
|
||||
20: Result := 'm/d/yy h:mm';
|
||||
case ANumFormat of
|
||||
nfGeneral:
|
||||
;
|
||||
nfFixed, nfFixedTh, nfPercentage, nfExp,
|
||||
nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed:
|
||||
if ADecimals > 0 then ADecimals := 2;
|
||||
nfSci:
|
||||
begin
|
||||
if ADecimals > 0 then ADecimals := 2;
|
||||
ANumFormat := nfExp;
|
||||
end;
|
||||
nfFmtDateTime:
|
||||
begin
|
||||
fmt := lowercase(AFormatString);
|
||||
if (fmt = 'd-mm') or (fmt = 'd/mm') or
|
||||
(fmt = 'dd-mm') or (fmt = 'dd/mm') or
|
||||
(fmt = 'dd-mmm') or (fmt = 'dd/mmm')
|
||||
then
|
||||
AFormatString := 'D-MMM'
|
||||
else
|
||||
if (fmt = 'm-yy') or (fmt = 'm/yy') or
|
||||
(fmt = 'mm-yy') or (fmt = 'mm/yy') or
|
||||
(fmt = 'mmm-yy') or (fmt = 'mmm/yy') or
|
||||
(fmt = 'm-yyyy') or (fmt = 'm/yyyy') or
|
||||
(fmt = 'mm-yyyy') or (fmt = 'mm/yyyy') or
|
||||
(fmt = 'mmm-yyyy') or (fmt = 'mmm-yyyy')
|
||||
then
|
||||
AFormatString := 'MMM-YY'
|
||||
else
|
||||
if (copy(fmt, 1, 5) = 'nn:ss') or (copy(fmt, 1, 5) = 'mm:ss') or
|
||||
(copy(fmt, 1, 4) = 'n:ss') or (copy(fmt, 1, 4) = 'm:ss')
|
||||
then
|
||||
ANumFormat := nfLongTime
|
||||
else
|
||||
ANumFormat := nfShortDateTime;
|
||||
end;
|
||||
nfCustom, nfTimeInterval:
|
||||
begin
|
||||
ANumFormat := nfGeneral;
|
||||
AFormatString := '';
|
||||
ADecimals := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
*)
|
||||
|
||||
|
||||
function TsBIFF2NumFormatList.FindFormatOf(AFormatCell: PCell): Integer;
|
||||
var
|
||||
fmt: String;
|
||||
begin
|
||||
case AFormatCell^.NumberFormat of
|
||||
nfGeneral : Result := 0;
|
||||
nfFixed : Result := IfThen(AFormatCell^.Decimals = 0, 1, 2);
|
||||
nfFixedTh : Result := IfThen(AFormatCell^.Decimals = 0, 3, 4);
|
||||
nfCurrency,
|
||||
nfCurrencyDash : Result := IfThen(AFormatCell^.Decimals = 0, 5, 7);
|
||||
nfCurrencyRed,
|
||||
nfCurrencyDashRed: Result := IfThen(AFormatCell^.Decimals = 0, 6, 8);
|
||||
nfPercentage : Result := IfThen(AFormatCell^.Decimals = 0, 9, 10);
|
||||
nfExp, nfSci : Result := 11;
|
||||
nfShortDate : Result := 12;
|
||||
nfLongDate : Result := 13;
|
||||
nfShortTimeAM : Result := 16;
|
||||
nfLongTimeAM : Result := 17;
|
||||
nfShortTime : Result := 18;
|
||||
nfLongTime : Result := 19;
|
||||
nfShortDateTime : Result := 20;
|
||||
nfFmtDateTime : begin
|
||||
fmt := lowercase(AFormatCell^.NumberFormatStr);
|
||||
if (fmt = 'd-mmm') or (fmt = 'd/mmm') or
|
||||
(fmt = 'd-mm') or (fmt = 'd/mm') or
|
||||
(fmt = 'dd-mm') or (fmt = 'dd/mm') or
|
||||
(fmt = 'dd-mmm') or (fmt = 'dd/mmm')
|
||||
then
|
||||
Result := 14
|
||||
else
|
||||
if (fmt = 'mmm-yy') or (fmt = 'mmm/yy') or
|
||||
(fmt = 'mm-yy') or (fmt = 'mm/yy') or
|
||||
(fmt = 'm-yy') or (fmt = 'm/y') or
|
||||
(fmt = 'mmm-yyyy') or (fmt = 'mmm/yyyy') or
|
||||
(fmt = 'mm-yyyy') or (fmt = 'mm/yyyy') or
|
||||
(fmt = 'm-yyyy') or (fmt = 'm/yyyy')
|
||||
then
|
||||
Result := 15
|
||||
else
|
||||
if (fmt = 'nn:ss') or (fmt = 'mm:ss') or
|
||||
(fmt = 'n:ss') or (fmt = 'm:ss')
|
||||
then
|
||||
Result := 19
|
||||
else
|
||||
if (fmt = 'nn:ss.z') or (fmt = 'mm:ss.z') or
|
||||
(fmt = 'n:ss.z') or (fmt = 'm:ss.z') or
|
||||
(fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or
|
||||
(fmt = 'n:ss.zzz') or (fmt = 'm:ss.zzz')
|
||||
then
|
||||
Result := 19
|
||||
else
|
||||
Result := 20;
|
||||
end;
|
||||
nfCustom,
|
||||
nfTimeInterval : Result := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Creates formatting strings that are written into the file. These are the
|
||||
strings in the format list. The only exception is the nfGeneral entry which
|
||||
is written as "General". }
|
||||
function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
||||
begin
|
||||
Result := inherited FormatStringForWriting(AIndex);
|
||||
if Result = '' then
|
||||
Result := 'General';
|
||||
end;
|
||||
|
||||
|
||||
{ TsSpreadBIFF2Reader }
|
||||
|
||||
@ -707,57 +801,62 @@ end;
|
||||
|
||||
function TsSpreadBIFF2Writer.FindXFIndex(ACell: PCell): Word;
|
||||
var
|
||||
i: Integer;
|
||||
lIndex: Integer;
|
||||
lCell: TCell;
|
||||
begin
|
||||
// First try the fast methods for default formats
|
||||
if ACell^.UsedFormattingFields = [] then
|
||||
Result := 15
|
||||
else begin
|
||||
// If not, then we need to search in the list of dynamic formats
|
||||
i := 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.
|
||||
// And for BIFF2, there is only a limited number of formats.
|
||||
lCell := ACell^;
|
||||
with lCell do 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;
|
||||
lIndex := FindFormattingInList(@lCell);
|
||||
|
||||
// Carefully check the index
|
||||
if (i < 0) or (i > Length(FFormattingStyles)) then
|
||||
if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then
|
||||
raise Exception.Create('[TsSpreadBIFF2Writer.WriteXFIndex] Invalid Index, this should not happen!');
|
||||
Result := FFormattingStyles[i].Row;
|
||||
Result := FFormattingStyles[lIndex].Row;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF2Writer.FixFormat(ACell: PCell);
|
||||
procedure TsSpreadBIFF2Writer.ListAllFormattingStyles;
|
||||
var
|
||||
j: Integer;
|
||||
i: Integer;
|
||||
begin
|
||||
case ACell.NumberFormat of
|
||||
nfExp:
|
||||
if ACell.Decimals <> 2 then begin
|
||||
ACell.Decimals := 2;
|
||||
ACell.CurrencySymbol := '';
|
||||
ACell.NumberFormatStr := '0.00E+00';
|
||||
end;
|
||||
nfSci:
|
||||
begin
|
||||
ACell.NumberFormat := nfExp;
|
||||
ACell.NumberFormatStr := '0.00E+00';
|
||||
ACell.Decimals := 2;
|
||||
ACell.CurrencySymbol := '';
|
||||
end;
|
||||
nfFmtDateTime:
|
||||
begin
|
||||
j := NumFormatList.Find(ACell);
|
||||
if j = -1 then ACell.NumberFormat := nfLongTime;
|
||||
end;
|
||||
nfCustom:
|
||||
ACell.NumberFormat := nfGeneral;
|
||||
end;
|
||||
inherited ListAllFormattingStyles;
|
||||
|
||||
for i:=0 to High(FFormattingStyles) do
|
||||
FNumFormatList.ConvertBeforeWriting(
|
||||
FFormattingStyles[i].NumberFormatStr,
|
||||
FFormattingStyles[i].NumberFormat,
|
||||
FFormattingStyles[i].Decimals,
|
||||
FFormattingStyles[i].CurrencySymbol
|
||||
);
|
||||
end;
|
||||
|
||||
{ Builds up the list of number formats to be written to the biff2 file.
|
||||
Unlike biff5+ no formats are added here because biff2 supports only 21
|
||||
standard formats; these formats have been added by the NumFormatList's
|
||||
AddBuiltInFormats. }
|
||||
procedure TsSpreadBIFF2Writer.ListAllNumFormats;
|
||||
begin
|
||||
// Nothing to do. All formats have already been added by the NumFormatList.
|
||||
// Nothing to do here.
|
||||
end;
|
||||
|
||||
{
|
||||
Attaches cell formatting data for the given cell to the current record.
|
||||
Is called from all writing methods of cell contents.
|
||||
}
|
||||
{ Attaches cell formatting data for the given cell to the current record.
|
||||
Is called from all writing methods of cell contents. }
|
||||
procedure TsSpreadBIFF2Writer.WriteCellFormatting(AStream: TStream; ACell: PCell;
|
||||
XFIndex: Word);
|
||||
var
|
||||
@ -1002,17 +1101,9 @@ begin
|
||||
|
||||
// Now apply the modifications.
|
||||
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
|
||||
j := NumFormatList.Find(@FFormattingStyles[i]);
|
||||
if j > -1 then begin
|
||||
j := NumFormatList.FindFormatOf(@FFormattingStyles[i]);
|
||||
if j > -1 then
|
||||
lFormatIndex := NumFormatList[j].Index;
|
||||
{
|
||||
// BIFF2 can only handle the 21 built-in formats. Here we find replacements
|
||||
// for the others.
|
||||
case NumFormatList[j].NumFormat of
|
||||
nfSci : lFormatIndex := 11; // Exp
|
||||
nfFmtDateTime : if lFormatIndex > 20 then lFormatIndex := 19;
|
||||
end;}
|
||||
end;
|
||||
end;
|
||||
|
||||
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
|
||||
@ -1162,26 +1253,6 @@ begin
|
||||
AStream.WriteByte(len); // AnsiString, char count in 1 byte
|
||||
AStream.WriteBuffer(s[1], len); // String data
|
||||
end;
|
||||
(*
|
||||
procedure TsSpreadBIFF2Writer.WriteFormat(AStream: TStream; AFormatCode: String);
|
||||
var
|
||||
len: Integer;
|
||||
s: AnsiString;
|
||||
begin
|
||||
if AFormatCode = '' then
|
||||
exit;
|
||||
|
||||
s := AFormatCode;
|
||||
len := Length(s);
|
||||
|
||||
{ BIFF record header }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
|
||||
AStream.WriteWord(WordToLE(len + 1));
|
||||
|
||||
{ Write format string }
|
||||
AStream.WriteByte(len);
|
||||
AStream.WriteBuffer(s[1], len);
|
||||
end; *)
|
||||
|
||||
procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream);
|
||||
begin
|
||||
@ -1189,83 +1260,6 @@ begin
|
||||
AStream.WriteWord(WordToLE(2));
|
||||
AStream.WriteWord(WordToLE(21)); // there are 21 built-in formats
|
||||
end;
|
||||
(*
|
||||
procedure TsSpreadBIFF2Writer.WriteFormats(AStream: TStream);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
WriteFormatCount(AStream);
|
||||
for i:=0 to High(NUMFORMAT_BIFF2) do
|
||||
WriteFormat(AStream, NUMFORMAT_BIFF2[i]);
|
||||
end;*)
|
||||
(*
|
||||
var
|
||||
ds, ts: Char; //decimal separator, thousand separator
|
||||
begin
|
||||
ds := DefaultFormatSettings.DecimalSeparator;
|
||||
ts := DefaultFormatSettings.ThousandSeparator;
|
||||
{ 0} WriteFormat(AStream, 'General'); // 0
|
||||
{ 1} WriteFormat(AStream, '0');
|
||||
{ 2} WriteFormat(AStream, '0'+ds+'00'); // 0.00
|
||||
{ 3} WriteFormat(AStream, '#'+ts+'##0'); // #,##0
|
||||
{ 4} WriteFormat(AStream, '#'+ts+'##0'+ds+'00'); // #,##0.00
|
||||
{ 5} WriteFormat(AStream, '"$"#'+ts+'##0_);("$"#'+ts+'##0)');
|
||||
{ 6} WriteFormat(AStream, '"$"#'+ts+'##0_);[Red]("$"#'+ts+'##0)');
|
||||
{ 7} WriteFormat(AStream, '"$"#'+ts+'##0'+ds+'00_);("$"#'+ts+'##0'+ds+'00)');
|
||||
{ 8} WriteFormat(AStream, '"$"#'+ts+'##0'+ds+'00_);[Red]("$"#'+ts+'##0'+ds+'00)');
|
||||
{ 9} WriteFormat(AStream, '0%');
|
||||
{10} WriteFormat(AStream, '0'+ds+'00%'); // 0.00%
|
||||
{11} WriteFormat(AStream, '0'+ds+'00E+00'); // 0.00E+00
|
||||
{12} WriteFormat(AStream, 'm/d/yy');
|
||||
{13} WriteFormat(AStream, 'd-mmm-yy');
|
||||
{14} WriteFormat(AStream, 'd-mmm');
|
||||
{15} WriteFormat(AStream, 'mmm-yy');
|
||||
{16} WriteFormat(AStream, 'h:mm AM/PM');
|
||||
{17} WriteFormat(AStream, 'h:mm:ss AM/PM');
|
||||
{18} WriteFormat(AStream, 'h:mm');
|
||||
{19} WriteFormat(AStream, 'h:mm:ss');
|
||||
{20} WriteFormat(AStream, 'm/d/yy h:mm');
|
||||
|
||||
{ # TODO: locale support
|
||||
0 => 'GENERAL',
|
||||
1 => '0',
|
||||
2 => '0.00',
|
||||
3 => '#,##0',
|
||||
4 => '#,##0.00',
|
||||
5 => '"$"#,##0_);("$"#,##0)',
|
||||
6 => '"$"#,##0_);[Red]("$"#,##0)',
|
||||
7 => '"$"#,##0.00_);("$"#,##0.00)',
|
||||
8 => '"$"#,##0.00_);[Red]("$"#,##0.00)',
|
||||
9 => '0%',
|
||||
10 => '0.00%',
|
||||
11 => '0.00E+00',
|
||||
12 => '# ?/?',
|
||||
13 => '# ??/??',
|
||||
14 => 'M/D/YY',
|
||||
15 => 'D-MMM-YY',
|
||||
16 => 'D-MMM',
|
||||
17 => 'MMM-YY',
|
||||
18 => 'h:mm AM/PM',
|
||||
19 => 'h:mm:ss AM/PM',
|
||||
20 => 'h:mm',
|
||||
21 => 'h:mm:ss',
|
||||
22 => 'M/D/YY h:mm',
|
||||
37 => '_(#,##0_);(#,##0)',
|
||||
38 => '_(#,##0_);[Red](#,##0)',
|
||||
39 => '_(#,##0.00_);(#,##0.00)',
|
||||
40 => '_(#,##0.00_);[Red](#,##0.00)',
|
||||
41 => '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
|
||||
42 => '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
|
||||
43 => '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
|
||||
44 => '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
|
||||
45 => 'mm:ss',
|
||||
46 => '[h]:mm:ss',
|
||||
47 => 'mm:ss.0',
|
||||
48 => '##0.0E+0',
|
||||
49 => '@',
|
||||
}
|
||||
end;
|
||||
*)
|
||||
|
||||
{
|
||||
Writes an Excel 2 FORMULA record
|
||||
|
@ -1119,7 +1119,7 @@ begin
|
||||
|
||||
// Now apply the modifications.
|
||||
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
|
||||
j := NumFormatList.Find(@FFormattingStyles[i]);
|
||||
j := NumFormatList.FindFormatOf(@FFormattingStyles[i]);
|
||||
if j > -1 then
|
||||
lFormatIndex := NumFormatList[j].Index;
|
||||
end;
|
||||
|
@ -307,7 +307,7 @@ begin
|
||||
|
||||
// Now apply the modifications.
|
||||
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
|
||||
j := NumFormatList.Find(@FFormattingStyles[i]);
|
||||
j := NumFormatList.FindFormatOf(@FFormattingStyles[i]);
|
||||
if j > -1 then
|
||||
lFormatIndex := NumFormatList[j].Index;
|
||||
end;
|
||||
|
@ -348,14 +348,7 @@ type
|
||||
TsBIFFNumFormatList = class(TsCustomNumFormatList)
|
||||
protected
|
||||
procedure AddBuiltinFormats; override;
|
||||
{
|
||||
procedure ConvertAfterReading(AFormatIndex: Integer; var AFormatString: String;
|
||||
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
|
||||
var ACurrencySymbol: String); override;
|
||||
procedure ConvertBeforeWriting(var AFormatString: String); override;
|
||||
}
|
||||
public
|
||||
// function FormatStringForWriting(AIndex: Integer): String; override;
|
||||
end;
|
||||
|
||||
{ TsSpreadBIFFReader }
|
||||
@ -589,138 +582,13 @@ begin
|
||||
FFirstFormatIndexInFile := 164;
|
||||
FNextFormatIndex := 164;
|
||||
end;
|
||||
(*
|
||||
{ Considers some Excel specialities for format detection.
|
||||
The output values will be passed to fpc. }
|
||||
procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
|
||||
var AFormatString: String; var ANumFormat: TsNumberFormat;
|
||||
var ADecimals: Byte; var ACurrencySymbol: String);
|
||||
var
|
||||
fmt: String;
|
||||
{
|
||||
parser: TsNumFormatParser;
|
||||
sections: TsNumFormatSections;
|
||||
}
|
||||
begin
|
||||
|
||||
{
|
||||
AFormatString := 'hh:mm:ss.0 AM/PM'; //"€" #,##.0;[red]"$" -#,##.000;-';
|
||||
|
||||
parser := TsNumFormatParser.Create(Workbook, AFormatString);
|
||||
try
|
||||
fmt := parser.FormatString;
|
||||
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:
|
||||
The prefix "[$-F400]" before the formatting string means that the system's
|
||||
long time format string is used. }
|
||||
if (pos('[$-F400]', AFormatString) = 1) then begin
|
||||
ANumFormat := nfLongTime;
|
||||
AFormatString := ''; // will be replaced by system's format setting
|
||||
ADecimals := 0;
|
||||
exit;
|
||||
end;
|
||||
{ Excel often has the locale ID [$-409] (for Germany) in front of the format
|
||||
string. We currently ignore this because it confuses fpc. }
|
||||
if (pos('[$', fmt) = 1) then begin
|
||||
if (pos('h:mm:ss\', fmt) > 0) then begin
|
||||
// long time format
|
||||
if (pos('am/pm', fmt) > 0) or (pos('a/p',fmt) > 0) then begin
|
||||
ANumFormat := nfLongTimeAM;
|
||||
AFormatString := '';
|
||||
end else begin
|
||||
ANumFormat := nfLongTime;
|
||||
AFormatString := '';
|
||||
end;
|
||||
ADecimals := 0;
|
||||
exit;
|
||||
end;
|
||||
if (pos('h:mm\', fmt) > 0) then begin
|
||||
if (pos('am/pm', fmt) > 0) or (pos ('a/p', fmt) > 0) then begin
|
||||
ANumFormat := nfShortTimeAM;
|
||||
AFormatString := '';
|
||||
end else begin
|
||||
ANumFormat := nfShortTime;
|
||||
AFormatString := '';
|
||||
end;
|
||||
ADecimals := 0;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// TO DO: Analyze currency
|
||||
end;
|
||||
|
||||
inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals, ACurrencySymbol);
|
||||
end;
|
||||
*)
|
||||
(*
|
||||
{ Creates formatting strings that are written into the file. }
|
||||
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];
|
||||
case item.NumFormat of
|
||||
nfFmtDateTime:
|
||||
begin
|
||||
Result := lowercase(item.FormatString);
|
||||
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';
|
||||
end;
|
||||
FixN(Result);
|
||||
end;
|
||||
nfTimeInterval:
|
||||
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);
|
||||
Result := Copy(item.FormatString, 1, i) + '[RED]'+ Copy(item.FormatString, i+1, Length(item.FormatString));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
*)
|
||||
|
||||
{ TsSpreadBIFFReader }
|
||||
|
||||
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
inherited Create(AWorkbook);
|
||||
FXFList := TFPList.Create;
|
||||
@ -793,9 +661,18 @@ end;
|
||||
formats.
|
||||
Valid for BIFF5.BIFF8. Needs to be overridden for BIFF2. }
|
||||
procedure TsSpreadBIFFReader.CreateNumFormatList;
|
||||
var
|
||||
i: Integer;
|
||||
item: TsNumFormatData;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsBIFFNumFormatList.Create(Workbook);
|
||||
// Convert builtin formats to fps syntax
|
||||
for i:=0 to FNumFormatList.Count-1 do begin
|
||||
item := FNumFormatList[i];
|
||||
FNumFormatList.ConvertAfterReading(item.Index, item.FormatString,
|
||||
item.NumFormat, item.Decimals, item.CurrencySymbol);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Extracts a number out of an RK value.
|
||||
@ -1332,7 +1209,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TsSpreadBIFFWriter }
|
||||
|
||||
constructor TsSpreadBIFFWriter.Create(AWorkbook: TsWorkbook);
|
||||
|
Reference in New Issue
Block a user