You've already forked lazarus-ccr
fpspreadsheet: Fix crash of unit test. Still some number format detection issues.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3046 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -42,7 +42,6 @@ begin
|
||||
WriteLn('Row: ', CurCell^.Row, ' Col: ', CurCell^.Col, ' Value: ',
|
||||
UTF8ToAnsi(MyWorkSheet.ReadAsUTF8Text(CurCell^.Row, CurCell^.Col))
|
||||
);
|
||||
WriteLn(MyWorkbook.GetFont(CurCell^.FontIndex).Size-11);
|
||||
CurCell := MyWorkSheet.GetNextCell();
|
||||
end;
|
||||
|
||||
|
@ -75,6 +75,7 @@ begin
|
||||
MyWorksheet.WriteBorderLineStyle(5, 5, cbNorth, lsThick);
|
||||
|
||||
// F7, top border only, but different color
|
||||
MyWorksheet.WriteBorders(6, 5, [cbNorth]);
|
||||
MyWorksheet.WriteBorderColor(6, 5, cbNorth, scGreen);
|
||||
MyWorksheet.WriteUTF8Text(6, 5, 'top border green or red?');
|
||||
// Excel shows it to be red --> the upper border wins
|
||||
@ -200,6 +201,10 @@ begin
|
||||
inc(r);
|
||||
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
|
||||
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
|
||||
// NOTE: The upper option "MSZ" = "mm:ss.z" should result only in 1 decimal.
|
||||
// This is true for writing, but in reading always 3 decimals are displayed.
|
||||
// This is due to fpc's SysUtile.FormatDateTime which does not distinguish
|
||||
// both cases.
|
||||
|
||||
// Write formatted numbers
|
||||
number := 12345.67890123456789;
|
||||
|
@ -149,8 +149,8 @@
|
||||
<UnitName Value="fpspreadsheetgrid"/>
|
||||
<EditorIndex Value="2"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="83"/>
|
||||
<CursorPos X="15" Y="96"/>
|
||||
<TopLine Value="525"/>
|
||||
<CursorPos X="30" Y="533"/>
|
||||
<UsageCount Value="100"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit3>
|
||||
@ -220,15 +220,18 @@
|
||||
<Unit12>
|
||||
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
|
||||
<UnitName Value="Grids"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="2464"/>
|
||||
<CursorPos X="1" Y="2495"/>
|
||||
<TopLine Value="4852"/>
|
||||
<CursorPos X="16" Y="4884"/>
|
||||
<UsageCount Value="48"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="..\..\fpsutils.pas"/>
|
||||
<UnitName Value="fpsutils"/>
|
||||
<EditorIndex Value="8"/>
|
||||
<EditorIndex Value="9"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="614"/>
|
||||
<CursorPos X="23" Y="621"/>
|
||||
@ -263,7 +266,7 @@
|
||||
<EditorIndex Value="5"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="1747"/>
|
||||
<CursorPos X="1" Y="1764"/>
|
||||
<CursorPos X="25" Y="1779"/>
|
||||
<UsageCount Value="78"/>
|
||||
<Bookmarks Count="1">
|
||||
<Item0 X="1" Y="1761" ID="1"/>
|
||||
@ -298,7 +301,7 @@
|
||||
<Unit21>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<UnitName Value="xlsbiff5"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<EditorIndex Value="7"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="1363"/>
|
||||
<CursorPos X="1" Y="1364"/>
|
||||
@ -308,11 +311,10 @@
|
||||
<Unit22>
|
||||
<Filename Value="..\..\xlsbiff2.pas"/>
|
||||
<UnitName Value="xlsbiff2"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="7"/>
|
||||
<EditorIndex Value="8"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="664"/>
|
||||
<CursorPos X="30" Y="687"/>
|
||||
<CursorPos X="21" Y="677"/>
|
||||
<UsageCount Value="62"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit22>
|
||||
@ -577,47 +579,47 @@
|
||||
<JumpHistory Count="30" HistoryIndex="29">
|
||||
<Position1>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1755" Column="19" TopLine="1715"/>
|
||||
<Caret Line="1753" Column="1" TopLine="1738"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1964" Column="1" TopLine="1924"/>
|
||||
<Caret Line="1968" Column="1" TopLine="1928"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1210" Column="81" TopLine="1176"/>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="1959" Column="1" TopLine="1919"/>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="80" Column="21" TopLine="47"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="41" Column="1" TopLine="41"/>
|
||||
<Caret Line="1760" Column="1" TopLine="1744"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1753" Column="1" TopLine="1738"/>
|
||||
<Caret Line="95" Column="22" TopLine="75"/>
|
||||
</Position6>
|
||||
<Position7>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1968" Column="1" TopLine="1928"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position7>
|
||||
<Position8>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Caret Line="1524" Column="37" TopLine="1516"/>
|
||||
</Position8>
|
||||
<Position9>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="80" Column="21" TopLine="47"/>
|
||||
<Caret Line="1649" Column="21" TopLine="1622"/>
|
||||
</Position9>
|
||||
<Position10>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1760" Column="1" TopLine="1744"/>
|
||||
<Caret Line="1527" Column="3" TopLine="1524"/>
|
||||
</Position10>
|
||||
<Position11>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="95" Column="22" TopLine="75"/>
|
||||
<Caret Line="1758" Column="3" TopLine="1733"/>
|
||||
</Position11>
|
||||
<Position12>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
@ -625,75 +627,75 @@
|
||||
</Position12>
|
||||
<Position13>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1524" Column="37" TopLine="1516"/>
|
||||
<Caret Line="51" Column="19" TopLine="18"/>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1649" Column="21" TopLine="1622"/>
|
||||
<Caret Line="57" Column="11" TopLine="24"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1527" Column="3" TopLine="1524"/>
|
||||
<Caret Line="67" Column="13" TopLine="34"/>
|
||||
</Position15>
|
||||
<Position16>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1758" Column="3" TopLine="1733"/>
|
||||
<Caret Line="1394" Column="3" TopLine="1388"/>
|
||||
</Position16>
|
||||
<Position17>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Caret Line="1761" Column="3" TopLine="1738"/>
|
||||
</Position17>
|
||||
<Position18>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="51" Column="19" TopLine="18"/>
|
||||
<Caret Line="95" Column="75" TopLine="76"/>
|
||||
</Position18>
|
||||
<Position19>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="57" Column="11" TopLine="24"/>
|
||||
<Caret Line="1749" Column="8" TopLine="1747"/>
|
||||
</Position19>
|
||||
<Position20>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="67" Column="13" TopLine="34"/>
|
||||
<Caret Line="95" Column="55" TopLine="95"/>
|
||||
</Position20>
|
||||
<Position21>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1394" Column="3" TopLine="1388"/>
|
||||
<Caret Line="1748" Column="49" TopLine="1733"/>
|
||||
</Position21>
|
||||
<Position22>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1761" Column="3" TopLine="1738"/>
|
||||
<Caret Line="95" Column="55" TopLine="95"/>
|
||||
</Position22>
|
||||
<Position23>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="95" Column="75" TopLine="76"/>
|
||||
<Caret Line="1749" Column="8" TopLine="1747"/>
|
||||
</Position23>
|
||||
<Position24>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1749" Column="8" TopLine="1747"/>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="95" Column="55" TopLine="95"/>
|
||||
</Position25>
|
||||
<Position26>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1748" Column="49" TopLine="1733"/>
|
||||
</Position26>
|
||||
<Position27>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="95" Column="55" TopLine="95"/>
|
||||
</Position27>
|
||||
<Position28>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1749" Column="8" TopLine="1747"/>
|
||||
</Position28>
|
||||
<Position29>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<Caret Line="1370" Column="1" TopLine="1358"/>
|
||||
</Position29>
|
||||
<Position30>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="..\..\xlscommon.pas"/>
|
||||
<Caret Line="39" Column="3" TopLine="10"/>
|
||||
</Position25>
|
||||
<Position26>
|
||||
<Filename Value="..\..\xlsbiff2.pas"/>
|
||||
<Caret Line="677" Column="21" TopLine="664"/>
|
||||
</Position26>
|
||||
<Position27>
|
||||
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
|
||||
<Caret Line="524" Column="27" TopLine="524"/>
|
||||
</Position27>
|
||||
<Position28>
|
||||
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
</Position28>
|
||||
<Position29>
|
||||
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
|
||||
<Caret Line="1787" Column="3" TopLine="1779"/>
|
||||
</Position29>
|
||||
<Position30>
|
||||
<Filename Value="..\..\xlsbiff8.pas"/>
|
||||
<Caret Line="1779" Column="25" TopLine="1747"/>
|
||||
</Position30>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
@ -723,6 +725,15 @@
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<BreakPoints Count="1">
|
||||
<Item1>
|
||||
<Kind Value="bpkSource"/>
|
||||
<WatchScope Value="wpsLocal"/>
|
||||
<WatchKind Value="wpkWrite"/>
|
||||
<Source Value="..\..\fpspreadsheetgrid.pas"/>
|
||||
<Line Value="1790"/>
|
||||
</Item1>
|
||||
</BreakPoints>
|
||||
<Watches Count="2">
|
||||
<Item1>
|
||||
<Expression Value="acol"/>
|
||||
|
@ -46,6 +46,14 @@ type
|
||||
dm1904 {e.g. Quattro Pro,Mac Excel compatibility}
|
||||
);
|
||||
|
||||
{ TsSpreadOpenDocNumFormatList }
|
||||
TsSpreadOpenDocNumFormatList = class(TsCustomNumFormatList)
|
||||
protected
|
||||
procedure AddBuiltinFormats; override;
|
||||
public
|
||||
// function FormatStringForWriting(AIndex: Integer): String; override;
|
||||
end;
|
||||
|
||||
{ TsSpreadOpenDocReader }
|
||||
|
||||
TsSpreadOpenDocReader = class(TsCustomSpreadReader)
|
||||
@ -58,6 +66,7 @@ type
|
||||
// Figures out what the base year for times in this file (dates are unambiguous)
|
||||
procedure ReadDateMode(SpreadSheetNode: TDOMNode);
|
||||
protected
|
||||
procedure CreateNumFormatList; override;
|
||||
{ Record writing methods }
|
||||
procedure ReadFormula(ARow : Word; ACol : Word; ACellNode: TDOMNode);
|
||||
procedure ReadLabel(ARow : Word; ACol : Word; ACellNode: TDOMNode);
|
||||
@ -79,6 +88,8 @@ type
|
||||
// Streams with the contents of files
|
||||
FSMeta, FSSettings, FSStyles, FSContent, FSMimetype: TStringStream;
|
||||
FSMetaInfManifest: TStringStream;
|
||||
// Helpers
|
||||
procedure CreateNumFormatList; override;
|
||||
// Routines to write those files
|
||||
procedure WriteMimetype;
|
||||
procedure WriteMetaInfManifest;
|
||||
@ -159,8 +170,23 @@ const
|
||||
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
|
||||
|
||||
|
||||
{ TsSpreadOpenDocNumFormatList }
|
||||
|
||||
procedure TsSpreadOpenDocNumFormatList.AddBuiltinFormats;
|
||||
begin
|
||||
// to be filled later...
|
||||
end;
|
||||
|
||||
{ TsSpreadOpenDocReader }
|
||||
|
||||
{ Creates the correct version of the number format list.
|
||||
It is for ods file formats. }
|
||||
procedure TsSpreadOpenDocReader.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
|
||||
end;
|
||||
|
||||
function TsSpreadOpenDocReader.GetAttrValue(ANode : TDOMNode; AAttrName : string) : string;
|
||||
var
|
||||
i : integer;
|
||||
@ -442,6 +468,12 @@ end;
|
||||
|
||||
{ TsSpreadOpenDocWriter }
|
||||
|
||||
procedure TsSpreadOpenDocWriter.CreateNumFormatList;
|
||||
begin
|
||||
FreeAndNil(FNumFormatList);
|
||||
FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocWriter.WriteMimetype;
|
||||
begin
|
||||
FMimetype := 'application/vnd.oasis.opendocument.spreadsheet';
|
||||
|
@ -125,7 +125,18 @@ type
|
||||
|
||||
{@@ Describes the type of content of a cell on a TsWorksheet }
|
||||
TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber,
|
||||
cctUTF8String, cctDateTime);
|
||||
cctUTF8String, cctDateTime, cctBool, cctError);
|
||||
|
||||
{@@ Error code values }
|
||||
TErrorValue = (
|
||||
errEmptyIntersection, // #NULL!
|
||||
errDivideByZero, // #DIV/0!
|
||||
errWrongType, // #VALUE!
|
||||
errIllegalRef, // #REF!
|
||||
errWrongName, // #NAME?
|
||||
errOverflow, // #NUM!
|
||||
errArgNotAvail // #N/A
|
||||
);
|
||||
|
||||
{@@ List of possible formatting fields }
|
||||
TsUsedFormattingField = (uffTextRotation, uffFont, uffBold, uffBorder,
|
||||
@ -278,6 +289,8 @@ type
|
||||
NumberValue: double;
|
||||
UTF8StringValue: ansistring;
|
||||
DateTimeValue: TDateTime;
|
||||
BoolValue: Boolean;
|
||||
StatusValue: Byte;
|
||||
{ Formatting fields }
|
||||
UsedFormattingFields: TsUsedFormattingFields;
|
||||
FontIndex: Integer;
|
||||
@ -369,8 +382,10 @@ type
|
||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||
AFormatString: String); overload;
|
||||
procedure WriteBlank(ARow, ACol: Cardinal);
|
||||
procedure WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
|
||||
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
||||
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
||||
procedure WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
|
||||
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
||||
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
|
||||
{ Writing of cell attributes }
|
||||
@ -688,6 +703,15 @@ resourcestring
|
||||
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
|
||||
lpUnknownSpreadsheetFormat = 'unknown format';
|
||||
lpInvalidFontIndex = 'Invalid font index';
|
||||
lpTRUE = 'TRUE';
|
||||
lpFALSE = 'FALSE';
|
||||
lpErrEmptyIntersection = '#NULL!';
|
||||
lpErrDivideByZero = '#DIV/0!';
|
||||
lpErrWrongType = '#VALUE!';
|
||||
lpErrIllegalRef = '#REF!';
|
||||
lpErrWrongName = '#NAME?';
|
||||
lpErrOverflow = '#NUM!';
|
||||
lpErrArgNotAvail = '#N/A';
|
||||
|
||||
var
|
||||
{@@
|
||||
@ -1173,6 +1197,18 @@ begin
|
||||
Result := UTF8StringValue;
|
||||
cctDateTime:
|
||||
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
|
||||
cctBool:
|
||||
Result := IfThen(BoolValue, lpTRUE, lpFALSE);
|
||||
cctError:
|
||||
case TErrorValue(StatusValue and $0F) of
|
||||
errEmptyIntersection: Result := lpErrEmptyIntersection;
|
||||
errDivideByZero : Result := lpErrDivideByZero;
|
||||
errWrongType : Result := lpErrWrongType;
|
||||
errIllegalRef : Result := lpErrIllegalRef;
|
||||
errWrongName : Result := lpErrWrongName;
|
||||
errOverflow : Result := lpErrOverflow;
|
||||
errArgNotAvail : Result := lpErrArgNotAvail;
|
||||
end;
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
@ -1382,6 +1418,23 @@ begin
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Writes as boolean cell
|
||||
|
||||
@param ARow The row of the cell
|
||||
@param ACol The column of the cell
|
||||
@param AValue The boolean value
|
||||
}
|
||||
procedure TsWorksheet.WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
|
||||
var
|
||||
ACell: PCell;
|
||||
begin
|
||||
ACell := GetCell(ARow, ACol);
|
||||
ACell^.ContentType := cctBool;
|
||||
ACell^.BoolValue := AValue;
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Writes a date/time value to a determined cell
|
||||
|
||||
@ -1446,6 +1499,23 @@ begin
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Writes a cell with an error.
|
||||
|
||||
@param ARow The row of the cell
|
||||
@param ACol The column of the cell
|
||||
@param AValue The error code value
|
||||
}
|
||||
procedure TsWorksheet.WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
|
||||
var
|
||||
ACell: PCell;
|
||||
begin
|
||||
ACell := GetCell(ARow, ACol);
|
||||
ACell^.ContentType := cctError;
|
||||
ACell^.StatusValue := (ACell^.StatusValue and $F0) or ord(AValue);
|
||||
ChangedCell(ARow, ACol);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Writes a formula to a determined cell
|
||||
|
||||
@ -2553,8 +2623,12 @@ begin
|
||||
ANumFormat := nfShortDateTime
|
||||
else if isDate then
|
||||
ANumFormat := SHORT_LONG_DATE[isLongDate]
|
||||
else if isTime then
|
||||
ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
|
||||
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;
|
||||
|
@ -189,7 +189,7 @@ begin
|
||||
SollDateTimeStrings[i, 6] := FormatDateTime('dd/mmm', SollDateTimes[i]);
|
||||
SollDateTimeStrings[i, 7] := FormatDateTime('mmm/yy', SollDateTimes[i]);
|
||||
SollDateTimeStrings[i, 8] := FormatDateTime('nn:ss', SollDateTimes[i]);
|
||||
SollDateTimeStrings[i, 9] := TimeIntervalToString(SollDateTimes[i]);
|
||||
SollDateTimeStrings[i, 9] := FormatDateTime('[h]:mm:ss', SollDateTimes[i]);
|
||||
end;
|
||||
|
||||
// Column width
|
||||
|
@ -25,7 +25,7 @@ uses
|
||||
// Not using lazarus package as the user may be working with multiple versions
|
||||
// Instead, add .. to unit search path
|
||||
Classes, SysUtils, fpcunit, testutils, testregistry,
|
||||
fpsallformats, fpspreadsheet, xlsbiff8 {and a project requirement for lclbase for utf8 handling},
|
||||
fpsallformats, fpsutils, fpspreadsheet, xlsbiff8 {and a project requirement for lclbase for utf8 handling},
|
||||
testsutility;
|
||||
|
||||
var
|
||||
|
Binary file not shown.
@ -130,37 +130,6 @@ var
|
||||
$00FFFF // $07: cyan
|
||||
);
|
||||
|
||||
(*
|
||||
{ These are the built-in number formats of BIFF2. They are not stored in
|
||||
the file. Note that, compared to the BUFF5+ built-in formats, two formats
|
||||
are missing and the indexes are offset by 2 after #11.
|
||||
It seems that BIFF2 can handle only these 21 formats. The other formats
|
||||
available in fpspreadsheet are mapped to these 21 formats such that least
|
||||
destruction is made. }
|
||||
NUMFORMAT_BIFF2: array[0..20] of string = (
|
||||
'General', // 0
|
||||
'0',
|
||||
'0.00',
|
||||
'#,##0',
|
||||
'#,##0.00',
|
||||
'"$"#,##0_);("$"#,##0)', // 5
|
||||
'"$"#,##0_);[Red]("$"#,##0)',
|
||||
'"$"#,##0.00_);("$"#,##0.00)',
|
||||
'"$"#,##0.00_);[Red]("$"#,##0.00)',
|
||||
'0%',
|
||||
'0.00%', // 10
|
||||
'0.00E+00',
|
||||
'M/D/YY',
|
||||
'D-MMM-YY',
|
||||
'D-MMM',
|
||||
'MMM-YY', // 15
|
||||
'h:mm AM/PM',
|
||||
'h:mm:ss AM/PM',
|
||||
'h:mm',
|
||||
'h:mm:ss',
|
||||
'M/D/YY h:mm' // 20
|
||||
);
|
||||
*)
|
||||
|
||||
implementation
|
||||
|
||||
@ -193,36 +162,7 @@ const
|
||||
INT_EXCEL_SHEET = $0010;
|
||||
INT_EXCEL_CHART = $0020;
|
||||
INT_EXCEL_MACRO_SHEET = $0040;
|
||||
(*
|
||||
{ FORMAT record constants for BIFF2 }
|
||||
// Subset of the built-in formats for US Excel,
|
||||
// including those needed for date/time output
|
||||
FORMAT_GENERAL = 0; //general/default format
|
||||
FORMAT_FIXED_0_DECIMALS = 1; //fixed, 0 decimals
|
||||
FORMAT_FIXED_2_DECIMALS = 2; //fixed, 2 decimals
|
||||
FORMAT_FIXED_THOUSANDS_0_DECIMALS = 3; //fixed, w/ thousand separator, 0 decs
|
||||
FORMAT_FIXED_THOUSANDS_2_DECIMALS = 4; //fixed, w/ thousand separator, 2 decs
|
||||
FORMAT_CURRENCY_0_DECIMALS = 5; //currency (with currency symbol), 0 decs
|
||||
FORMAT_CURRENCY_2_DECIMALS = 7; //currency (with currency symbol), 2 decs
|
||||
FORMAT_PERCENT_0_DECIMALS = 9; //percent, 0 decimals
|
||||
FORMAT_PERCENT_2_DECIMALS = 10; //percent, 2 decimals
|
||||
FORMAT_EXP_2_DECIMALS = 11; //exponent, 2 decimals
|
||||
FORMAT_SCI_1_DECIMAL = 11; //scientific, 1 decimal -- not present in BIFF2 -- mapped to EXP_2_DECIMALS
|
||||
FORMAT_SHORT_DATE = 12; //short date
|
||||
FORMAT_DATE_DM = 14; //date D-MMM
|
||||
FORMAT_DATE_MY = 15; //date MMM-YYYY
|
||||
FORMAT_SHORT_TIME_AM = 16; //short time H:MM with AM
|
||||
FORMAT_LONG_TIME_AM = 17; //long time H:MM:SS with AM
|
||||
FORMAT_SHORT_TIME = 18; //short time H:MM
|
||||
FORMAT_LONG_TIME = 19; //long time H:MM:SS
|
||||
FORMAT_SHORT_DATETIME = 20; //short date+time
|
||||
{ The next three formats are not available in BIFF2. They should not be used
|
||||
when a file is to be saved in BIFF2. If it IS saved as BIFF2 the formats
|
||||
are mapped to FORMAT_LONG_TIME}
|
||||
FORMAT_TIME_MS = 19; //time MM:SS
|
||||
FORMAT_TIME_MSZ = 19; //time MM:SS.0
|
||||
FORMAT_TIME_INTERVAL = 19; //time [hh]:mm:ss, hh can be >24
|
||||
*)
|
||||
|
||||
|
||||
{ TsBIFF2NumFormatList }
|
||||
|
||||
@ -351,74 +291,19 @@ end;
|
||||
procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD;
|
||||
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
|
||||
out ANumberFormatStr: String);
|
||||
const
|
||||
NOT_USED = nfGeneral;
|
||||
fmts: array[1..20] of TsNumberFormat = (
|
||||
nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
|
||||
nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
|
||||
nfExp, nfShortDate, nfShortDate, nfFmtDateTime, nfFmtDateTime, // 11..15
|
||||
nfShortTimeAM, nfLongTimeAM, nfShortTime, nfLongTime, nfShortDateTime// 16..20
|
||||
);
|
||||
decs: array[1..20] of word = (
|
||||
0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20
|
||||
);
|
||||
var
|
||||
lNumFormatData: TsNumFormatData;
|
||||
lXFData: TXFListData;
|
||||
isAMPM: Boolean;
|
||||
isLongTime: Boolean;
|
||||
isMilliSec: Boolean;
|
||||
t,d: Boolean;
|
||||
begin
|
||||
ANumberFormat := nfGeneral;
|
||||
ANumberFormatStr := '';
|
||||
ADecimals := 0;
|
||||
(*
|
||||
lNumFormatData := FindNumFormatDataForCell(AXFIndex);
|
||||
if lNumFormatData = nil then begin
|
||||
// no custom format, so first test for default formats
|
||||
lXFData := TXFListData (FXFList.Items[AXFIndex]);
|
||||
if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin
|
||||
ANumberFormat := fmts[lXFData.FormatIndex];
|
||||
ADecimals := decs[lXFData.FormatIndex];
|
||||
end;
|
||||
end else
|
||||
// The next is copied from xlscommon - I think it's not necessary here
|
||||
if IsPercentNumberFormat(lNumFormatData.FormatString, ADecimals) then
|
||||
ANumberFormat := nfPercentage
|
||||
else
|
||||
if IsExpNumberFormat(lNumFormatData.Formatstring, ADecimals) then
|
||||
ANumberFormat := nfExp
|
||||
else
|
||||
if IsThousandSepNumberFormat(lNumFormatData.FormatString, ADecimals) then
|
||||
ANumberFormat := nfFixedTh
|
||||
else
|
||||
if IsFixedNumberFormat(lNumFormatData.FormatString, ADecimals) then
|
||||
ANumberFormat := nfFixed
|
||||
else begin
|
||||
t := IsTimeFormat(lNumFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
|
||||
d := IsDateFormat(lNumFormatData.FormatString, isLongDate);
|
||||
if d and t then
|
||||
ANumberFormat := nfShortDateTime
|
||||
else
|
||||
if d then
|
||||
ANumberFormat := nfShortDate
|
||||
else
|
||||
if t then begin
|
||||
if isAMPM then begin
|
||||
if isLongTime then
|
||||
ANumberFormat := nfLongTimeAM
|
||||
else
|
||||
ANumberFormat := nfShortTimeAM;
|
||||
end else begin
|
||||
if isLongTime then
|
||||
ANumberFormat := nfLongTime
|
||||
else
|
||||
ANumberFormat := nfShortTime;
|
||||
end;
|
||||
end;
|
||||
end; *)
|
||||
if lNumFormatData <> nil then begin
|
||||
ANumberFormat := lNumFormatData.NumFormat;
|
||||
ANumberFormatStr := lNumFormatData.FormatString;
|
||||
ADecimals := lNumFormatData.Decimals;
|
||||
end else begin
|
||||
ANumberFormat := nfGeneral;
|
||||
ANumberFormatStr := '';
|
||||
ADecimals := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream);
|
||||
@ -513,22 +398,20 @@ begin
|
||||
CurStreamPos := AStream.Position;
|
||||
|
||||
case RecordType of
|
||||
|
||||
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
||||
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
|
||||
INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
|
||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
|
||||
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
|
||||
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
|
||||
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
|
||||
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
|
||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||
INT_EXCEL_ID_XF : ReadXF(AStream);
|
||||
INT_EXCEL_ID_BOF : ;
|
||||
INT_EXCEL_ID_EOF : BIFF2EOF := True;
|
||||
|
||||
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
|
||||
INT_EXCEL_ID_FONT : ReadFont(AStream);
|
||||
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
|
||||
INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
|
||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||
INT_EXCEL_ID_LABEL : ReadLabel(AStream);
|
||||
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
|
||||
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
|
||||
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
|
||||
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
|
||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||
INT_EXCEL_ID_XF : ReadXF(AStream);
|
||||
INT_EXCEL_ID_BOF : ;
|
||||
INT_EXCEL_ID_EOF : BIFF2EOF := True;
|
||||
else
|
||||
// nothing
|
||||
end;
|
||||
|
@ -78,21 +78,16 @@ type
|
||||
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
|
||||
procedure ReadBoundsheet(AStream: TStream);
|
||||
function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
|
||||
procedure ReadSST(const AStream: TStream);
|
||||
procedure ReadLabelSST(const AStream: TStream);
|
||||
// Read XF record
|
||||
procedure ReadXF(const AStream: TStream);
|
||||
// Workbook Globals records
|
||||
// procedure ReadCodepage in xlscommon
|
||||
// procedure ReadDateMode in xlscommon
|
||||
protected
|
||||
procedure ReadBlank(AStream: TStream); override;
|
||||
procedure ReadFont(const AStream: TStream);
|
||||
procedure ReadFormat(AStream: TStream); override;
|
||||
{ Record reading methods }
|
||||
procedure ReadBlank(AStream: TStream); override;
|
||||
procedure ReadLabel(AStream: TStream); override;
|
||||
procedure ReadLabelSST(const AStream: TStream);
|
||||
procedure ReadRichString(const AStream: TStream);
|
||||
protected
|
||||
procedure ReadSST(const AStream: TStream);
|
||||
procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override;
|
||||
procedure ReadXF(const AStream: TStream);
|
||||
public
|
||||
destructor Destroy; override;
|
||||
{ General reading methods }
|
||||
@ -1750,16 +1745,13 @@ procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream;
|
||||
var
|
||||
record_id: Word;
|
||||
record_size: word;
|
||||
p: Cardinal;
|
||||
begin
|
||||
record_id := WordLEToN(AStream.ReadWord);
|
||||
if record_id <> INT_EXCEL_ID_STRING then
|
||||
raise Exception.Create('ReadStringRecord: wrong record found.');
|
||||
record_size := WordLEToN(AStream.ReadWord);
|
||||
p := AStream.Position;
|
||||
|
||||
AStringResult := ReadWideString(AStream, false);
|
||||
AStream.Position := p + record_size;
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
|
||||
|
@ -237,33 +237,6 @@ const
|
||||
{ DATEMODE record, 5.28 }
|
||||
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
|
||||
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
|
||||
(*
|
||||
{ FORMAT record constants for BIFF5-BIFF8}
|
||||
// Subset of the built-in formats for US Excel,
|
||||
// including those needed for date/time output
|
||||
FORMAT_GENERAL = 0; //general/default format
|
||||
FORMAT_FIXED_0_DECIMALS = 1; //fixed, 0 decimals
|
||||
FORMAT_FIXED_2_DECIMALS = 2; //fixed, 2 decimals
|
||||
FORMAT_FIXED_THOUSANDS_0_DECIMALS = 3; //fixed, w/ thousand separator, 0 decs
|
||||
FORMAT_FIXED_THOUSANDS_2_DECIMALS = 4; //fixed, w/ thousand separator, 2 decs
|
||||
FORMAT_CURRENCY_0_DECIMALS = 5; //currency (with currency symbol), 0 decs
|
||||
FORMAT_CURRENCY_2_DECIMALS = 7; //currency (with currency symbol), 2 decs
|
||||
FORMAT_PERCENT_0_DECIMALS = 9; //percent, 0 decimals
|
||||
FORMAT_PERCENT_2_DECIMALS = 10; //percent, 2 decimals
|
||||
FORMAT_EXP_2_DECIMALS = 11; //exponent, 2 decimals
|
||||
FORMAT_SHORT_DATE = 14; //short date
|
||||
FORMAT_DATE_DM = 16; //date D-MMM
|
||||
FORMAT_DATE_MY = 17; //date MMM-YYYY
|
||||
FORMAT_SHORT_TIME_AM = 18; //short time H:MM with AM
|
||||
FORMAT_LONG_TIME_AM = 19; //long time H:MM:SS with AM
|
||||
FORMAT_SHORT_TIME = 20; //short time H:MM
|
||||
FORMAT_LONG_TIME = 21; //long time H:MM:SS
|
||||
FORMAT_SHORT_DATETIME = 22; //short date+time
|
||||
FORMAT_TIME_MS = 45; //time MM:SS
|
||||
FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
|
||||
FORMAT_TIME_MSZ = 47; //time MM:SS.0
|
||||
FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal
|
||||
*)
|
||||
|
||||
{ WINDOW1 record constants - BIFF5-BIFF8 }
|
||||
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
|
||||
@ -336,6 +309,14 @@ const
|
||||
MASK_XF_VERT_ALIGN_BOTTOM = $20;
|
||||
MASK_XF_VERT_ALIGN_JUSTIFIED = $30;
|
||||
|
||||
{ Error codes }
|
||||
ERR_INTERSECTION_EMPTY = $00; // #NULL!
|
||||
ERR_DIVIDE_BY_ZERO = $07; // #DIV/0!
|
||||
ERR_WRONG_TYPE_OF_OPERAND = $0F; // #VALUE!
|
||||
ERR_ILLEGAL_REFERENCE = $17; // #REF!
|
||||
ERR_WRONG_NAME = $1D; // #NAME?
|
||||
ERR_OVERFLOW = $24; // #NUM!
|
||||
ERR_NOT_AVAILABLE = $2A; // #N/A
|
||||
|
||||
type
|
||||
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
|
||||
@ -943,6 +924,7 @@ var
|
||||
nd: Word;
|
||||
nfs: String;
|
||||
resultStr: String;
|
||||
err: TErrorValue;
|
||||
|
||||
begin
|
||||
{ BIFF Record header }
|
||||
@ -970,18 +952,33 @@ begin
|
||||
|
||||
//RPN data not used by now
|
||||
AStream.Position := AStream.Position + FormulaSize;
|
||||
|
||||
(*
|
||||
// Now determine the type of the formula result
|
||||
if (Data[6] = $FF) and (Data[7] = $FF) then
|
||||
case Data[0] of
|
||||
0: begin
|
||||
ReadStringRecord(AStream, resultStr);
|
||||
FWorksheet.WriteUTF8Text(ARow, ACol, resultStr);
|
||||
end;
|
||||
1: FWorksheet.WriteUTF8Text(ARow, ACol, '(Bool)');
|
||||
2: FWorksheet.WriteUTF8Text(ARow, ACol, '(ERROR)');
|
||||
3: FWorksheet.WriteUTF8Text(ARow, ACol, '(empty)');
|
||||
if resultStr = '' then
|
||||
FWorksheet.WriteBlank(ARow, ACol)
|
||||
else
|
||||
FWorksheet.WriteUTF8Text(ARow, ACol, resultStr);
|
||||
end;
|
||||
1: FWorksheet.WriteBoolValue(ARow, ACol, Data[2] = 1);
|
||||
2: begin
|
||||
case Data[2] of
|
||||
ERR_INTERSECTION_EMPTY : err := errEmptyIntersection;
|
||||
ERR_DIVIDE_BY_ZERO : err := errDivideByZero;
|
||||
ERR_WRONG_TYPE_OF_OPERAND: err := errWrongType;
|
||||
ERR_ILLEGAL_REFERENCE : err := errIllegalRef;
|
||||
ERR_WRONG_NAME : err := errWrongName;
|
||||
ERR_OVERFLOW : err := errOverflow;
|
||||
ERR_NOT_AVAILABLE : err := errArgNotAvail;
|
||||
end;
|
||||
FWorksheet.WriteErrorValue(ARow, ACol, err);
|
||||
end;
|
||||
3: FWorksheet.WriteBlank(ARow, ACol);
|
||||
end
|
||||
else begin
|
||||
else begin *)
|
||||
if SizeOf(Double) <> 8 then
|
||||
raise Exception.Create('Double is not 8 bytes');
|
||||
|
||||
@ -994,7 +991,7 @@ begin
|
||||
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
|
||||
else
|
||||
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
|
||||
end;
|
||||
// end;
|
||||
|
||||
{Add attributes}
|
||||
ApplyCellFormatting(ARow, ACol, XF);
|
||||
@ -1076,7 +1073,7 @@ var
|
||||
nd: word;
|
||||
nfs: String;
|
||||
begin
|
||||
ReadRowColXF(AStream,ARow,ACol,XF);
|
||||
ReadRowColXF(AStream, ARow, ACol, XF);
|
||||
|
||||
{ IEE 754 floating-point value }
|
||||
AStream.ReadBuffer(value, 8);
|
||||
@ -1609,14 +1606,21 @@ end;
|
||||
procedure TsSpreadBIFFWriter.WriteFormats(AStream: TStream);
|
||||
var
|
||||
i: Integer;
|
||||
|
||||
item: TsNumFormatData;
|
||||
|
||||
begin
|
||||
ListAllNumFormats;
|
||||
|
||||
item := NumFormatList[20];
|
||||
|
||||
i := NumFormatList.Find(NumFormatList.FirstFormatIndexInFile);
|
||||
while i < NumFormatList.Count do begin
|
||||
if NumFormatList[i] <> nil then
|
||||
WriteFormat(AStream, NumFormatList[i], i);
|
||||
inc(i);
|
||||
end;
|
||||
if i > -1 then
|
||||
while i < NumFormatList.Count do begin
|
||||
if NumFormatList[i] <> nil then
|
||||
WriteFormat(AStream, NumFormatList[i], i);
|
||||
inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Writes a 64-bit floating point NUMBER record.
|
||||
|
Reference in New Issue
Block a user