2008-02-24 13:18:34 +00:00
|
|
|
{
|
|
|
|
fpspreadsheet.pas
|
|
|
|
|
|
|
|
Writes an spreadsheet document
|
|
|
|
|
|
|
|
AUTHORS: Felipe Monteiro de Carvalho
|
|
|
|
}
|
|
|
|
unit fpspreadsheet;
|
|
|
|
|
|
|
|
{$ifdef fpc}
|
|
|
|
{$mode delphi}
|
|
|
|
{$endif}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2014-05-15 22:41:14 +00:00
|
|
|
Classes, SysUtils, fpimage, AVL_Tree, avglvltree, lconvencoding;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
type
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ File formats suppored by fpspreadsheet }
|
2014-06-25 08:38:39 +00:00
|
|
|
TsSpreadsheetFormat = (sfExcel2, {sfExcel3, sfExcel4,} sfExcel5, sfExcel8,
|
2013-06-11 14:15:59 +00:00
|
|
|
sfOOXML, sfOpenDocument, sfCSV, sfWikiTable_Pipes, sfWikiTable_WikiMedia);
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
const
|
|
|
|
{ Default extensions }
|
|
|
|
STR_EXCEL_EXTENSION = '.xls';
|
2009-01-28 17:18:04 +00:00
|
|
|
STR_OOXML_EXCEL_EXTENSION = '.xlsx';
|
|
|
|
STR_OPENDOCUMENT_CALC_EXTENSION = '.ods';
|
2011-08-11 14:30:25 +00:00
|
|
|
STR_COMMA_SEPARATED_EXTENSION = '.csv';
|
2013-06-11 14:15:59 +00:00
|
|
|
STR_WIKITABLE_PIPES = '.wikitable_pipes';
|
|
|
|
STR_WIKITABLE_WIKIMEDIA = '.wikitable_wikimedia';
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2009-02-02 09:58:51 +00:00
|
|
|
type
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2010-07-30 06:44:53 +00:00
|
|
|
{@@ Possible encodings for a non-unicode encoded text }
|
|
|
|
TsEncoding = (
|
|
|
|
seLatin1,
|
|
|
|
seLatin2,
|
|
|
|
seCyrillic,
|
|
|
|
seGreek,
|
|
|
|
seTurkish,
|
|
|
|
seHebrew,
|
|
|
|
seArabic
|
|
|
|
);
|
|
|
|
|
2009-02-02 09:58:51 +00:00
|
|
|
{@@ Describes a formula
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2009-02-02 09:58:51 +00:00
|
|
|
Supported syntax:
|
2014-06-21 20:25:01 +00:00
|
|
|
<pre>
|
2009-02-02 09:58:51 +00:00
|
|
|
=A1+B1+C1/D2... - Array with simple mathematical operations
|
|
|
|
=SUM(A1:D1) - SUM operation in a interval
|
2014-06-21 20:25:01 +00:00
|
|
|
</pre>
|
2009-02-02 09:58:51 +00:00
|
|
|
}
|
|
|
|
TsFormula = record
|
|
|
|
FormulaStr: string;
|
2008-02-24 13:18:34 +00:00
|
|
|
DoubleValue: double;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Tokens to identify the elements in an expanded formula.
|
2014-04-08 09:48:30 +00:00
|
|
|
|
|
|
|
See http://www.techonthenet.com/excel/formulas/ for an explanation of
|
|
|
|
meaning and parameters of each formula
|
|
|
|
|
2014-05-24 17:11:05 +00:00
|
|
|
NOTE: When adding or rearranging items:
|
|
|
|
- make sure that the subtypes TOperandTokens, TBasicOperationTokens and TFuncTokens
|
|
|
|
are complete
|
|
|
|
- make sure to keep the FEProps table in sync
|
|
|
|
- make sure to keep the TokenID table
|
|
|
|
in TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID, unit xlscommon,
|
|
|
|
in sync
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
2009-06-09 21:34:58 +00:00
|
|
|
TFEKind = (
|
|
|
|
{ Basic operands }
|
2014-05-23 13:16:01 +00:00
|
|
|
fekCell, fekCellRef, fekCellRange, fekNum, fekInteger, fekString, fekBool,
|
2014-05-24 17:11:05 +00:00
|
|
|
fekErr, fekMissingArg,
|
2009-06-09 21:34:58 +00:00
|
|
|
{ Basic operations }
|
2014-05-25 16:49:45 +00:00
|
|
|
fekAdd, fekSub, fekMul, fekDiv, fekPercent, fekPower, fekUMinus, fekUPlus,
|
2014-04-08 09:48:30 +00:00
|
|
|
fekConcat, // string concatenation
|
|
|
|
fekEqual, fekGreater, fekGreaterEqual, fekLess, fekLessEqual, fekNotEqual,
|
2014-05-24 17:11:05 +00:00
|
|
|
fekParen,
|
2013-12-07 13:42:22 +00:00
|
|
|
{ Built-in/Worksheet Functions}
|
2014-04-08 09:48:30 +00:00
|
|
|
// math
|
|
|
|
fekABS, fekACOS, fekACOSH, fekASIN, fekASINH, fekATAN, fekATANH,
|
|
|
|
fekCOS, fekCOSH, fekDEGREES, fekEXP, fekINT, fekLN, fekLOG,
|
|
|
|
fekLOG10, fekPI, fekRADIANS, fekRAND, fekROUND,
|
|
|
|
fekSIGN, fekSIN, fekSINH, fekSQRT,
|
|
|
|
fekTAN, fekTANH,
|
|
|
|
// date/time
|
|
|
|
fekDATE, fekDATEDIF, fekDATEVALUE, fekDAY, fekHOUR, fekMINUTE, fekMONTH,
|
|
|
|
fekNOW, fekSECOND, fekTIME, fekTIMEVALUE, fekTODAY, fekWEEKDAY, fekYEAR,
|
|
|
|
// statistical
|
|
|
|
fekAVEDEV, fekAVERAGE, fekBETADIST, fekBETAINV, fekBINOMDIST, fekCHIDIST,
|
|
|
|
fekCHIINV, fekCOUNT, fekCOUNTA, fekCOUNTBLANK, fekCOUNTIF,
|
|
|
|
fekMAX, fekMEDIAN, fekMIN, fekPERMUT, fekPOISSON, fekPRODUCT,
|
|
|
|
fekSTDEV, fekSTDEVP, fekSUM, fekSUMIF, fekSUMSQ, fekVAR, fekVARP,
|
|
|
|
// financial
|
2014-05-24 17:11:05 +00:00
|
|
|
fekFV, fekNPER, fekPMT, fekPV, fekRATE,
|
2014-04-08 09:48:30 +00:00
|
|
|
// logical
|
|
|
|
fekAND, fekFALSE, fekIF, fekNOT, fekOR, fekTRUE,
|
|
|
|
// string
|
|
|
|
fekCHAR, fekCODE, fekLEFT, fekLOWER, fekMID, fekPROPER, fekREPLACE, fekRIGHT,
|
|
|
|
fekSUBSTITUTE, fekTRIM, fekUPPER,
|
|
|
|
// lookup/reference
|
|
|
|
fekCOLUMN, fekCOLUMNS, fekROW, fekROWS,
|
|
|
|
// info
|
|
|
|
fekCELLINFO, fekINFO, fekIsBLANK, fekIsERR, fekIsERROR,
|
|
|
|
fekIsLOGICAL, fekIsNA, fekIsNONTEXT, fekIsNUMBER, fekIsRef, fekIsTEXT,
|
|
|
|
fekValue,
|
2009-06-09 21:34:58 +00:00
|
|
|
{ Other operations }
|
2014-04-17 12:25:40 +00:00
|
|
|
fekOpSUM {Unary sum operation. Note: CANNOT be used for summing sell contents; use fekSUM}
|
2009-06-09 21:34:58 +00:00
|
|
|
);
|
2009-02-02 09:58:51 +00:00
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ These tokens identify operands in RPN formulas. }
|
2014-05-24 17:11:05 +00:00
|
|
|
TOperandTokens = fekCell..fekMissingArg;
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ These tokens identify basic operations in RPN formulas. }
|
2014-05-24 17:11:05 +00:00
|
|
|
TBasicOperationTokens = fekAdd..fekParen;
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ These tokens identify spreadsheet functions in RPN formulas. }
|
2014-05-24 17:11:05 +00:00
|
|
|
TFuncTokens = fekAbs..fekOpSum;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Flags to mark the address or a cell or a range of cells to be absolute
|
|
|
|
or relative. They are used in the set TsRelFlags. }
|
2014-05-15 22:41:14 +00:00
|
|
|
TsRelFlag = (rfRelRow, rfRelCol, rfRelRow2, rfRelCol2);
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ Flags to mark the address of a cell or a range of cells to be absolute
|
|
|
|
or relative. It is a set consisting of TsRelFlag elements. }
|
2014-05-15 22:41:14 +00:00
|
|
|
TsRelFlags = set of TsRelFlag;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Elements of an expanded formula. }
|
2009-02-02 09:58:51 +00:00
|
|
|
TsFormulaElement = record
|
|
|
|
ElementKind: TFEKind;
|
2009-06-09 11:19:10 +00:00
|
|
|
Row, Row2: Word; // zero-based
|
2014-04-08 09:48:30 +00:00
|
|
|
Col, Col2: Word; // zero-based
|
2009-06-09 21:34:58 +00:00
|
|
|
Param1, Param2: Word; // Extra parameters
|
2009-02-02 09:58:51 +00:00
|
|
|
DoubleValue: double;
|
2014-04-08 09:48:30 +00:00
|
|
|
IntValue: Word;
|
|
|
|
StringValue: String;
|
|
|
|
RelFlags: TsRelFlags; // store info on relative/absolute addresses
|
|
|
|
ParamsNum: Byte;
|
2009-02-02 09:58:51 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Expanded formula. Used by backend modules. Provides more information than the text only.
|
2014-06-23 21:49:20 +00:00
|
|
|
Is an array of TsFormulaElement items. }
|
2009-02-02 09:58:51 +00:00
|
|
|
TsExpandedFormula = array of TsFormulaElement;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2009-06-09 11:19:10 +00:00
|
|
|
{@@ RPN formula. Similar to the expanded formula, but in RPN notation.
|
|
|
|
Simplifies the task of format writers which need RPN }
|
|
|
|
TsRPNFormula = array of TsFormulaElement;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Describes the type of content in a cell of a TsWorksheet }
|
2010-07-30 06:44:53 +00:00
|
|
|
TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber,
|
2014-05-14 23:17:46 +00:00
|
|
|
cctUTF8String, cctDateTime, cctBool, cctError);
|
|
|
|
|
|
|
|
{@@ Error code values }
|
2014-05-25 16:49:45 +00:00
|
|
|
TsErrorValue = (
|
|
|
|
errOK, // no error
|
2014-05-14 23:17:46 +00:00
|
|
|
errEmptyIntersection, // #NULL!
|
|
|
|
errDivideByZero, // #DIV/0!
|
|
|
|
errWrongType, // #VALUE!
|
|
|
|
errIllegalRef, // #REF!
|
|
|
|
errWrongName, // #NAME?
|
|
|
|
errOverflow, // #NUM!
|
2014-05-25 16:49:45 +00:00
|
|
|
errArgError, // #N/A
|
2014-05-23 13:16:01 +00:00
|
|
|
// --- no Excel errors --
|
|
|
|
errFormulaNotSupported
|
2014-05-14 23:17:46 +00:00
|
|
|
);
|
2010-07-30 06:44:53 +00:00
|
|
|
|
|
|
|
{@@ List of possible formatting fields }
|
2014-04-22 23:10:32 +00:00
|
|
|
TsUsedFormattingField = (uffTextRotation, uffFont, uffBold, uffBorder,
|
|
|
|
uffBackgroundColor, uffNumberFormat, uffWordWrap,
|
|
|
|
uffHorAlign, uffVertAlign
|
|
|
|
);
|
2010-07-30 06:44:53 +00:00
|
|
|
|
|
|
|
{@@ Describes which formatting fields are active }
|
|
|
|
TsUsedFormattingFields = set of TsUsedFormattingField;
|
|
|
|
|
2013-12-07 13:42:22 +00:00
|
|
|
{@@ Number/cell formatting. Only uses a subset of the default formats,
|
2014-05-14 15:24:02 +00:00
|
|
|
enough to be able to read/write date/time values.
|
|
|
|
nfCustom allows to apply a format string directly. }
|
2014-05-17 15:13:08 +00:00
|
|
|
TsNumberFormat = (
|
|
|
|
// general-purpose for all numbers
|
|
|
|
nfGeneral,
|
|
|
|
// numbers
|
2014-06-23 09:15:56 +00:00
|
|
|
nfFixed, nfFixedTh, nfExp, nfPercentage,
|
2014-05-17 15:13:08 +00:00
|
|
|
// currency
|
2014-06-23 09:15:56 +00:00
|
|
|
nfCurrency, nfCurrencyRed,
|
2014-05-17 15:13:08 +00:00
|
|
|
// dates and times
|
2014-06-12 22:20:45 +00:00
|
|
|
nfShortDateTime, {nfFmtDateTime, }nfShortDate, nfLongDate, nfShortTime, nfLongTime,
|
2014-05-17 15:13:08 +00:00
|
|
|
nfShortTimeAM, nfLongTimeAM, nfTimeInterval,
|
|
|
|
// other (format string goes directly into the file)
|
|
|
|
nfCustom);
|
2013-12-07 13:42:22 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
const
|
|
|
|
{ @@ Codes for curreny format according to FormatSettings.CurrencyFormat:
|
|
|
|
"C" = currency symbol, "V" = currency value, "S" = space character
|
|
|
|
For the negative value formats, we use also:
|
|
|
|
"B" = bracket, "M" = Minus
|
2014-06-20 23:06:29 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
The order of these characters represents the order of these items.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
Example: 1000 dollars --> "$1000" for pCV, or "1000 $" for pVsC
|
|
|
|
-1000 dollars --> "($1000)" for nbCVb, or "-$ 1000" for nMCSV
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
Assignment taken from "sysstr.inc" }
|
2014-06-12 22:20:45 +00:00
|
|
|
pcfDefault = -1; // use value from Worksheet.FormatSettings.CurrencyFormat
|
|
|
|
pcfCV = 0; // $1000
|
|
|
|
pcfVC = 1; // 1000$
|
|
|
|
pcfCSV = 2; // $ 1000
|
|
|
|
pcfVSC = 3; // 1000 $
|
|
|
|
|
|
|
|
ncfDefault = -1; // use value from Worksheet.FormatSettings.NegCurrFormat
|
|
|
|
ncfBCVB = 0; // ($1000)
|
|
|
|
ncfMCV = 1; // -$1000
|
|
|
|
ncfCMV = 2; // $-1000
|
|
|
|
ncfCVM = 3; // $1000-
|
|
|
|
ncfBVCB = 4; // (1000$)
|
|
|
|
ccfMVC = 5; // -1000$
|
|
|
|
ncfVMC = 6; // 1000-$
|
|
|
|
ncfVCM = 7; // 1000$-
|
|
|
|
ncfMVSC = 8; // -1000 $
|
|
|
|
ncfMCSV = 9; // -$ 1000
|
|
|
|
ncfVSCM = 10; // 1000 $-
|
|
|
|
ncfCSVM = 11; // $ 1000-
|
|
|
|
ncfCSMV = 12; // $ -1000
|
|
|
|
ncfVMSC = 13; // 1000- $
|
|
|
|
ncfBCSVB = 14; // ($ 1000)
|
|
|
|
ncfBVSCB = 15; // (1000 $)
|
|
|
|
|
|
|
|
type
|
2011-05-26 09:25:56 +00:00
|
|
|
{@@ Text rotation formatting. The text is rotated relative to the standard
|
2014-05-08 12:12:06 +00:00
|
|
|
orientation, which is from left to right horizontal:
|
2014-06-20 23:06:29 +00:00
|
|
|
<pre>
|
2014-05-08 12:12:06 +00:00
|
|
|
--->
|
2014-06-20 23:06:29 +00:00
|
|
|
ABC </pre>
|
2011-05-26 09:25:56 +00:00
|
|
|
|
|
|
|
So 90 degrees clockwise means that the text will be:
|
2014-06-20 23:06:29 +00:00
|
|
|
<pre>
|
2011-05-26 09:25:56 +00:00
|
|
|
| A
|
|
|
|
| B
|
2014-06-20 23:06:29 +00:00
|
|
|
v C </pre>
|
2011-05-26 09:25:56 +00:00
|
|
|
|
|
|
|
And 90 degree counter clockwise will be:
|
2014-06-20 23:06:29 +00:00
|
|
|
<pre>
|
2014-04-25 22:15:26 +00:00
|
|
|
^ C
|
2011-05-26 09:25:56 +00:00
|
|
|
| B
|
2014-06-20 23:06:29 +00:00
|
|
|
| A</pre>
|
2014-05-08 12:12:06 +00:00
|
|
|
|
|
|
|
Due to limitations of the text mode the characters are not rotated here.
|
|
|
|
There is, however, also a "stacked" variant which looks exactly like
|
|
|
|
the former case.
|
2011-05-26 09:25:56 +00:00
|
|
|
}
|
2010-07-30 06:44:53 +00:00
|
|
|
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
|
2014-04-25 22:15:26 +00:00
|
|
|
rt90DegreeCounterClockwiseRotation, rtStacked);
|
2010-07-30 06:44:53 +00:00
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Indicates horizontal text alignment in cells }
|
2014-04-20 20:31:36 +00:00
|
|
|
TsHorAlignment = (haDefault, haLeft, haCenter, haRight);
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ Indicates vertical text alignment in cells }
|
2014-04-20 20:31:36 +00:00
|
|
|
TsVertAlignment = (vaDefault, vaTop, vaCenter, vaBottom);
|
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{@@
|
|
|
|
Colors in fpspreadsheet are given as indices into a palette.
|
2014-04-24 21:27:57 +00:00
|
|
|
Use the workbook's GetPaletteColor to determine the color rgb value as
|
|
|
|
little-endian (with "r" being the low-value byte, in agreement with TColor).
|
2014-05-03 17:00:00 +00:00
|
|
|
The data type for rgb values is TsColorValue. }
|
2014-04-23 22:29:32 +00:00
|
|
|
TsColor = Word;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
These are some constants for color indices into the default palette.
|
|
|
|
Note, however, that if a different palette is used there may be more colors,
|
|
|
|
and the names of the color constants may no longer be correct.
|
|
|
|
}
|
|
|
|
const
|
|
|
|
scBlack = $00;
|
|
|
|
scWhite = $01;
|
|
|
|
scRed = $02;
|
|
|
|
scGreen = $03;
|
|
|
|
scBlue = $04;
|
|
|
|
scYellow = $05;
|
|
|
|
scMagenta = $06;
|
|
|
|
scCyan = $07;
|
2014-04-24 21:27:57 +00:00
|
|
|
scDarkRed = $08;
|
|
|
|
scDarkGreen = $09;
|
|
|
|
scDarkBlue = $0A; scNavy = $0A;
|
|
|
|
scOlive = $0B;
|
|
|
|
scPurple = $0C;
|
|
|
|
scTeal = $0D;
|
|
|
|
scSilver = $0E;
|
|
|
|
scGrey = $0F; scGray = $0F; // redefine to allow different kinds of writing
|
|
|
|
scGrey10pct = $10; scGray10pct = $10;
|
|
|
|
scGrey20pct = $11; scGray20pct = $11;
|
|
|
|
scOrange = $12;
|
|
|
|
scDarkbrown = $13;
|
|
|
|
scBrown = $14;
|
|
|
|
scBeige = $15;
|
|
|
|
scWheat = $16;
|
|
|
|
|
|
|
|
// not sure - but I think the mechanism with scRGBColor is not working...
|
|
|
|
// Will be removed sooner or later...
|
2014-04-23 22:29:32 +00:00
|
|
|
scRGBColor = $FFFF;
|
2011-05-25 13:40:53 +00:00
|
|
|
|
2014-06-23 13:49:12 +00:00
|
|
|
scTransparent = $FFFE;
|
2014-05-11 11:56:20 +00:00
|
|
|
scNotDefined = $FFFF;
|
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
type
|
2014-04-24 21:27:57 +00:00
|
|
|
{@@ Data type for rgb color values }
|
|
|
|
TsColorValue = DWord;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Palette of color values. A "color value" is a DWord value containing
|
|
|
|
rgb colors. }
|
2014-04-24 21:27:57 +00:00
|
|
|
TsPalette = array[0..0] of TsColorValue;
|
2014-04-23 22:29:32 +00:00
|
|
|
PsPalette = ^TsPalette;
|
2014-04-22 23:10:32 +00:00
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{@@ Font style (redefined to avoid usage of "Graphics" }
|
2014-04-22 23:10:32 +00:00
|
|
|
TsFontStyle = (fssBold, fssItalic, fssStrikeOut, fssUnderline);
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ Set of font styles }
|
2014-04-22 23:10:32 +00:00
|
|
|
TsFontStyles = set of TsFontStyle;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Font record used in fpspreadsheet. Contains the font name, the font size
|
|
|
|
(in points), the font style, and the font color. }
|
2014-04-22 23:10:32 +00:00
|
|
|
TsFont = class
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Name of the font face, such as 'Arial' or 'Times New Roman' }
|
2014-04-22 23:10:32 +00:00
|
|
|
FontName: String;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Size of the font in points }
|
2014-04-22 23:10:32 +00:00
|
|
|
Size: Single; // in "points"
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Font style, such as bold, italics etc. - see TsFontStyle}
|
2014-04-22 23:10:32 +00:00
|
|
|
Style: TsFontStyles;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Text color given by the index into the workbook's color palette }
|
2014-04-22 23:10:32 +00:00
|
|
|
Color: TsColor;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Indicates the border for a cell. If included in the CellBorders set the
|
|
|
|
corresponding border is drawn in the style defined by the CellBorderStyle. }
|
2014-05-03 17:00:00 +00:00
|
|
|
TsCellBorder = (cbNorth, cbWest, cbEast, cbSouth);
|
|
|
|
|
|
|
|
{@@ Indicates the border for a cell }
|
|
|
|
TsCellBorders = set of TsCellBorder;
|
|
|
|
|
|
|
|
{@@ Line style (for cell borders) }
|
2014-05-11 09:20:52 +00:00
|
|
|
TsLineStyle = (lsThin, lsMedium, lsDashed, lsDotted, lsThick, lsDouble, lsHair);
|
2014-05-03 17:00:00 +00:00
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ The Cell border style reocrd contains the linestyle and color of a cell
|
|
|
|
border. There is a CellBorderStyle for each border. }
|
2014-05-03 17:00:00 +00:00
|
|
|
TsCellBorderStyle = record
|
|
|
|
LineStyle: TsLineStyle;
|
|
|
|
Color: TsColor;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ The cell border styles of each cell border are collected in this array. }
|
2014-05-03 17:00:00 +00:00
|
|
|
TsCellBorderStyles = array[TsCellBorder] of TsCellBorderStyle;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Border styles for each cell border used by default: a thin, black, solid line }
|
2014-05-03 17:00:00 +00:00
|
|
|
const
|
|
|
|
DEFAULT_BORDERSTYLES: TsCellBorderStyles = (
|
|
|
|
(LineStyle: lsThin; Color: scBlack),
|
|
|
|
(LineStyle: lsThin; Color: scBlack),
|
|
|
|
(LineStyle: lsThin; Color: scBlack),
|
|
|
|
(LineStyle: lsThin; Color: scBlack)
|
|
|
|
);
|
|
|
|
|
|
|
|
type
|
2010-05-25 09:11:02 +00:00
|
|
|
{@@ Cell structure for TsWorksheet
|
2014-06-20 23:06:29 +00:00
|
|
|
The cell record contains information on the location of the cell (row and
|
|
|
|
column index), on the value contained (number, date, text, ...), and on
|
|
|
|
formatting.
|
2010-05-25 09:11:02 +00:00
|
|
|
|
|
|
|
Never suppose that all *Value fields are valid,
|
|
|
|
only one of the ContentTypes is valid. For other fields
|
|
|
|
use TWorksheet.ReadAsUTF8Text and similar methods
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
@see ReadAsUTF8Text }
|
2008-02-24 13:18:34 +00:00
|
|
|
TCell = record
|
2014-04-19 19:29:13 +00:00
|
|
|
Col: Cardinal; // zero-based
|
2012-06-13 15:24:44 +00:00
|
|
|
Row: Cardinal; // zero-based
|
2008-02-24 13:18:34 +00:00
|
|
|
ContentType: TCellContentType;
|
2009-06-09 11:19:10 +00:00
|
|
|
{ Possible values for the cells }
|
2009-02-02 09:58:51 +00:00
|
|
|
FormulaValue: TsFormula;
|
2009-06-09 11:19:10 +00:00
|
|
|
RPNFormulaValue: TsRPNFormula;
|
2008-02-24 13:18:34 +00:00
|
|
|
NumberValue: double;
|
2009-01-28 17:18:04 +00:00
|
|
|
UTF8StringValue: ansistring;
|
2012-01-23 13:24:13 +00:00
|
|
|
DateTimeValue: TDateTime;
|
2014-05-14 23:17:46 +00:00
|
|
|
BoolValue: Boolean;
|
2014-05-25 16:49:45 +00:00
|
|
|
ErrorValue: TsErrorValue;
|
2010-07-30 06:44:53 +00:00
|
|
|
{ Formatting fields }
|
2014-05-15 22:41:14 +00:00
|
|
|
{ When adding/deleting formatting fields don't forget to update CopyFormat! }
|
2010-07-30 06:44:53 +00:00
|
|
|
UsedFormattingFields: TsUsedFormattingFields;
|
2014-04-22 23:10:32 +00:00
|
|
|
FontIndex: Integer;
|
2010-07-30 06:44:53 +00:00
|
|
|
TextRotation: TsTextRotation;
|
2014-04-20 20:31:36 +00:00
|
|
|
HorAlignment: TsHorAlignment;
|
|
|
|
VertAlignment: TsVertAlignment;
|
2011-05-25 13:40:53 +00:00
|
|
|
Border: TsCellBorders;
|
2014-05-03 17:00:00 +00:00
|
|
|
BorderStyles: TsCelLBorderStyles;
|
2011-05-25 15:50:18 +00:00
|
|
|
BackgroundColor: TsColor;
|
2013-12-07 13:42:22 +00:00
|
|
|
NumberFormat: TsNumberFormat;
|
2013-12-22 14:02:04 +00:00
|
|
|
NumberFormatStr: String;
|
2013-06-12 11:02:02 +00:00
|
|
|
RGBBackgroundColor: TFPColor; // only valid if BackgroundColor=scRGBCOLOR
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Pointer to a TCell record }
|
2008-02-24 13:18:34 +00:00
|
|
|
PCell = ^TCell;
|
|
|
|
|
2014-05-31 21:04:53 +00:00
|
|
|
const
|
|
|
|
// Takes account of effect of cell margins on row height by adding this
|
|
|
|
// value to the nominal row height. Note that this is an empirical value and may be wrong.
|
|
|
|
ROW_HEIGHT_CORRECTION = 0.2;
|
|
|
|
|
|
|
|
type
|
2014-06-24 16:10:01 +00:00
|
|
|
{@@ The record TRow contains information about a spreadsheet row:
|
2014-06-20 23:06:29 +00:00
|
|
|
@param Row The index of the row (beginning with 0)
|
|
|
|
@param Height The height of the row (expressed as lines count of the default font)
|
|
|
|
Only rows with heights that cannot be derived from the font height have a
|
|
|
|
row record. }
|
2012-06-13 15:24:44 +00:00
|
|
|
TRow = record
|
|
|
|
Row: Cardinal;
|
2014-05-31 21:04:53 +00:00
|
|
|
Height: Single; // in "lines"
|
2012-06-13 15:24:44 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Pointer to a TRow record }
|
2012-06-13 15:24:44 +00:00
|
|
|
PRow = ^TRow;
|
|
|
|
|
2014-06-24 16:10:01 +00:00
|
|
|
{@@ The record TCol contains information about a spreadsheet column:
|
2014-06-20 23:06:29 +00:00
|
|
|
@param Col The index of the column (beginning with 0)
|
|
|
|
@param Width The width of the column (expressed in character count of the "0" character of the default font.
|
|
|
|
Only columns with non-default widths have a column record. }
|
2012-06-13 15:24:44 +00:00
|
|
|
TCol = record
|
2014-04-23 22:29:32 +00:00
|
|
|
Col: Cardinal;
|
2014-05-31 21:04:53 +00:00
|
|
|
Width: Single; // in "characters". Excel uses the width of char "0" in 1st font
|
2012-06-13 15:24:44 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Pointer to a TCol record }
|
2012-06-13 15:24:44 +00:00
|
|
|
PCol = ^TCol;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ User interface options:
|
|
|
|
@param soShowGridLines Show or hide the grid lines in the spreadsheet
|
|
|
|
@param soShowHeaders Show or hide the column or row headers of the spreadsheet
|
|
|
|
@param soHasFrozenPanes If set a number of rows and columns of the spreadsheet
|
|
|
|
is fixed and does not scroll. The number is defined by
|
2014-06-24 22:47:15 +00:00
|
|
|
LeftPaneWidth and TopPaneHeight. }
|
2014-06-27 14:24:23 +00:00
|
|
|
TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes,
|
|
|
|
soCalcBeforeSaving);
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
{@@ Set of user interface options
|
|
|
|
@ see TsSheetOption }
|
2014-05-04 18:07:54 +00:00
|
|
|
TsSheetOptions = set of TsSheetOption;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
type
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
TsCustomSpreadReader = class;
|
2008-02-24 13:18:34 +00:00
|
|
|
TsCustomSpreadWriter = class;
|
2014-04-22 23:10:32 +00:00
|
|
|
TsWorkbook = class;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{ TsWorksheet }
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ This event fires whenever a cell value or cell formatting changes. It is
|
|
|
|
handled by TsWorksheetGrid to update the grid. }
|
2014-05-07 22:44:00 +00:00
|
|
|
TsCellEvent = procedure (Sender: TObject; ARow, ACol: Cardinal) of object;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ The worksheet contains a list of cells and provides a variety of methods
|
|
|
|
to read or write data to the cells, or to change their formatting. }
|
2008-02-24 13:18:34 +00:00
|
|
|
TsWorksheet = class
|
|
|
|
private
|
2014-04-22 23:10:32 +00:00
|
|
|
FWorkbook: TsWorkbook;
|
2012-06-13 15:24:44 +00:00
|
|
|
FCells: TAvlTree; // Items are TCell
|
2009-10-06 19:25:18 +00:00
|
|
|
FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
|
2014-05-31 21:04:53 +00:00
|
|
|
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
|
2014-05-04 18:07:54 +00:00
|
|
|
FLeftPaneWidth: Integer;
|
|
|
|
FTopPaneHeight: Integer;
|
|
|
|
FOptions: TsSheetOptions;
|
2014-05-07 22:44:00 +00:00
|
|
|
FOnChangeCell: TsCellEvent;
|
2014-05-08 21:52:04 +00:00
|
|
|
FOnChangeFont: TsCellEvent;
|
2014-06-27 14:24:23 +00:00
|
|
|
procedure CalcFormulaCallback(data, arg: Pointer);
|
2014-06-05 21:57:23 +00:00
|
|
|
function GetFormatSettings: TFormatSettings;
|
2014-06-23 13:49:12 +00:00
|
|
|
procedure RemoveCallback(data, arg: pointer);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
protected
|
2014-06-27 14:24:23 +00:00
|
|
|
procedure CalcRPNFormula(ACell: PCell);
|
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure ChangedCell(ARow, ACol: Cardinal);
|
2014-05-08 21:52:04 +00:00
|
|
|
procedure ChangedFont(ARow, ACol: Cardinal);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
public
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Name of the sheet. In the popular spreadsheet applications this is
|
|
|
|
displayed at the tab of the sheet. }
|
2008-02-24 13:18:34 +00:00
|
|
|
Name: string;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ Base methods }
|
|
|
|
constructor Create;
|
|
|
|
destructor Destroy; override;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2011-08-29 10:55:22 +00:00
|
|
|
{ Utils }
|
2014-05-07 22:44:00 +00:00
|
|
|
class function CellPosToText(ARow, ACol: Cardinal): string;
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure RemoveAllCells;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
{ Reading of values }
|
2014-05-23 23:13:49 +00:00
|
|
|
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring; overload;
|
|
|
|
function ReadAsUTF8Text(ACell: PCell): ansistring; overload;
|
2014-06-21 20:25:01 +00:00
|
|
|
function ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
|
|
|
|
function ReadAsNumber(ACell: PCell): Double; overload;
|
|
|
|
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
|
|
|
|
function ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean; overload;
|
2014-06-06 15:48:02 +00:00
|
|
|
function ReadFormulaAsString(ACell: PCell): String;
|
2014-05-23 23:13:49 +00:00
|
|
|
function ReadRPNFormulaAsString(ACell: PCell): String;
|
2013-06-11 14:15:59 +00:00
|
|
|
function ReadUsedFormatting(ARow, ACol: Cardinal): TsUsedFormattingFields;
|
|
|
|
function ReadBackgroundColor(ARow, ACol: Cardinal): TsColor;
|
2014-05-23 23:13:49 +00:00
|
|
|
|
2014-06-13 07:59:42 +00:00
|
|
|
{ Reading of cell attributes }
|
|
|
|
function GetNumberFormatAttributes(ACell: PCell; out ADecimals: Byte;
|
|
|
|
out ACurrencySymbol: String): Boolean;
|
|
|
|
|
2014-05-03 17:00:00 +00:00
|
|
|
{ Writing of values }
|
2014-06-30 10:39:49 +00:00
|
|
|
procedure WriteBlank(ARow, ACol: Cardinal); overload;
|
|
|
|
procedure WriteBlank(ACell: PCell); overload;
|
2014-06-29 09:55:47 +00:00
|
|
|
|
|
|
|
procedure WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean); overload;
|
|
|
|
procedure WriteBoolValue(ACell: PCell; AValue: Boolean); overload;
|
2014-06-12 22:20:45 +00:00
|
|
|
|
2014-06-22 13:49:48 +00:00
|
|
|
procedure WriteCellValueAsString(ARow, ACol: Cardinal; AValue: String); overload;
|
|
|
|
procedure WriteCellValueAsString(ACell: PCell; AValue: String); overload;
|
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
|
|
|
|
ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
|
|
|
|
ANegCurrFormat: Integer = -1); overload;
|
|
|
|
procedure WriteCurrency(ACell: PCell; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
|
|
|
|
ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
|
|
|
|
ANegCurrFormat: Integer = -1); overload;
|
|
|
|
procedure WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String); overload;
|
|
|
|
procedure WriteCurrency(ACell: PCell; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String); overload;
|
|
|
|
|
|
|
|
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
|
|
|
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
|
|
|
|
procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
|
|
|
|
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
|
2013-12-22 14:02:04 +00:00
|
|
|
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatStr: String); overload;
|
2014-05-23 15:45:07 +00:00
|
|
|
procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatStr: String); overload;
|
|
|
|
|
2014-05-25 16:49:45 +00:00
|
|
|
procedure WriteErrorValue(ARow, ACol: Cardinal; AValue: TsErrorValue); overload;
|
|
|
|
procedure WriteErrorValue(ACell: PCell; AValue: TsErrorValue); overload;
|
2009-02-02 09:58:51 +00:00
|
|
|
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
2014-06-12 22:20:45 +00:00
|
|
|
|
2014-05-20 16:13:48 +00:00
|
|
|
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
2014-06-20 15:58:22 +00:00
|
|
|
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2); overload;
|
|
|
|
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
|
|
|
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2); overload;
|
2014-05-20 16:13:48 +00:00
|
|
|
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormat: TsNumberFormat; AFormatString: String); overload;
|
|
|
|
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String); overload;
|
|
|
|
|
2009-06-09 11:19:10 +00:00
|
|
|
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
|
2014-06-06 15:48:02 +00:00
|
|
|
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring); overload;
|
|
|
|
procedure WriteUTF8Text(ACell: PCell; AText: ansistring); overload;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-05-03 17:00:00 +00:00
|
|
|
{ Writing of cell attributes }
|
2013-06-11 14:15:59 +00:00
|
|
|
procedure WriteBackgroundColor(ARow, ACol: Cardinal; AColor: TsColor);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure WriteBorderColor(ARow, ACol: Cardinal; ABorder: TsCellBorder; AColor: TsColor);
|
|
|
|
procedure WriteBorderLineStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
|
|
|
|
ALineStyle: TsLineStyle);
|
2014-04-21 21:43:43 +00:00
|
|
|
procedure WriteBorders(ARow, ACol: Cardinal; ABorders: TsCellBorders);
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
|
|
|
|
AStyle: TsCellBorderStyle); overload;
|
|
|
|
procedure WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
|
|
|
|
ALineStyle: TsLineStyle; AColor: TsColor); overload;
|
|
|
|
procedure WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
|
|
|
procedure WriteDecimals(ARow, ACol: Cardinal; ADecimals: byte); overload;
|
|
|
|
procedure WriteDecimals(ACell: PCell; ADecimals: Byte); overload;
|
|
|
|
|
|
|
|
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
|
|
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
|
|
|
|
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
|
|
|
|
function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
|
|
|
function WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
|
|
|
function WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
|
|
|
function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer;
|
|
|
|
|
2014-04-20 20:31:36 +00:00
|
|
|
procedure WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
|
|
|
procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
|
2014-06-05 21:57:23 +00:00
|
|
|
const AFormatString: String = ''); overload;
|
|
|
|
procedure WriteNumberFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
|
|
|
|
const AFormatString: String = ''); overload;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
|
|
|
procedure WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation);
|
|
|
|
|
|
|
|
procedure WriteUsedFormatting(ARow, ACol: Cardinal; AUsedFormatting: TsUsedFormattingFields);
|
|
|
|
|
2014-04-20 20:31:36 +00:00
|
|
|
procedure WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-04-29 21:58:48 +00:00
|
|
|
procedure WriteWordwrap(ARow, ACol: Cardinal; AValue: boolean);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
{ Data manipulation methods - For Cells }
|
2014-06-27 14:24:23 +00:00
|
|
|
procedure CalcFormulas;
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet);
|
|
|
|
procedure CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal); overload;
|
|
|
|
procedure CopyFormat(AFromCell, AToCell: PCell); overload;
|
|
|
|
function FindCell(ARow, ACol: Cardinal): PCell;
|
|
|
|
function GetCell(ARow, ACol: Cardinal): PCell;
|
|
|
|
function GetCellCount: Cardinal;
|
|
|
|
function GetFirstCell(): PCell;
|
|
|
|
function GetNextCell(): PCell;
|
|
|
|
function GetFirstCellOfRow(ARow: Cardinal): PCell;
|
|
|
|
function GetLastCellOfRow(ARow: Cardinal): PCell;
|
|
|
|
function GetLastColIndex: Cardinal;
|
|
|
|
function GetLastColNumber: Cardinal; deprecated 'Use GetLastColIndex';
|
|
|
|
function GetLastRowIndex: Cardinal;
|
|
|
|
function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex';
|
|
|
|
|
2012-06-13 15:24:44 +00:00
|
|
|
{ Data manipulation methods - For Rows and Cols }
|
2014-06-17 09:06:34 +00:00
|
|
|
function CalcAutoRowHeight(ARow: Cardinal): Single;
|
2012-06-13 15:24:44 +00:00
|
|
|
function FindRow(ARow: Cardinal): PRow;
|
|
|
|
function FindCol(ACol: Cardinal): PCol;
|
2014-05-31 21:04:53 +00:00
|
|
|
function GetCellCountInRow(ARow: Cardinal): Cardinal;
|
|
|
|
function GetCellCountInCol(ACol: Cardinal): Cardinal;
|
2012-06-13 15:24:44 +00:00
|
|
|
function GetRow(ARow: Cardinal): PRow;
|
2014-05-31 21:04:53 +00:00
|
|
|
function GetRowHeight(ARow: Cardinal): Single;
|
2012-06-13 15:24:44 +00:00
|
|
|
function GetCol(ACol: Cardinal): PCol;
|
2014-05-31 21:04:53 +00:00
|
|
|
function GetColWidth(ACol: Cardinal): Single;
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure RemoveAllRows;
|
|
|
|
procedure RemoveAllCols;
|
|
|
|
procedure WriteRowInfo(ARow: Cardinal; AData: TRow);
|
2014-05-07 18:31:27 +00:00
|
|
|
procedure WriteRowHeight(ARow: Cardinal; AHeight: Single);
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure WriteColInfo(ACol: Cardinal; AData: TCol);
|
2014-04-24 23:05:00 +00:00
|
|
|
procedure WriteColWidth(ACol: Cardinal; AWidth: Single);
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2012-06-13 15:24:44 +00:00
|
|
|
{ Properties }
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
{@@ List of cells of the worksheet. Only cells with contents or with formatting
|
|
|
|
are listed }
|
2009-09-02 22:03:01 +00:00
|
|
|
property Cells: TAVLTree read FCells;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ List of all column records of the worksheet having a non-standard column width }
|
2014-04-18 13:17:22 +00:00
|
|
|
property Cols: TIndexedAVLTree read FCols;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ FormatSettings for localization of some formatting strings }
|
2014-06-05 21:57:23 +00:00
|
|
|
property FormatSettings: TFormatSettings read GetFormatSettings;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ List of all row records of the worksheet having a non-standard row height }
|
2014-04-20 14:57:23 +00:00
|
|
|
property Rows: TIndexedAVLTree read FRows;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Workbook to which the worksheet belongs }
|
2014-04-22 23:10:32 +00:00
|
|
|
property Workbook: TsWorkbook read FWorkbook;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
// These are properties to interface to TsWorksheetGrid
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Parameters controlling visibility of grid lines and row/column headers,
|
|
|
|
usage of frozen panes etc. }
|
2014-05-04 18:07:54 +00:00
|
|
|
property Options: TsSheetOptions read FOptions write FOptions;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Number of frozen columns which do not scroll }
|
2014-05-04 18:07:54 +00:00
|
|
|
property LeftPaneWidth: Integer read FLeftPaneWidth write FLeftPaneWidth;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Number of frozen rows which do not scroll }
|
2014-05-04 18:07:54 +00:00
|
|
|
property TopPaneHeight: Integer read FTopPaneHeight write FTopPaneHeight;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Event fired when cell contents or formatting changes }
|
2014-05-07 22:44:00 +00:00
|
|
|
property OnChangeCell: TsCellEvent read FOnChangeCell write FOnChangeCell;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Event fired when the font size in a cell changes }
|
2014-05-08 21:52:04 +00:00
|
|
|
property OnChangeFont: TsCellEvent read FOnChangeFont write FOnChangeFont;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-07 22:44:00 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
2014-06-24 16:10:01 +00:00
|
|
|
The workbook contains the worksheets and provides methods for reading from
|
2014-06-23 21:49:20 +00:00
|
|
|
and writing to file.
|
|
|
|
}
|
2008-02-24 13:18:34 +00:00
|
|
|
TsWorkbook = class
|
|
|
|
private
|
2009-01-10 21:47:59 +00:00
|
|
|
{ Internal data }
|
2008-02-24 13:18:34 +00:00
|
|
|
FWorksheets: TFPList;
|
2010-07-30 06:44:53 +00:00
|
|
|
FEncoding: TsEncoding;
|
2014-04-21 21:43:43 +00:00
|
|
|
FFormat: TsSpreadsheetFormat;
|
2014-04-22 23:10:32 +00:00
|
|
|
FFontList: TFPList;
|
|
|
|
FBuiltinFontCount: Integer;
|
2014-04-24 21:27:57 +00:00
|
|
|
FPalette: array of TsColorValue;
|
2014-05-23 13:16:01 +00:00
|
|
|
FReadFormulas: Boolean;
|
2014-05-31 21:04:53 +00:00
|
|
|
FDefaultColWidth: Single; // in "characters". Excel uses the width of char "0" in 1st font
|
|
|
|
FDefaultRowHeight: Single; // in "character heights", i.e. line count
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{ Internal methods }
|
2014-06-27 14:24:23 +00:00
|
|
|
procedure PrepareBeforeSaving;
|
2014-04-22 23:10:32 +00:00
|
|
|
procedure RemoveWorksheetsCallback(data, arg: pointer);
|
2014-05-31 21:04:53 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
public
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ A copy of SysUtil's DefaultFormatSettings to provide some kind of
|
|
|
|
localization to some formatting strings. Can be modified before
|
|
|
|
loading/writing files }
|
2014-05-17 15:13:08 +00:00
|
|
|
FormatSettings: TFormatSettings;
|
2014-05-31 21:04:53 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ Base methods }
|
|
|
|
constructor Create;
|
|
|
|
destructor Destroy; override;
|
2014-06-19 19:25:40 +00:00
|
|
|
class function GetFormatFromFileName(const AFileName: TFileName; out SheetType: TsSpreadsheetFormat): Boolean;
|
2009-01-10 21:47:59 +00:00
|
|
|
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
|
2008-02-24 13:18:34 +00:00
|
|
|
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
|
2011-05-25 13:52:46 +00:00
|
|
|
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload;
|
|
|
|
procedure ReadFromFile(AFileName: string); overload;
|
2011-12-25 09:03:20 +00:00
|
|
|
procedure ReadFromFileIgnoringExtension(AFileName: string);
|
2009-01-10 21:47:59 +00:00
|
|
|
procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
2009-11-08 19:21:23 +00:00
|
|
|
procedure WriteToFile(const AFileName: string;
|
|
|
|
const AFormat: TsSpreadsheetFormat;
|
2011-08-11 14:30:25 +00:00
|
|
|
const AOverwriteExisting: Boolean = False); overload;
|
|
|
|
procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload;
|
2008-02-24 13:18:34 +00:00
|
|
|
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
2014-05-31 21:04:53 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ Worksheet list handling methods }
|
|
|
|
function AddWorksheet(AName: string): TsWorksheet;
|
|
|
|
function GetFirstWorksheet: TsWorksheet;
|
|
|
|
function GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet;
|
2013-12-07 13:42:22 +00:00
|
|
|
function GetWorksheetByName(AName: String): TsWorksheet;
|
2008-02-24 13:18:34 +00:00
|
|
|
function GetWorksheetCount: Cardinal;
|
|
|
|
procedure RemoveAllWorksheets;
|
2014-05-31 21:04:53 +00:00
|
|
|
|
2014-04-22 23:10:32 +00:00
|
|
|
{ Font handling }
|
|
|
|
function AddFont(const AFontName: String; ASize: Single;
|
|
|
|
AStyle: TsFontStyles; AColor: TsColor): Integer; overload;
|
|
|
|
function AddFont(const AFont: TsFont): Integer; overload;
|
|
|
|
procedure CopyFontList(ASource: TFPList);
|
|
|
|
function FindFont(const AFontName: String; ASize: Single;
|
|
|
|
AStyle: TsFontStyles; AColor: TsColor): Integer;
|
2014-06-06 13:09:14 +00:00
|
|
|
function GetDefaultFont: TsFont;
|
2014-05-31 21:04:53 +00:00
|
|
|
function GetDefaultFontSize: Single;
|
2014-04-22 23:10:32 +00:00
|
|
|
function GetFont(AIndex: Integer): TsFont;
|
|
|
|
function GetFontCount: Integer;
|
|
|
|
procedure InitFonts;
|
|
|
|
procedure RemoveAllFonts;
|
|
|
|
procedure SetDefaultFont(const AFontName: String; ASize: Single);
|
2014-05-31 21:04:53 +00:00
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{ Color handling }
|
2014-05-27 13:09:23 +00:00
|
|
|
function AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
2014-04-23 22:29:32 +00:00
|
|
|
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
2014-04-24 21:27:57 +00:00
|
|
|
function GetColorName(AColorIndex: TsColor): string;
|
|
|
|
function GetPaletteColor(AColorIndex: TsColor): TsColorValue;
|
2014-05-27 22:12:48 +00:00
|
|
|
function GetPaletteColorAsHTMLStr(AColorIndex: TsColor): String;
|
2014-04-24 21:27:57 +00:00
|
|
|
procedure SetPaletteColor(AColorIndex: TsColor; AColorValue: TsColorValue);
|
2014-04-23 22:29:32 +00:00
|
|
|
function GetPaletteSize: Integer;
|
2014-05-27 16:21:59 +00:00
|
|
|
procedure UseDefaultPalette;
|
2014-04-24 21:27:57 +00:00
|
|
|
procedure UsePalette(APalette: PsPalette; APaletteCount: Word;
|
|
|
|
ABigEndian: Boolean = false);
|
2014-05-31 21:04:53 +00:00
|
|
|
|
|
|
|
{@@ The default column width given in "character units" (width of the
|
|
|
|
character "0" in the default font) }
|
|
|
|
property DefaultColWidth: Single read FDefaultColWidth;
|
|
|
|
{@@ The default row height is given in "line count" (height of the
|
|
|
|
default font }
|
|
|
|
property DefaultRowHeight: Single read FDefaultRowHeight;
|
2010-07-30 06:44:53 +00:00
|
|
|
{@@ This property is only used for formats which don't support unicode
|
|
|
|
and support a single encoding for the whole document, like Excel 2 to 5 }
|
|
|
|
property Encoding: TsEncoding read FEncoding write FEncoding;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Identifies the file format which was detected when reading the file }
|
2014-04-21 21:43:43 +00:00
|
|
|
property FileFormat: TsSpreadsheetFormat read FFormat;
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ This property allows to turn off reading of rpn formulas; this is a
|
|
|
|
precaution since formulas not correctly implemented by fpspreadsheet
|
|
|
|
could crash the reading operation. }
|
2014-05-23 13:16:01 +00:00
|
|
|
property ReadFormulas: Boolean read FReadFormulas write FReadFormulas;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Contents of a number format record }
|
2014-05-14 15:24:02 +00:00
|
|
|
TsNumFormatData = class
|
|
|
|
public
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Excel refers to a number format by means of the format "index". }
|
2014-05-14 15:24:02 +00:00
|
|
|
Index: Integer;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ OpenDocument refers to a number format by means of the format "name". }
|
2014-05-26 08:03:36 +00:00
|
|
|
Name: String;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Identifier of a built-in number format, see TsNumberFormat }
|
2014-05-14 15:24:02 +00:00
|
|
|
NumFormat: TsNumberFormat;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ String of format codes, such as '#,##0.00', or 'hh:nn'. }
|
2014-05-14 15:24:02 +00:00
|
|
|
FormatString: string;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@ Specialized list for number format items }
|
|
|
|
TsCustomNumFormatList = class(TFPList)
|
|
|
|
private
|
|
|
|
function GetItem(AIndex: Integer): TsNumFormatData;
|
|
|
|
procedure SetItem(AIndex: Integer; AValue: TsNumFormatData);
|
|
|
|
protected
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Workbook from which the number formats are collected in the list. It is
|
|
|
|
mainly needed to get access to the FormatSettings for easy localization of some
|
|
|
|
formatting strings. }
|
2014-05-19 22:26:42 +00:00
|
|
|
FWorkbook: TsWorkbook;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Identifies the first number format item that is written to the file. Items
|
|
|
|
having a smaller index are not written. }
|
2014-05-14 15:24:02 +00:00
|
|
|
FFirstFormatIndexInFile: Integer;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Identifies the index of the next Excel number format item to be written.
|
|
|
|
Needed for auto-creating of the user-defined Excel number format indexes }
|
2014-05-14 15:24:02 +00:00
|
|
|
FNextFormatIndex: Integer;
|
|
|
|
procedure AddBuiltinFormats; virtual;
|
|
|
|
procedure RemoveFormat(AIndex: Integer);
|
2014-06-20 23:06:29 +00:00
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
public
|
2014-05-20 16:13:48 +00:00
|
|
|
constructor Create(AWorkbook: TsWorkbook);
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor Destroy; override;
|
|
|
|
function AddFormat(AFormatCell: PCell): Integer; overload;
|
2014-05-26 08:03:36 +00:00
|
|
|
function AddFormat(AFormatIndex: Integer; AFormatName, AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat: TsNumberFormat): Integer; overload;
|
2014-05-21 12:12:16 +00:00
|
|
|
function AddFormat(AFormatIndex: Integer; AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat: TsNumberFormat): Integer; overload;
|
2014-05-26 08:03:36 +00:00
|
|
|
function AddFormat(AFormatName, AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat: TsNumberFormat): Integer; overload;
|
|
|
|
function AddFormat(AFormatString: String; ANumFormat: TsNumberFormat): Integer; overload;
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure AnalyzeAndAdd(AFormatIndex: Integer; AFormatString: String);
|
|
|
|
procedure Clear;
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure ConvertAfterReading(AFormatIndex: Integer; var AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
var ANumFormat: TsNumberFormat); virtual;
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure ConvertBeforeWriting(var AFormatString: String;
|
2014-06-13 13:33:02 +00:00
|
|
|
var ANumFormat: TsNumberFormat); virtual;
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure Delete(AIndex: Integer);
|
2014-06-12 22:20:45 +00:00
|
|
|
function Find(ANumFormat: TsNumberFormat; AFormatString: String): Integer; overload;
|
2014-05-21 12:12:16 +00:00
|
|
|
function Find(AFormatString: String): Integer; overload;
|
2014-05-26 22:27:07 +00:00
|
|
|
function FindByIndex(AFormatIndex: Integer): Integer;
|
|
|
|
function FindByName(AFormatName: String): Integer;
|
2014-05-21 23:01:07 +00:00
|
|
|
function FindFormatOf(AFormatCell: PCell): integer; virtual;
|
2014-05-14 15:24:02 +00:00
|
|
|
function FormatStringForWriting(AIndex: Integer): String; virtual;
|
|
|
|
procedure Sort;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Workbook from which the number formats are collected in the list. It is
|
|
|
|
mainly needed to get access to the FormatSettings for easy localization of some
|
|
|
|
formatting strings. }
|
2014-05-19 22:26:42 +00:00
|
|
|
property Workbook: TsWorkbook read FWorkbook;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Identifies the first number format item that is written to the file. Items
|
|
|
|
having a smaller index are not written. }
|
2014-05-14 15:24:02 +00:00
|
|
|
property FirstFormatIndexInFile: Integer read FFirstFormatIndexInFile;
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Number format items contained in the list }
|
2014-05-14 15:24:02 +00:00
|
|
|
property Items[AIndex: Integer]: TsNumFormatData read GetItem write SetItem; default;
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{ TsCustomSpreadReader }
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ TsSpreadReader class reference type }
|
2008-02-24 13:18:34 +00:00
|
|
|
TsSpreadReaderClass = class of TsCustomSpreadReader;
|
2009-01-10 21:47:59 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
|
|
|
Custom reader of spreadsheet files. "Custom" means that it provides only
|
|
|
|
the basic functionality. The main implementation is done in derived classes
|
|
|
|
for each individual file format.
|
|
|
|
}
|
2008-02-24 13:18:34 +00:00
|
|
|
TsCustomSpreadReader = class
|
|
|
|
protected
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ A copy of the workbook's FormatSetting to extract some localized number format information }
|
2008-02-24 13:18:34 +00:00
|
|
|
FWorkbook: TsWorkbook;
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ Instance of the worksheet which is currently being read. }
|
2014-04-20 14:57:23 +00:00
|
|
|
FWorksheet: TsWorksheet;
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ List of number formats found in the file }
|
2014-05-14 15:24:02 +00:00
|
|
|
FNumFormatList: TsCustomNumFormatList;
|
2014-05-15 12:53:56 +00:00
|
|
|
procedure CreateNumFormatList; virtual;
|
2014-04-21 11:30:22 +00:00
|
|
|
{ Record reading methods }
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Abstract method for reading a blank cell. Must be overridden by descendent classes. }
|
2014-04-21 21:43:43 +00:00
|
|
|
procedure ReadBlank(AStream: TStream); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Abstract method for reading a formula cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure ReadFormula(AStream: TStream); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Abstract method for reading a text cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure ReadLabel(AStream: TStream); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Abstract method for reading a number cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure ReadNumber(AStream: TStream); virtual; abstract;
|
2008-02-24 13:18:34 +00:00
|
|
|
public
|
2014-04-23 22:29:32 +00:00
|
|
|
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor Destroy; override;
|
2008-02-24 13:18:34 +00:00
|
|
|
{ General writing methods }
|
|
|
|
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
|
2009-01-10 21:47:59 +00:00
|
|
|
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
|
2013-06-11 14:15:59 +00:00
|
|
|
procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); virtual;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Instance of the workbook which is currently being read. }
|
2014-04-23 22:29:32 +00:00
|
|
|
property Workbook: TsWorkbook read FWorkbook;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ List of number formats found in the file. }
|
2014-05-14 15:24:02 +00:00
|
|
|
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{ TsCustomSpreadWriter }
|
|
|
|
|
|
|
|
{@@ TsSpreadWriter class reference type }
|
2008-02-24 13:18:34 +00:00
|
|
|
TsSpreadWriterClass = class of TsCustomSpreadWriter;
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Callback function when iterating cells while accessing a stream }
|
2011-05-25 15:50:18 +00:00
|
|
|
TCellsCallback = procedure (ACell: PCell; AStream: TStream) of object;
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
|
|
|
Custom writer of spreadsheet files. "Custom" means that it provides only
|
|
|
|
the basic functionality. The main implementation is done in derived classes
|
|
|
|
for each individual file format. }
|
2008-02-24 13:18:34 +00:00
|
|
|
TsCustomSpreadWriter = class
|
2014-04-22 23:10:32 +00:00
|
|
|
private
|
2014-04-23 22:29:32 +00:00
|
|
|
FWorkbook: TsWorkbook;
|
2014-06-23 21:49:20 +00:00
|
|
|
|
2014-04-21 11:30:22 +00:00
|
|
|
protected
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ List of number formats found in the workbook. }
|
2014-05-14 15:24:02 +00:00
|
|
|
FNumFormatList: TsCustomNumFormatList;
|
2014-04-21 11:30:22 +00:00
|
|
|
{ Helper routines }
|
|
|
|
procedure AddDefaultFormats(); virtual;
|
2014-05-15 12:53:56 +00:00
|
|
|
procedure CreateNumFormatList; virtual;
|
2014-04-21 11:30:22 +00:00
|
|
|
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
|
|
|
|
function FindFormattingInList(AFormat: PCell): Integer;
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure FixFormat(ACell: PCell); virtual;
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
|
2014-05-21 23:01:07 +00:00
|
|
|
procedure ListAllFormattingStyles; virtual;
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
|
|
|
|
procedure ListAllNumFormats; virtual;
|
2014-04-21 11:30:22 +00:00
|
|
|
{ Helpers for writing }
|
|
|
|
procedure WriteCellCallback(ACell: PCell; AStream: TStream);
|
|
|
|
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
|
|
|
|
{ Record writing methods }
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for writing a blank cell. Must be overridden by descendent classes. }
|
2014-04-21 21:43:43 +00:00
|
|
|
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for a date/time value to a cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; const AValue: TDateTime; ACell: PCell); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for a formula to a cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsFormula; ACell: PCell); virtual;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for am RPN formula to a cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); virtual;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for a string to a cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ abstract method for a number value to a cell. Must be overridden by descendent classes. }
|
2014-04-21 11:30:22 +00:00
|
|
|
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); virtual; abstract;
|
2014-06-23 21:49:20 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
public
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ An array with cells which are models for the used styles
|
|
|
|
In this array the Row property holds the index to the corresponding XF field }
|
2011-05-27 13:14:14 +00:00
|
|
|
FFormattingStyles: array of TCell;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Indicates which should be the next XF (style) index when filling the FFormattingStyles array }
|
|
|
|
NextXFIndex: Integer;
|
2014-04-23 22:29:32 +00:00
|
|
|
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor Destroy; override;
|
2008-02-24 13:18:34 +00:00
|
|
|
{ General writing methods }
|
2011-05-25 15:50:18 +00:00
|
|
|
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
2014-04-23 22:29:32 +00:00
|
|
|
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
|
|
|
|
procedure WriteToStream(AStream: TStream); virtual;
|
|
|
|
procedure WriteToStrings(AStrings: TStrings); virtual;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ Instance of the workbook which is currently being saved. }
|
2014-04-23 22:29:32 +00:00
|
|
|
property Workbook: TsWorkbook read FWorkbook;
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@ List of number formats found in the workbook. }
|
2014-05-14 15:24:02 +00:00
|
|
|
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@ List of registered formats }
|
|
|
|
TsSpreadFormatData = record
|
|
|
|
ReaderClass: TsSpreadReaderClass;
|
|
|
|
WriterClass: TsSpreadWriterClass;
|
|
|
|
Format: TsSpreadsheetFormat;
|
|
|
|
end;
|
2014-04-08 09:48:30 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{ Simple creation an RPNFormula array to be used in fpspreadsheet. }
|
|
|
|
|
|
|
|
{@@ Helper record for simplification of RPN formula creation }
|
2014-04-08 09:48:30 +00:00
|
|
|
PRPNItem = ^TRPNItem;
|
|
|
|
TRPNItem = record
|
|
|
|
FE: TsFormulaElement;
|
|
|
|
Next: PRPNItem;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function CreateRPNFormula(AItem: PRPNItem): TsRPNFormula;
|
2014-05-23 13:16:01 +00:00
|
|
|
procedure DestroyRPNFormula(AItem: PRPNItem);
|
2014-04-08 09:48:30 +00:00
|
|
|
|
|
|
|
function RPNBool(AValue: Boolean;
|
|
|
|
ANext: PRPNItem): PRPNItem;
|
|
|
|
function RPNCellValue(ACellAddress: String;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNCellValue(ARow, ACol: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNCellRef(ACellAddress: String;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNCellRef(ARow, ACol: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNCellRange(ACellRangeAddress: String;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNCellRange(ARow, ACol, ARow2, ACol2: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem; overload;
|
2014-05-23 13:16:01 +00:00
|
|
|
function RPNErr(AErrCode: Byte; ANext: PRPNItem): PRPNItem;
|
|
|
|
function RPNInteger(AValue: Word; ANext: PRPNItem): PRPNItem;
|
2014-04-08 09:48:30 +00:00
|
|
|
function RPNMissingArg(ANext: PRPNItem): PRPNItem;
|
|
|
|
function RPNNumber(AValue: Double; ANext: PRPNItem): PRPNItem;
|
2014-05-23 23:13:49 +00:00
|
|
|
function RPNParenthesis(ANext: PRPNItem): PRPNItem;
|
2014-04-08 09:48:30 +00:00
|
|
|
function RPNString(AValue: String; ANext: PRPNItem): PRPNItem;
|
|
|
|
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem; overload;
|
|
|
|
|
2014-05-24 17:11:05 +00:00
|
|
|
function FixedParamCount(AElementKind: TFEKind): Boolean;
|
2014-04-21 21:43:43 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
var
|
|
|
|
GsSpreadFormats: array of TsSpreadFormatData;
|
|
|
|
|
|
|
|
procedure RegisterSpreadFormat(
|
|
|
|
AReaderClass: TsSpreadReaderClass;
|
|
|
|
AWriterClass: TsSpreadWriterClass;
|
|
|
|
AFormat: TsSpreadsheetFormat);
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure CopyCellFormat(AFromCell, AToCell: PCell);
|
2014-04-21 21:43:43 +00:00
|
|
|
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
|
2014-04-24 21:27:57 +00:00
|
|
|
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
implementation
|
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
uses
|
2014-06-27 14:24:23 +00:00
|
|
|
Math, StrUtils, TypInfo, fpsUtils, fpsNumFormatParser, fpsMath;
|
2009-09-02 22:03:01 +00:00
|
|
|
|
2014-04-20 20:31:36 +00:00
|
|
|
{ Translatable strings }
|
|
|
|
resourcestring
|
|
|
|
lpUnsupportedReadFormat = 'Tried to read a spreadsheet using an unsupported format';
|
|
|
|
lpUnsupportedWriteFormat = 'Tried to write a spreadsheet using an unsupported format';
|
2014-04-22 23:10:32 +00:00
|
|
|
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
|
2014-04-21 21:43:43 +00:00
|
|
|
lpUnknownSpreadsheetFormat = 'unknown format';
|
2014-04-22 23:10:32 +00:00
|
|
|
lpInvalidFontIndex = 'Invalid font index';
|
2014-05-20 16:13:48 +00:00
|
|
|
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
2014-06-12 22:20:45 +00:00
|
|
|
lpInvalidDateTimeFormat = 'Trying to use an incompatible date/time format.';
|
2014-05-20 16:13:48 +00:00
|
|
|
lpNoValidNumberFormatString = 'No valid number format string.';
|
|
|
|
lpNoValidDateTimeFormatString = 'No valid date/time format string.';
|
2014-05-24 19:44:40 +00:00
|
|
|
lpNoValidCellAddress = '"%s" is not a valid cell address.';
|
|
|
|
lpNoValidCellRangeAddress = '"%s" is not a valid cell range address.';
|
2014-05-21 12:12:16 +00:00
|
|
|
lpIllegalNumberFormat = 'Illegal number format.';
|
2014-05-24 17:11:05 +00:00
|
|
|
lpSpecifyNumberOfParams = 'Specify number of parameters for function %s';
|
|
|
|
lpIncorrectParamCount = 'Funtion %s requires at least %d and at most %d parameters.';
|
2014-05-14 23:17:46 +00:00
|
|
|
lpTRUE = 'TRUE';
|
|
|
|
lpFALSE = 'FALSE';
|
|
|
|
lpErrEmptyIntersection = '#NULL!';
|
|
|
|
lpErrDivideByZero = '#DIV/0!';
|
|
|
|
lpErrWrongType = '#VALUE!';
|
|
|
|
lpErrIllegalRef = '#REF!';
|
|
|
|
lpErrWrongName = '#NAME?';
|
|
|
|
lpErrOverflow = '#NUM!';
|
2014-05-25 16:49:45 +00:00
|
|
|
lpErrArgError = '#N/A';
|
2014-05-23 13:16:01 +00:00
|
|
|
lpErrFormulaNotSupported = '<FORMULA?>';
|
2014-04-21 21:43:43 +00:00
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
var
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ RGB colors RGB in "big-endian" notation (red at left). The values are inverted
|
2014-04-24 21:27:57 +00:00
|
|
|
at initialization to be little-endian at run-time!
|
2014-06-21 20:25:01 +00:00
|
|
|
The indices into this palette are named as scXXXX color constants. }
|
2014-04-24 21:27:57 +00:00
|
|
|
DEFAULT_PALETTE: array[$00..$16] of TsColorValue = (
|
2014-04-23 22:29:32 +00:00
|
|
|
$000000, // $00: black
|
|
|
|
$FFFFFF, // $01: white
|
|
|
|
$FF0000, // $02: red
|
|
|
|
$00FF00, // $03: green
|
|
|
|
$0000FF, // $04: blue
|
|
|
|
$FFFF00, // $05: yellow
|
|
|
|
$FF00FF, // $06: magenta
|
|
|
|
$00FFFF, // $07: cyan
|
2014-04-24 21:27:57 +00:00
|
|
|
$800000, // $08: dark red
|
|
|
|
$008000, // $09: dark green
|
|
|
|
$000080, // $0A: dark blue
|
|
|
|
$808000, // $0B: olive
|
|
|
|
$800080, // $0C: purple
|
|
|
|
$008080, // $0D: teal
|
|
|
|
$C0C0C0, // $0E: silver
|
|
|
|
$808080, // $0F: gray
|
|
|
|
$E6E6E6, // $10: gray 10%
|
|
|
|
$CCCCCC, // $11: gray 20%
|
|
|
|
$FFA500, // $12: orange
|
|
|
|
$A0522D, // $13: dark brown
|
|
|
|
$CD853F, // $14: brown
|
|
|
|
$F5F5DC, // $15: beige
|
|
|
|
$F5DEB3 // $16: wheat
|
|
|
|
);
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Names of the colors of the DEFAULT_PALETTE }
|
2014-04-24 21:27:57 +00:00
|
|
|
DEFAULT_COLORNAMES: array[$00..$16] of string = (
|
|
|
|
'black', // 0
|
|
|
|
'white', // 1
|
|
|
|
'red', // 2
|
|
|
|
'green', // 3
|
|
|
|
'blue', // 4
|
|
|
|
'yellow', // 5
|
|
|
|
'magenta', // 6
|
|
|
|
'cyan', // 7
|
|
|
|
'dark red', // 8
|
|
|
|
'dark green', // 9
|
|
|
|
'dark blue', // $0A
|
|
|
|
'olive', // $0B
|
|
|
|
'purple', // $0C
|
|
|
|
'teal', // $0D
|
|
|
|
'silver', // $0E
|
|
|
|
'gray', // $0F
|
|
|
|
'gray 10%', // $10
|
|
|
|
'gray 20%', // $11
|
|
|
|
'orange', // $12
|
|
|
|
'dark brown', // $13
|
|
|
|
'brown', // $14
|
|
|
|
'beige', // $15
|
|
|
|
'wheat' // $16
|
2014-04-23 22:29:32 +00:00
|
|
|
);
|
2009-01-10 21:47:59 +00:00
|
|
|
|
2014-05-24 17:11:05 +00:00
|
|
|
|
|
|
|
{ Properties of formula elements }
|
|
|
|
|
|
|
|
type
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ Properties of formula elements:
|
|
|
|
@param Symbol Symbol used in the formula
|
|
|
|
@param MinParams Minimum count of parameters used in this function
|
2014-06-27 14:24:23 +00:00
|
|
|
@param MaxParams Maximum count of parameters used in this function
|
|
|
|
@param Func Function to be calculated }
|
|
|
|
TFEProp = record
|
|
|
|
Symbol: String;
|
|
|
|
MinParams, MaxParams: Byte;
|
|
|
|
Func: TsFormulaFunc;
|
|
|
|
end;
|
2014-05-24 17:11:05 +00:00
|
|
|
|
|
|
|
const
|
|
|
|
FEProps: array[TFEKind] of TFEProp = (
|
|
|
|
{ Operands }
|
2014-06-28 19:40:28 +00:00
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCell
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellRef
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellRange
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellNum
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellInteger
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellString
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellBool
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellErr
|
|
|
|
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellMissingArg
|
2014-05-24 17:11:05 +00:00
|
|
|
{ Basic operations }
|
2014-06-28 19:40:28 +00:00
|
|
|
(Symbol:'+'; MinParams:2; MaxParams:2; Func:fpsAdd), // fekAdd
|
|
|
|
(Symbol:'-'; MinParams:2; MaxParams:2; Func:fpsSub), // fekSub
|
|
|
|
(Symbol:'*'; MinParams:2; MaxParams:2; Func:fpsMul), // fekMul
|
|
|
|
(Symbol:'/'; MinParams:2; MaxParams:2; Func:fpsDiv), // fekDiv
|
|
|
|
(Symbol:'%'; MinParams:1; MaxParams:1; Func:fpsPercent), // fekPercent
|
|
|
|
(Symbol:'^'; MinParams:2; MaxParams:2; Func:fpsPower), // fekPower
|
|
|
|
(Symbol:'-'; MinParams:1; MaxParams:1; Func:fpsUMinus), // fekUMinus
|
|
|
|
(Symbol:'+'; MinParams:1; MaxParams:1; Func:fpsUPlus), // fekUPlus
|
|
|
|
(Symbol:'&'; MinParams:2; MaxParams:2; Func:fpsConcat), // fekConcat (string concatenation)
|
2014-06-29 09:55:47 +00:00
|
|
|
(Symbol:'='; MinParams:2; MaxParams:2; Func:fpsEqual), // fekEqual
|
|
|
|
(Symbol:'>'; MinParams:2; MaxParams:2; Func:fpsGreater), // fekGreater
|
|
|
|
(Symbol:'>='; MinParams:2; MaxParams:2; Func:fpsGreaterEqual), // fekGreaterEqual
|
|
|
|
(Symbol:'<'; MinParams:2; MaxParams:2; Func:fpsLess), // fekLess
|
|
|
|
(Symbol:'<='; MinParams:2; MaxParams:2; Func:fpsLessEqual), // fekLessEqual
|
|
|
|
(Symbol:'<>'; MinParams:2; MaxParams:2; Func:fpsNotEqual), // fekNotEqual
|
2014-06-28 19:40:28 +00:00
|
|
|
(Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen
|
2014-05-24 17:11:05 +00:00
|
|
|
{ math }
|
2014-06-30 13:21:04 +00:00
|
|
|
(Symbol:'ABS'; MinParams:1; MaxParams:1; Func:fpsABS), // fekABS
|
|
|
|
(Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:fpsACOS), // fekACOS
|
|
|
|
(Symbol:'ACOSH'; MinParams:1; MaxParams:1; Func:fpsACOSH), // fekACOSH
|
|
|
|
(Symbol:'ASIN'; MinParams:1; MaxParams:1; Func:fpsASIN), // fekASIN
|
|
|
|
(Symbol:'ASINH'; MinParams:1; MaxParams:1; Func:fpsASINH), // fekASINH
|
|
|
|
(Symbol:'ATAN'; MinParams:1; MaxParams:1; Func:fpsATAN), // fekATAN
|
|
|
|
(Symbol:'ATANH'; MinParams:1; MaxParams:1; Func:fpsATANH), // fekATANH,
|
|
|
|
(Symbol:'COS'; MinParams:1; MaxParams:1; Func:fpsCOS), // fekCOS
|
|
|
|
(Symbol:'COSH'; MinParams:1; MaxParams:1; Func:fpsCOSH), // fekCOSH
|
|
|
|
(Symbol:'DEGREES'; MinParams:1; MaxParams:1; Func:fpsDEGREES), // fekDEGREES
|
|
|
|
(Symbol:'EXP'; MinParams:1; MaxParams:1; Func:fpsEXP), // fekEXP
|
|
|
|
(Symbol:'INT'; MinParams:1; MaxParams:1; Func:fpsINT), // fekINT
|
|
|
|
(Symbol:'LN'; MinParams:1; MaxParams:1; Func:fpsLN), // fekLN
|
|
|
|
(Symbol:'LOG'; MinParams:1; MaxParams:2; Func:fpsLOG), // fekLOG,
|
|
|
|
(Symbol:'LOG10'; MinParams:1; MaxParams:1; Func:fpsLOG10), // fekLOG10
|
|
|
|
(Symbol:'PI'; MinParams:0; MaxParams:0; Func:fpsPI), // fekPI
|
|
|
|
(Symbol:'RADIANS'; MinParams:1; MaxParams:1; Func:fpsRADIANS), // fekRADIANS
|
|
|
|
(Symbol:'RAND'; MinParams:0; MaxParams:0; Func:fpsRAND), // fekRAND
|
|
|
|
(Symbol:'ROUND'; MinParams:2; MaxParams:2; Func:fpsROUND), // fekROUND,
|
|
|
|
(Symbol:'SIGN'; MinParams:1; MaxParams:1; Func:fpsSIGN), // fekSIGN
|
|
|
|
(Symbol:'SIN'; MinParams:1; MaxParams:1; Func:fpsSIN), // fekSIN
|
|
|
|
(Symbol:'SINH'; MinParams:1; MaxParams:1; Func:fpsSINH), // fekSINH
|
|
|
|
(Symbol:'SQRT'; MinParams:1; MaxParams:1; Func:fpsSQRT), // fekSQRT,
|
|
|
|
(Symbol:'TAN'; MinParams:1; MaxParams:1; Func:fpsTAN), // fekTAN
|
|
|
|
(Symbol:'TANH'; MinParams:1; MaxParams:1; Func:fpsTANH), // fekTANH,
|
2014-05-24 17:11:05 +00:00
|
|
|
{ date/time }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'DATE'; MinParams:3; MaxParams:3; Func:nil), // fekDATE
|
|
|
|
(Symbol:'DATEDIF'; MinParams:3; MaxParams:3; Func:nil), // fekDATEDIF
|
|
|
|
(Symbol:'DATEVALUE'; MinParams:1; MaxParams:1; Func:nil), // fekDATEVALUE
|
|
|
|
(Symbol:'DAY'; MinParams:1; MaxParams:1; Func:nil), // fekDAY
|
|
|
|
(Symbol:'HOUR'; MinParams:1; MaxParams:1; Func:nil), // fekHOUR
|
|
|
|
(Symbol:'MINUTE'; MinParams:1; MaxParams:1; Func:nil), // fekMINUTE
|
|
|
|
(Symbol:'MONTH'; MinParams:1; MaxParams:1; Func:nil), // fekMONTH
|
|
|
|
(Symbol:'NOW'; MinParams:0; MaxParams:0; Func:nil), // fekNOW
|
|
|
|
(Symbol:'SECOND'; MinParams:1; MaxParams:1; Func:nil), // fekSECOND
|
|
|
|
(Symbol:'TIME'; MinParams:3; MaxParams:3; Func:nil), // fekTIME
|
|
|
|
(Symbol:'TIMEVALUE'; MinParams:1; MaxParams:1; Func:nil), // fekTIMEVALUE
|
|
|
|
(Symbol:'TODAY'; MinParams:0; MaxParams:0; Func:nil), // fekTODAY
|
|
|
|
(Symbol:'WEEKDAY'; MinParams:1; MaxParams:2; Func:nil), // fekWEEKDAY
|
|
|
|
(Symbol:'YEAR'; MinParams:1; MaxParams:1; Func:nil), // fekYEAR
|
2014-05-24 17:11:05 +00:00
|
|
|
{ statistical }
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'AVEDEV'; MinParams:1; MaxParams:30; Func:fpsAVEDEV), // fekAVEDEV
|
|
|
|
(Symbol:'AVERAGE'; MinParams:1; MaxParams:30; Func:fpsAVERAGE), // fekAVERAGE
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'BETADIST'; MinParams:3; MaxParams:5; Func:nil), // fekBETADIST
|
|
|
|
(Symbol:'BETAINV'; MinParams:3; MaxParams:5; Func:nil), // fekBETAINV
|
|
|
|
(Symbol:'BINOMDIST'; MinParams:4; MaxParams:4; Func:nil), // fekBINOMDIST
|
|
|
|
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2; Func:nil), // fekCHIDIST
|
|
|
|
(Symbol:'CHIINV'; MinParams:2; MaxParams:2; Func:nil), // fekCHIINV
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:fpsCOUNT), // fekCOUNT
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:nil), // fekCOUNTA
|
|
|
|
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1; Func:nil), // fekCOUNTBLANK
|
|
|
|
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2; Func:nil), // fekCOUNTIF
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:fpsMAX), // fekMAX
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'MEDIAN'; MinParams:1; MaxParams:30; Func:nil), // fekMEDIAN
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'MIN'; MinParams:1; MaxParams:30; Func:fpsMIN), // fekMIN
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'PERMUT'; MinParams:2; MaxParams:2; Func:nil), // fekPERMUT
|
|
|
|
(Symbol:'POISSON'; MinParams:3; MaxParams:3; Func:nil), // fekPOISSON
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'PRODUCT'; MinParams:0; MaxParams:30; Func:fpsPRODUCT), // fekPRODUCT
|
|
|
|
(Symbol:'STDEV'; MinParams:1; MaxParams:30; Func:fpsSTDEV), // fekSTDEV
|
|
|
|
(Symbol:'STDEVP'; MinParams:1; MaxParams:30; Func:fpsSTDEVP), // fekSTDEVP
|
|
|
|
(Symbol:'SUM'; MinParams:0; MaxParams:30; Func:fpsSUM), // fekSUM
|
|
|
|
(Symbol:'SUMIF'; MinParams:2; MaxParams:3; Func:nil), // fekSUMIF
|
|
|
|
(Symbol:'SUMSQ'; MinParams:0; MaxParams:30; Func:fpsSUMSQ), // fekSUMSQ
|
|
|
|
(Symbol:'VAR'; MinParams:1; MaxParams:30; Func:fpsVAR), // fekVAR
|
|
|
|
(Symbol:'VARP'; MinParams:1; MaxParams:30; Func:fpsVARP), // fekVARP
|
2014-05-24 17:11:05 +00:00
|
|
|
{ financial }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'FV'; MinParams:3; MaxParams:5; Func:nil), // fekFV
|
|
|
|
(Symbol:'NPER'; MinParams:3; MaxParams:5; Func:nil), // fekNPER
|
|
|
|
(Symbol:'PMT'; MinParams:3; MaxParams:5; Func:nil), // fekPMT
|
|
|
|
(Symbol:'PV'; MinParams:3; MaxParams:5; Func:nil), // fekPV
|
|
|
|
(Symbol:'RATE'; MinParams:3; MaxParams:6; Func:nil), // fekRATE
|
2014-05-24 17:11:05 +00:00
|
|
|
{ logical }
|
2014-06-29 09:55:47 +00:00
|
|
|
(Symbol:'AND'; MinParams:0; MaxParams:30; Func:fpsAND), // fekAND
|
2014-06-30 10:39:49 +00:00
|
|
|
(Symbol:'FALSE'; MinParams:0; MaxParams:0; Func:fpsFALSE), // fekFALSE
|
|
|
|
(Symbol:'IF'; MinParams:2; MaxParams:3; Func:fpsIF), // fekIF
|
|
|
|
(Symbol:'NOT'; MinParams:1; MaxParams:1; Func:fpsNOT), // fekNOT
|
2014-06-30 08:41:29 +00:00
|
|
|
(Symbol:'OR'; MinParams:1; MaxParams:30; Func:fpsOR), // fekOR
|
2014-06-30 10:39:49 +00:00
|
|
|
(Symbol:'TRUE'; MinParams:0; MaxParams:0; Func:fpsTRUE), // fekTRUE
|
2014-05-24 17:11:05 +00:00
|
|
|
{ string }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'CHAR'; MinParams:1; MaxParams:1; Func:nil), // fekCHAR
|
|
|
|
(Symbol:'CODE'; MinParams:1; MaxParams:1; Func:nil), // fekCODE
|
|
|
|
(Symbol:'LEFT'; MinParams:1; MaxParams:2; Func:nil), // fekLEFT
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'LOWER'; MinParams:1; MaxParams:1; Func:fpsLOWER), // fekLOWER
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'MID'; MinParams:3; MaxParams:3; Func:nil), // fekMID
|
|
|
|
(Symbol:'PROPER'; MinParams:1; MaxParams:1; Func:nil), // fekPROPER
|
|
|
|
(Symbol:'REPLACE'; MinParams:4; MaxParams:4; Func:nil), // fekREPLACE
|
|
|
|
(Symbol:'RIGHT'; MinParams:1; MaxParams:2; Func:nil), // fekRIGHT
|
|
|
|
(Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4; Func:nil), // fekSUBSTITUTE
|
2014-06-30 15:49:49 +00:00
|
|
|
(Symbol:'TRIM'; MinParams:1; MaxParams:1; Func:fpsTRIM), // fekTRIM
|
|
|
|
(Symbol:'UPPER'; MinParams:1; MaxParams:1; Func:fpsUPPER), // fekUPPER
|
2014-05-24 17:11:05 +00:00
|
|
|
{ lookup/reference }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'COLUMN'; MinParams:0; MaxParams:1; Func:nil), // fekCOLUMN
|
|
|
|
(Symbol:'COLUMNS'; MinParams:1; MaxParams:1; Func:nil), // fekCOLUMNS
|
|
|
|
(Symbol:'ROW'; MinParams:0; MaxParams:1; Func:nil), // fekROW
|
|
|
|
(Symbol:'ROWS'; MinParams:1; MaxParams:1; Func:nil), // fekROWS
|
2014-05-24 17:11:05 +00:00
|
|
|
{ info }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'CELL'; MinParams:1; MaxParams:2; Func:nil), // fekCELLINFO
|
|
|
|
(Symbol:'INFO'; MinParams:1; MaxParams:1; Func:nil), // fekINFO
|
|
|
|
(Symbol:'ISBLANK'; MinParams:1; MaxParams:1; Func:nil), // fekIsBLANK
|
|
|
|
(Symbol:'ISERR'; MinParams:1; MaxParams:1; Func:nil), // fekIsERR
|
|
|
|
(Symbol:'ISERROR'; MinParams:1; MaxParams:1; Func:nil), // fekIsERROR
|
|
|
|
(Symbol:'ISLOGICAL'; MinParams:1; MaxParams:1; Func:nil), // fekIsLOGICAL
|
|
|
|
(Symbol:'ISNA'; MinParams:1; MaxParams:1; Func:nil), // fekIsNA
|
|
|
|
(Symbol:'ISNONTEXT'; MinParams:1; MaxParams:1; Func:nil), // fekIsNONTEXT
|
|
|
|
(Symbol:'ISNUMBER'; MinParams:1; MaxParams:1; Func:nil), // fekIsNUMBER
|
|
|
|
(Symbol:'ISREF'; MinParams:1; MaxParams:1; Func:nil), // fekIsRef
|
|
|
|
(Symbol:'ISTEXT'; MinParams:1; MaxParams:1; Func:nil), // fekIsTEXT
|
|
|
|
(Symbol:'VALUE'; MinParams:1; MaxParams:1; Func:nil), // fekValue
|
2014-05-24 17:11:05 +00:00
|
|
|
{ Other operations }
|
2014-06-27 14:24:23 +00:00
|
|
|
(Symbol:'SUM'; MinParams:1; MaxParams:1; Func:nil) // fekOpSUM (Unary sum operation). Note: CANNOT be used for summing sell contents; use fekSUM}
|
2014-05-24 17:11:05 +00:00
|
|
|
);
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Registers a new reader/writer pair for a given spreadsheet file format
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
procedure RegisterSpreadFormat(
|
|
|
|
AReaderClass: TsSpreadReaderClass;
|
|
|
|
AWriterClass: TsSpreadWriterClass;
|
|
|
|
AFormat: TsSpreadsheetFormat);
|
|
|
|
var
|
|
|
|
len: Integer;
|
|
|
|
begin
|
|
|
|
len := Length(GsSpreadFormats);
|
|
|
|
SetLength(GsSpreadFormats, len + 1);
|
|
|
|
|
|
|
|
GsSpreadFormats[len].ReaderClass := AReaderClass;
|
|
|
|
GsSpreadFormats[len].WriterClass := AWriterClass;
|
|
|
|
GsSpreadFormats[len].Format := AFormat;
|
|
|
|
end;
|
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Returns the name of the given spreadsheet file format.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
@param AFormat Identifier of the file format
|
|
|
|
@return 'BIFF2', 'BIFF3', 'BIFF4', 'BIFF5', 'BIFF8', 'OOXML', 'Open Document',
|
|
|
|
'CSV, 'WikiTable Pipes', or 'WikiTable WikiMedia"
|
2014-04-21 21:43:43 +00:00
|
|
|
}
|
|
|
|
function GetFileFormatName(AFormat: TsSpreadsheetFormat): string;
|
|
|
|
begin
|
|
|
|
case AFormat of
|
|
|
|
sfExcel2 : Result := 'BIFF2';
|
2014-06-25 08:38:39 +00:00
|
|
|
{
|
2014-04-21 21:43:43 +00:00
|
|
|
sfExcel3 : Result := 'BIFF3';
|
|
|
|
sfExcel4 : Result := 'BIFF4';
|
2014-06-25 08:38:39 +00:00
|
|
|
}
|
2014-04-21 21:43:43 +00:00
|
|
|
sfExcel5 : Result := 'BIFF5';
|
|
|
|
sfExcel8 : Result := 'BIFF8';
|
|
|
|
sfooxml : Result := 'OOXML';
|
|
|
|
sfOpenDocument : Result := 'Open Document';
|
|
|
|
sfCSV : Result := 'CSV';
|
|
|
|
sfWikiTable_Pipes : Result := 'WikiTable Pipes';
|
|
|
|
sfWikiTable_WikiMedia : Result := 'WikiTable WikiMedia';
|
|
|
|
else Result := lpUnknownSpreadsheetFormat;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
{@@
|
|
|
|
If a palette is coded as big-endian (e.g. by copying the rgb values from
|
|
|
|
the OpenOffice doc) the palette values can be converted by means of this
|
|
|
|
procedure to little-endian which is required internally by TsWorkbook.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param APalette Pointer to the palette to be converted. After conversion,
|
|
|
|
its color values are replaced.
|
|
|
|
@param APaletteSize Number of colors contained in the palette
|
2014-04-24 21:27:57 +00:00
|
|
|
}
|
|
|
|
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
2014-06-24 22:47:15 +00:00
|
|
|
{$PUSH}{$R-}
|
2014-04-24 21:27:57 +00:00
|
|
|
for i := 0 to APaletteSize-1 do
|
|
|
|
APalette^[i] := LongRGBToExcelPhysical(APalette^[i])
|
2014-06-24 22:47:15 +00:00
|
|
|
{$POP}
|
2014-04-24 21:27:57 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
{@@
|
|
|
|
Copies the format of a cell to another one.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AFromCell cell from which the format is to be copied
|
|
|
|
@param AToCell cell to which the format is to be copied
|
2014-05-21 12:12:16 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
end;
|
|
|
|
|
2013-12-22 14:02:04 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ TsWorksheet }
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Helper method for clearing the records in a spreadsheet.
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.RemoveCallback(data, arg: pointer);
|
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(arg);
|
2014-04-17 20:13:38 +00:00
|
|
|
{ The strings and dyn arrays must be reset to nil content manually, because
|
2009-04-23 12:23:09 +00:00
|
|
|
FreeMem only frees the record mem, without checking its content }
|
2014-04-17 20:13:38 +00:00
|
|
|
PCell(data).UTF8StringValue := '';
|
|
|
|
PCell(data).NumberFormatStr := '';
|
|
|
|
SetLength(PCell(data).RPNFormulaValue, 0);
|
2008-02-24 13:18:34 +00:00
|
|
|
FreeMem(data);
|
|
|
|
end;
|
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
function CompareCells(Item1, Item2: Pointer): Integer;
|
|
|
|
begin
|
|
|
|
result := PCell(Item1).Row - PCell(Item2).Row;
|
|
|
|
if Result = 0 then
|
|
|
|
Result := PCell(Item1).Col - PCell(Item2).Col;
|
|
|
|
end;
|
|
|
|
|
2012-06-13 15:24:44 +00:00
|
|
|
function CompareRows(Item1, Item2: Pointer): Integer;
|
|
|
|
begin
|
|
|
|
result := PRow(Item1).Row - PRow(Item2).Row;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function CompareCols(Item1, Item2: Pointer): Integer;
|
|
|
|
begin
|
|
|
|
result := PCol(Item1).Col - PCol(Item2).Col;
|
|
|
|
end;
|
2011-08-11 14:30:25 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Constructor of the TsWorksheet class.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
constructor TsWorksheet.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
FCells := TAVLTree.Create(@CompareCells);
|
2012-06-13 15:24:44 +00:00
|
|
|
FRows := TIndexedAVLTree.Create(@CompareRows);
|
|
|
|
FCols := TIndexedAVLTree.Create(@CompareCols);
|
2014-05-03 20:12:44 +00:00
|
|
|
|
2014-05-04 18:07:54 +00:00
|
|
|
FOptions := [soShowGridLines, soShowHeaders];
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Destructor of the TsWorksheet class.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
destructor TsWorksheet.Destroy;
|
|
|
|
begin
|
|
|
|
RemoveAllCells;
|
2012-06-13 15:24:44 +00:00
|
|
|
RemoveAllRows;
|
|
|
|
RemoveAllCols;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
FCells.Free;
|
2012-06-13 15:24:44 +00:00
|
|
|
FRows.Free;
|
|
|
|
FCols.Free;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
2014-06-27 14:24:23 +00:00
|
|
|
{@@
|
|
|
|
Helper method for clearing the records in a spreadsheet.
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.CalcFormulaCallback(data, arg: pointer);
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
Unused(arg);
|
|
|
|
cell := PCell(data);
|
|
|
|
|
|
|
|
// Empty cell or error cell --> nothing to do
|
|
|
|
if (cell = nil) or (cell^.ContentType = cctError) then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
// Cell contains an RPN formula --> calculate the formula
|
|
|
|
if Length(cell^.RPNFormulaValue) > 0 then
|
|
|
|
CalcRPNFormula(cell);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.CalcFormulas;
|
|
|
|
var
|
|
|
|
node: TAVLTreeNode;
|
|
|
|
begin
|
|
|
|
Node := FCells.FindLowest;
|
|
|
|
while Assigned(Node) do begin
|
|
|
|
CalcFormulaCallback(Node.Data, nil);
|
|
|
|
node := FCells.FindSuccessor(node);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{@@
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.CalcRPNFormula(ACell: PCell);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
formula: TsRPNFormula;
|
|
|
|
args: TsArgumentStack;
|
|
|
|
func: TsFormulaFunc;
|
|
|
|
val: TsArgument;
|
|
|
|
fe: TsFormulaElement;
|
|
|
|
begin
|
|
|
|
if (Length(ACell^.RPNFormulaValue) = 0) or
|
|
|
|
(ACell^.ContentType = cctError)
|
|
|
|
then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
args := TsArgumentStack.Create;
|
|
|
|
try
|
|
|
|
for i := 0 to Length(ACell^.RPNFormulaValue) - 1 do begin
|
|
|
|
fe := ACell^.RPNFormulaValue[i]; // "formula element"
|
|
|
|
case fe.ElementKind of
|
|
|
|
fekCell: ;
|
|
|
|
fekCellRef: ;
|
|
|
|
fekCellRange: ;
|
|
|
|
fekNum:
|
|
|
|
args.PushNumber(fe.DoubleValue);
|
|
|
|
fekInteger:
|
|
|
|
args.PushNumber(1.0*fe.IntValue);
|
|
|
|
fekString:
|
|
|
|
args.PushString(fe.StringValue);
|
|
|
|
fekBool:
|
|
|
|
args.PushBool(fe.DoubleValue <> 0.0);
|
|
|
|
fekMissingArg:
|
|
|
|
args.PushMissing;
|
|
|
|
fekParen: ; // visual effect only
|
|
|
|
fekErr:
|
|
|
|
exit;
|
|
|
|
else
|
|
|
|
func := FEProps[fe.ElementKind].Func;
|
|
|
|
if not Assigned(func) then begin
|
|
|
|
// calculation of function not implemented
|
|
|
|
exit;
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
if args.Count < fe.ParamsNum then begin
|
2014-06-27 14:24:23 +00:00
|
|
|
// not enough parameters
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
// Result of function
|
2014-06-30 08:41:29 +00:00
|
|
|
val := func(args, fe.ParamsNum);
|
2014-06-27 14:24:23 +00:00
|
|
|
// Push valid result on stack, exit in case of error
|
|
|
|
case val.ArgumentType of
|
2014-06-30 10:39:49 +00:00
|
|
|
atNumber, atString, atBool, atEmpty:
|
2014-06-27 14:24:23 +00:00
|
|
|
args.Push(val);
|
|
|
|
atError:
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
|
|
|
WriteErrorValue(ACell, val.ErrorValue);
|
|
|
|
exit;
|
|
|
|
end;
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
end; // case
|
|
|
|
end; // for
|
|
|
|
if args.Count = 1 then begin
|
|
|
|
val := args.Pop;
|
|
|
|
case val.ArgumentType of
|
|
|
|
atNumber: WriteNumber(ACell, val.NumberValue);
|
2014-06-29 09:55:47 +00:00
|
|
|
atBool : WriteBoolValue(ACell, val.BoolValue);
|
2014-06-27 14:24:23 +00:00
|
|
|
atString: WriteUTF8Text(ACell, val.StringValue);
|
2014-06-30 10:39:49 +00:00
|
|
|
atEmpty : WriteBlank(ACell);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
end else
|
2014-06-28 19:40:28 +00:00
|
|
|
// This case is a program error --> raise an exception
|
|
|
|
raise Exception.CreateFmt('Incorrect argument count of the formula in cell %s', [
|
|
|
|
GetCellString(ACell^.Row, ACell^.Col, [])
|
|
|
|
]);
|
2014-06-27 14:24:23 +00:00
|
|
|
finally
|
|
|
|
args.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Converts a FPSpreadsheet cell position, which is Row, Col in numbers
|
|
|
|
and zero based, to a textual representation which is [Col][Row],
|
|
|
|
being that the Col is in letters and the row is in 1-based numbers }
|
2011-08-29 10:55:22 +00:00
|
|
|
class function TsWorksheet.CellPosToText(ARow, ACol: Cardinal): string;
|
|
|
|
var
|
|
|
|
lStr: string;
|
|
|
|
begin
|
|
|
|
lStr := '';
|
2011-08-29 13:01:53 +00:00
|
|
|
if ACol < 26 then lStr := Char(ACol+65);
|
2011-08-29 10:55:22 +00:00
|
|
|
|
|
|
|
Result := Format('%s%d', [lStr, ARow+1]);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Is called whenever a cell value or formatting has changed. Fires an event
|
|
|
|
"OnChangeCell". This is handled by TsWorksheetGrid to update the grid cell.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell which has been changed
|
|
|
|
@param ACol Column index of the cell which has been changed
|
|
|
|
}
|
2014-05-07 22:44:00 +00:00
|
|
|
procedure TsWorksheet.ChangedCell(ARow, ACol: Cardinal);
|
|
|
|
begin
|
|
|
|
if Assigned(FOnChangeCell) then FOnChangeCell(Self, ARow, ACol);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Is called whenever a font height changes. Fires an even "OnChangeFont"
|
|
|
|
which is handled by TsWorksheetGrid to update the row heights.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell for which the font height has changed
|
|
|
|
@param ACol Column index of the cell for which the font height has changed.
|
|
|
|
}
|
2014-05-08 21:52:04 +00:00
|
|
|
procedure TsWorksheet.ChangedFont(ARow, ACol: Cardinal);
|
|
|
|
begin
|
|
|
|
if Assigned(FonChangeFont) then FOnChangeFont(Self, ARow, ACol);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Copies a cell. The source cell can be located in a different worksheet, while
|
|
|
|
the destination cell must be in the same worksheet which calls the methode.
|
|
|
|
|
|
|
|
@param AFromRow Row index of the source cell
|
|
|
|
@param AFromCol Column index of the source cell
|
|
|
|
@param AToRow Row index of the destination cell
|
|
|
|
@param AToCol Column index of the destination cell
|
|
|
|
@param AFromWorksheet Worksheet containing the source cell.
|
|
|
|
}
|
2013-06-11 14:15:59 +00:00
|
|
|
procedure TsWorksheet.CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal;
|
|
|
|
AFromWorksheet: TsWorksheet);
|
|
|
|
var
|
2014-05-15 22:41:14 +00:00
|
|
|
lSrcCell, lDestCell: PCell;
|
2013-06-11 14:15:59 +00:00
|
|
|
begin
|
2014-05-15 22:41:14 +00:00
|
|
|
lSrcCell := AFromWorksheet.FindCell(AFromRow, AFromCol);
|
|
|
|
lDestCell := GetCell(AToRow, AToCol);
|
|
|
|
lDestCell^ := lSrcCell^;
|
|
|
|
lDestCell^.Row := AToRow;
|
|
|
|
lDestCell^.Col := AToCol;
|
|
|
|
ChangedCell(AToRow, AToCol);
|
|
|
|
ChangedFont(AToRow, AToCol);
|
|
|
|
{
|
2013-06-11 14:15:59 +00:00
|
|
|
lCurStr := AFromWorksheet.ReadAsUTF8Text(AFromRow, AFromCol);
|
|
|
|
lCurUsedFormatting := AFromWorksheet.ReadUsedFormatting(AFromRow, AFromCol);
|
|
|
|
lCurColor := AFromWorksheet.ReadBackgroundColor(AFromRow, AFromCol);
|
|
|
|
WriteUTF8Text(AToRow, AToCol, lCurStr);
|
|
|
|
WriteUsedFormatting(AToRow, AToCol, lCurUsedFormatting);
|
|
|
|
if uffBackgroundColor in lCurUsedFormatting then
|
|
|
|
begin
|
|
|
|
WriteBackgroundColor(AToRow, AToCol, lCurColor);
|
|
|
|
end;
|
2014-05-15 22:41:14 +00:00
|
|
|
}
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Copies all format parameters from the format cell to another cell.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AFromCell Pointer to source cell
|
|
|
|
@param AToCell Pointer to destination cell
|
2014-05-15 22:41:14 +00:00
|
|
|
}
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure TsWorksheet.CopyFormat(AFromCell, AToCell: PCell);
|
2014-05-15 22:41:14 +00:00
|
|
|
begin
|
2014-05-21 12:12:16 +00:00
|
|
|
if (AFromCell = nil) or (AToCell = nil) then
|
2014-05-15 22:41:14 +00:00
|
|
|
exit;
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
CopyCellFormat(AFromCell, AToCell);
|
|
|
|
ChangedCell(AToCell^.Row, AToCell^.Col);
|
|
|
|
ChangedFont(AToCell^.Row, AToCell^.Col);
|
|
|
|
end;
|
2014-05-15 22:41:14 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Copies all format parameters from a given cell to another cell identified
|
|
|
|
by its row/column indexes.
|
|
|
|
|
|
|
|
@param AFormat Pointer to the source cell from which the format is copied.
|
|
|
|
@param AToRow Row index of the destination cell
|
|
|
|
@param AToCol Column index of the destination cell
|
|
|
|
}
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure TsWorksheet.CopyFormat(AFormat: PCell; AToRow, AToCol: Cardinal);
|
|
|
|
begin
|
|
|
|
CopyFormat(AFormat, GetCell(AToRow, AToCol));
|
2013-06-11 14:15:59 +00:00
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2013-12-07 13:42:22 +00:00
|
|
|
Tries to locate a Cell in the list of already
|
2008-02-24 13:18:34 +00:00
|
|
|
written Cells
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
2014-06-21 20:25:01 +00:00
|
|
|
@return Pointer to the cell if found, or nil if not found
|
2008-02-24 13:18:34 +00:00
|
|
|
@see TCell
|
|
|
|
}
|
|
|
|
function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell;
|
|
|
|
var
|
2009-09-02 22:03:01 +00:00
|
|
|
LCell: TCell;
|
|
|
|
AVLNode: TAVLTreeNode;
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
|
|
|
Result := nil;
|
2009-09-02 22:03:01 +00:00
|
|
|
|
|
|
|
LCell.Row := ARow;
|
|
|
|
LCell.Col := ACol;
|
2009-10-06 19:25:18 +00:00
|
|
|
AVLNode := FCells.Find(@LCell);
|
2009-09-02 22:03:01 +00:00
|
|
|
if Assigned(AVLNode) then
|
|
|
|
result := PCell(AVLNode.Data);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Obtains an allocated cell at the desired location.
|
|
|
|
|
|
|
|
If the Cell already exists, a pointer to it will
|
|
|
|
be returned.
|
|
|
|
|
|
|
|
If not, then new memory for the cell will be allocated,
|
|
|
|
a pointer to it will be returned and it will be added
|
2014-06-21 20:25:01 +00:00
|
|
|
to the list of cells.
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
@return A pointer to the Cell on the desired location.
|
|
|
|
|
|
|
|
@see TCell
|
|
|
|
}
|
|
|
|
function TsWorksheet.GetCell(ARow, ACol: Cardinal): PCell;
|
|
|
|
begin
|
|
|
|
Result := FindCell(ARow, ACol);
|
|
|
|
|
|
|
|
if (Result = nil) then
|
|
|
|
begin
|
|
|
|
Result := GetMem(SizeOf(TCell));
|
|
|
|
FillChar(Result^, SizeOf(TCell), #0);
|
|
|
|
|
|
|
|
Result^.Row := ARow;
|
|
|
|
Result^.Col := ACol;
|
2014-05-28 07:53:50 +00:00
|
|
|
Result^.ContentType := cctEmpty;
|
2014-05-03 17:00:00 +00:00
|
|
|
Result^.BorderStyles := DEFAULT_BORDERSTYLES;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
Cells.Add(Result);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
|
|
|
Returns the number of cells in the worksheet with contents.
|
|
|
|
|
2009-10-06 19:25:18 +00:00
|
|
|
This routine is used together with GetFirstCell and GetNextCell
|
|
|
|
to iterate througth all cells in a worksheet efficiently.
|
2009-01-10 21:47:59 +00:00
|
|
|
|
|
|
|
@return The number of cells with contents in the worksheet
|
|
|
|
|
|
|
|
@see TCell
|
2009-10-06 19:25:18 +00:00
|
|
|
@see GetFirstCell
|
|
|
|
@see GetNextCell
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
|
|
|
function TsWorksheet.GetCellCount: Cardinal;
|
|
|
|
begin
|
2009-10-06 19:25:18 +00:00
|
|
|
Result := FCells.Count;
|
2009-01-10 21:47:59 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Determines some number format attributes (decimal places, currency symbol) of
|
|
|
|
a cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell under investigation
|
|
|
|
@param ADecimals Number of decimal places that can be extracted from
|
|
|
|
the formatting string, e.g. in case of '0.000' this
|
|
|
|
would be 3.
|
|
|
|
@param ACurrencySymbol String representing the currency symbol extracted from
|
|
|
|
the formatting string.
|
|
|
|
|
|
|
|
@return true if the the format string could be analyzed successfully, false if not
|
|
|
|
}
|
2014-06-13 07:59:42 +00:00
|
|
|
function TsWorksheet.GetNumberFormatAttributes(ACell: PCell; out ADecimals: byte;
|
|
|
|
out ACurrencySymbol: String): Boolean;
|
|
|
|
var
|
|
|
|
parser: TsNumFormatParser;
|
2014-06-13 10:03:29 +00:00
|
|
|
nf: TsNumberFormat;
|
2014-06-13 07:59:42 +00:00
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
if ACell <> nil then begin
|
|
|
|
parser := TsNumFormatParser.Create(FWorkbook, ACell^.NumberFormatStr);
|
|
|
|
try
|
|
|
|
if parser.Status = psOK then begin
|
2014-06-13 10:03:29 +00:00
|
|
|
nf := parser.NumFormat;
|
|
|
|
if (nf = nfGeneral) or IsDateTimeFormat(nf) then begin
|
|
|
|
ADecimals := 2;
|
|
|
|
ACurrencySymbol := '?';
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
ADecimals := parser.Decimals;
|
|
|
|
ACurrencySymbol := parser.CurrencySymbol;
|
|
|
|
end;
|
2014-06-13 07:59:42 +00:00
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
finally
|
|
|
|
parser.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-01-30 18:21:18 +00:00
|
|
|
{@@
|
2009-10-06 19:25:18 +00:00
|
|
|
Returns the first Cell.
|
|
|
|
|
|
|
|
Use together with GetCellCount and GetNextCell
|
|
|
|
to iterate througth all cells in a worksheet efficiently.
|
|
|
|
|
|
|
|
@return The first cell if any exists, nil otherwise
|
|
|
|
|
|
|
|
@see TCell
|
|
|
|
@see GetCellCount
|
|
|
|
@see GetNextCell
|
|
|
|
}
|
|
|
|
function TsWorksheet.GetFirstCell(): PCell;
|
|
|
|
begin
|
|
|
|
FCurrentNode := FCells.FindLowest();
|
|
|
|
if FCurrentNode <> nil then
|
|
|
|
Result := PCell(FCurrentNode.Data)
|
|
|
|
else Result := nil;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Returns the next Cell.
|
|
|
|
|
|
|
|
Should always be used either after GetFirstCell or
|
|
|
|
after GetNextCell.
|
|
|
|
|
|
|
|
Use together with GetCellCount and GetFirstCell
|
|
|
|
to iterate througth all cells in a worksheet efficiently.
|
|
|
|
|
|
|
|
@return The first cell if any exists, nil otherwise
|
|
|
|
|
|
|
|
@see TCell
|
|
|
|
@see GetCellCount
|
|
|
|
@see GetFirstCell
|
|
|
|
}
|
|
|
|
function TsWorksheet.GetNextCell(): PCell;
|
|
|
|
begin
|
|
|
|
FCurrentNode := FCells.FindSuccessor(FCurrentNode);
|
|
|
|
if FCurrentNode <> nil then
|
|
|
|
Result := PCell(FCurrentNode.Data)
|
|
|
|
else Result := nil;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-05-26 15:27:35 +00:00
|
|
|
Returns the 0-based index of the last column with a cell with contents.
|
2009-01-30 18:21:18 +00:00
|
|
|
|
|
|
|
If no cells have contents, zero will be returned, which is also a valid value.
|
|
|
|
|
|
|
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
|
|
|
worksheet.
|
|
|
|
|
|
|
|
@see GetCellCount
|
|
|
|
}
|
2014-05-26 15:27:35 +00:00
|
|
|
function TsWorksheet.GetLastColIndex: Cardinal;
|
2009-01-28 23:20:25 +00:00
|
|
|
var
|
2009-09-02 22:03:01 +00:00
|
|
|
AVLNode: TAVLTreeNode;
|
2014-05-31 21:04:53 +00:00
|
|
|
i: Integer;
|
2009-01-28 23:20:25 +00:00
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
// Traverse the tree from lowest to highest.
|
|
|
|
// Since tree primary sort order is on Row
|
|
|
|
// highest Col could exist anywhere.
|
2009-10-06 19:25:18 +00:00
|
|
|
AVLNode := FCells.FindLowest;
|
2009-09-02 22:03:01 +00:00
|
|
|
While Assigned(AVLNode) do
|
2009-01-28 23:20:25 +00:00
|
|
|
begin
|
2009-09-02 22:03:01 +00:00
|
|
|
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
|
2009-10-06 19:25:18 +00:00
|
|
|
AVLNode := FCells.FindSuccessor(AVLNode);
|
2009-01-28 23:20:25 +00:00
|
|
|
end;
|
2014-05-31 21:04:53 +00:00
|
|
|
|
|
|
|
// In addition, there may be column records defining the column width even
|
|
|
|
// without content
|
|
|
|
for i:=0 to FCols.Count-1 do
|
|
|
|
if FCols[i] <> nil then
|
|
|
|
Result := Math.Max(Result, PCol(FCols[i])^.Col);
|
2009-01-28 23:20:25 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Deprecated, use GetLastColIndex instead
|
|
|
|
|
|
|
|
@see GetLastColIndex
|
|
|
|
}
|
2014-05-26 15:27:35 +00:00
|
|
|
function TsWorksheet.GetLastColNumber: Cardinal;
|
|
|
|
begin
|
|
|
|
Result := GetLastColIndex;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Finds the first cell with contents in a given row
|
|
|
|
|
|
|
|
@param ARow Index of the row considered
|
|
|
|
@return Pointer to the first cell in this row, or nil if the row is empty.
|
|
|
|
}
|
2014-05-07 18:31:27 +00:00
|
|
|
function TsWorksheet.GetFirstCellOfRow(ARow: Cardinal): PCell;
|
|
|
|
var
|
|
|
|
c, n: Cardinal;
|
|
|
|
begin
|
2014-05-26 15:27:35 +00:00
|
|
|
n := GetLastColIndex;
|
2014-05-07 18:31:27 +00:00
|
|
|
c := 0;
|
|
|
|
Result := FindCell(ARow, c);
|
|
|
|
while (result = nil) and (c < n) do begin
|
|
|
|
inc(c);
|
|
|
|
result := FindCell(ARow, c);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Finds the last cell with contents in a given row
|
|
|
|
|
|
|
|
@param ARow Index of the row considered
|
|
|
|
@return Pointer to the last cell in this row, or nil if the row is empty.
|
|
|
|
}
|
2014-05-07 18:31:27 +00:00
|
|
|
function TsWorksheet.GetLastCellOfRow(ARow: Cardinal): PCell;
|
|
|
|
var
|
|
|
|
c, n: Cardinal;
|
|
|
|
begin
|
2014-05-26 15:27:35 +00:00
|
|
|
n := GetLastColIndex;
|
2014-05-07 18:31:27 +00:00
|
|
|
c := n;
|
|
|
|
Result := FindCell(ARow, c);
|
|
|
|
while (Result = nil) and (c > 0) do begin
|
|
|
|
dec(c);
|
|
|
|
Result := FindCell(ARow, c);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-01-30 18:21:18 +00:00
|
|
|
{@@
|
2014-05-26 15:27:35 +00:00
|
|
|
Returns the 0-based index of the last row with a cell with contents.
|
2009-01-30 18:21:18 +00:00
|
|
|
|
|
|
|
If no cells have contents, zero will be returned, which is also a valid value.
|
|
|
|
|
|
|
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
|
|
|
worksheet.
|
|
|
|
|
|
|
|
@see GetCellCount
|
|
|
|
}
|
2014-05-26 15:27:35 +00:00
|
|
|
function TsWorksheet.GetLastRowIndex: Cardinal;
|
2009-01-28 23:20:25 +00:00
|
|
|
var
|
2009-09-02 22:03:01 +00:00
|
|
|
AVLNode: TAVLTreeNode;
|
2014-05-31 21:04:53 +00:00
|
|
|
i: Integer;
|
2009-01-28 23:20:25 +00:00
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
|
2009-09-02 22:03:01 +00:00
|
|
|
AVLNode := FCells.FindHighest;
|
|
|
|
if Assigned(AVLNode) then
|
|
|
|
Result := PCell(AVLNode.Data).Row;
|
2014-05-31 21:04:53 +00:00
|
|
|
|
|
|
|
// In addition, there may be row records even for empty rows.
|
|
|
|
for i:=0 to FRows.Count-1 do
|
|
|
|
if FRows[i] <> nil then
|
|
|
|
Result := Math.Max(Result, PRow(FRows[i])^.Row);
|
2009-01-28 23:20:25 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Deprecated, use GetLastColIndex instead
|
|
|
|
|
|
|
|
@see GetLastColIndex
|
|
|
|
}
|
2014-05-26 15:27:35 +00:00
|
|
|
function TsWorksheet.GetLastRowNumber: Cardinal;
|
|
|
|
begin
|
|
|
|
Result := GetLastRowIndex;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
2009-01-28 17:18:04 +00:00
|
|
|
Reads the contents of a cell and returns an user readable text
|
|
|
|
representing the contents of the cell.
|
|
|
|
|
|
|
|
The resulting ansistring is UTF-8 encoded.
|
2009-01-10 21:47:59 +00:00
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@return The text representation of the cell
|
|
|
|
}
|
2009-01-28 17:18:04 +00:00
|
|
|
function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
|
2014-05-23 23:13:49 +00:00
|
|
|
begin
|
|
|
|
Result := ReadAsUTF8Text(GetCell(ARow, ACol));
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Reads the contents of a cell and returns an user readable text
|
|
|
|
representing the contents of the cell.
|
|
|
|
|
|
|
|
The resulting ansistring is UTF-8 encoded.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell
|
|
|
|
@return The text representation of the cell
|
|
|
|
}
|
2014-05-23 23:13:49 +00:00
|
|
|
function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
|
2013-12-22 14:02:04 +00:00
|
|
|
|
|
|
|
function FloatToStrNoNaN(const Value: Double;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
|
2014-05-17 15:13:08 +00:00
|
|
|
var
|
|
|
|
fs: TFormatSettings;
|
2014-05-22 21:54:24 +00:00
|
|
|
left, right: String;
|
2013-12-22 14:02:04 +00:00
|
|
|
begin
|
2014-05-17 15:13:08 +00:00
|
|
|
fs := FWorkbook.FormatSettings;
|
2013-12-22 14:02:04 +00:00
|
|
|
if IsNan(Value) then
|
|
|
|
Result := ''
|
|
|
|
else
|
|
|
|
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
|
2014-05-17 15:13:08 +00:00
|
|
|
Result := FloatToStr(Value, fs)
|
2013-12-22 14:02:04 +00:00
|
|
|
else
|
|
|
|
if (ANumberFormat = nfPercentage) then
|
2014-05-17 15:13:08 +00:00
|
|
|
Result := FormatFloat(ANumberFormatStr, Value*100, fs)
|
2013-12-22 14:02:04 +00:00
|
|
|
else
|
2014-05-17 15:13:08 +00:00
|
|
|
Result := FormatFloat(ANumberFormatStr, Value, fs)
|
2013-12-22 14:02:04 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function DateTimeToStrNoNaN(const Value: Double;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumberFormat: TsNumberFormat; ANumberFormatStr: String): ansistring;
|
2014-06-03 22:04:11 +00:00
|
|
|
var
|
|
|
|
fmtp, fmtn, fmt0: String;
|
2013-07-03 00:01:48 +00:00
|
|
|
begin
|
2013-12-22 14:02:04 +00:00
|
|
|
Result := '';
|
|
|
|
if not IsNaN(Value) then begin
|
|
|
|
if ANumberFormatStr = '' then
|
2014-05-21 16:23:38 +00:00
|
|
|
ANumberFormatStr := BuildDateTimeFormatString(ANumberFormat,
|
|
|
|
Workbook.FormatSettings, ANumberFormatStr);
|
2014-06-03 22:04:11 +00:00
|
|
|
// Saw strange cases in ods where date/time formats contained pos/neg/zero parts.
|
|
|
|
// Split to be on the safe side.
|
|
|
|
SplitFormatString(ANumberFormatStr, fmtp, fmtn, fmt0);
|
|
|
|
if (Value > 0) or ((Value = 0) and (fmt0 = '')) or ((Value < 0) and (fmtn = '')) then
|
|
|
|
Result := FormatDateTime(fmtp, Value, [fdoInterval])
|
|
|
|
else
|
|
|
|
if (Value < 0) then
|
|
|
|
Result := FormatDateTime(fmtn, Value, [fdoInterval])
|
|
|
|
else
|
|
|
|
if (Value = 0) then
|
|
|
|
Result := FormatDateTime(fmt0, Value, [fdoInterval]);
|
2013-12-22 14:02:04 +00:00
|
|
|
end;
|
2013-07-03 00:01:48 +00:00
|
|
|
end;
|
2013-12-22 14:02:04 +00:00
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
begin
|
2014-05-23 23:13:49 +00:00
|
|
|
Result := '';
|
2009-01-10 21:47:59 +00:00
|
|
|
if ACell = nil then
|
|
|
|
Exit;
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
with ACell^ do
|
|
|
|
case ContentType of
|
|
|
|
cctNumber:
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr);
|
2014-05-14 15:24:02 +00:00
|
|
|
cctUTF8String:
|
|
|
|
Result := UTF8StringValue;
|
|
|
|
cctDateTime:
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr);
|
2014-05-14 23:17:46 +00:00
|
|
|
cctBool:
|
2014-06-20 15:58:22 +00:00
|
|
|
Result := StrUtils.IfThen(BoolValue, lpTRUE, lpFALSE);
|
2014-05-14 23:17:46 +00:00
|
|
|
cctError:
|
2014-05-25 16:49:45 +00:00
|
|
|
case TsErrorValue(ErrorValue) of
|
2014-05-23 13:16:01 +00:00
|
|
|
errEmptyIntersection : Result := lpErrEmptyIntersection;
|
|
|
|
errDivideByZero : Result := lpErrDivideByZero;
|
|
|
|
errWrongType : Result := lpErrWrongType;
|
|
|
|
errIllegalRef : Result := lpErrIllegalRef;
|
|
|
|
errWrongName : Result := lpErrWrongName;
|
|
|
|
errOverflow : Result := lpErrOverflow;
|
2014-05-25 16:49:45 +00:00
|
|
|
errArgError : Result := lpErrArgError;
|
2014-05-23 13:16:01 +00:00
|
|
|
errFormulaNotSupported: Result := lpErrFormulaNotSupported;
|
2014-05-14 23:17:46 +00:00
|
|
|
end;
|
2014-05-14 15:24:02 +00:00
|
|
|
else
|
|
|
|
Result := '';
|
|
|
|
end;
|
2009-01-10 21:47:59 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Returns the value of a cell as a number.
|
|
|
|
|
|
|
|
If the cell contains a date/time value its serial value is returned
|
|
|
|
(as FPC TDateTime).
|
|
|
|
|
|
|
|
If the cell contains a text value it is attempted to convert it to a number.
|
|
|
|
|
|
|
|
If the cell is empty or its contents cannot be represented as a number the
|
|
|
|
value 0.0 is returned.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@return Floating-point value representing the cell contents, or 0.0 if cell
|
|
|
|
does not exist or its contents cannot be converted to a number.
|
|
|
|
}
|
2010-05-01 18:10:38 +00:00
|
|
|
function TsWorksheet.ReadAsNumber(ARow, ACol: Cardinal): Double;
|
2014-06-21 20:25:01 +00:00
|
|
|
begin
|
|
|
|
Result := ReadAsNumber(FindCell(ARow, ACol));
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Returns the value of a cell as a number.
|
|
|
|
|
|
|
|
If the cell contains a date/time value its serial value is returned
|
|
|
|
(as FPC TDateTime).
|
|
|
|
|
|
|
|
If the cell contains a text value it is attempted to convert it to a number.
|
|
|
|
|
|
|
|
If the cell is empty or its contents cannot be represented as a number the
|
|
|
|
value 0.0 is returned.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell
|
|
|
|
@return Floating-point value representing the cell contents, or 0.0 if cell
|
|
|
|
does not exist or its contents cannot be converted to a number.
|
|
|
|
}
|
|
|
|
function TsWorksheet.ReadAsNumber(ACell: PCell): Double;
|
2010-05-01 18:10:38 +00:00
|
|
|
begin
|
2014-05-17 15:13:08 +00:00
|
|
|
Result := 0.0;
|
2010-05-01 18:10:38 +00:00
|
|
|
if ACell = nil then
|
2014-05-17 15:13:08 +00:00
|
|
|
exit;
|
2010-05-01 18:10:38 +00:00
|
|
|
|
|
|
|
case ACell^.ContentType of
|
2014-05-17 15:13:08 +00:00
|
|
|
cctDateTime : Result := ACell^.DateTimeValue; //this is in FPC TDateTime format, not Excel
|
|
|
|
cctNumber : Result := ACell^.NumberValue;
|
2014-06-21 20:25:01 +00:00
|
|
|
cctUTF8String : if not TryStrToFloat(ACell^.UTF8StringValue, Result) then Result := 0.0;
|
|
|
|
cctBool : if ACell^.BoolValue then Result := 1.0 else Result := 0.0;
|
2010-05-01 18:10:38 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2012-01-23 13:24:13 +00:00
|
|
|
{@@
|
|
|
|
Reads the contents of a cell and returns the date/time value of the cell.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
2014-06-21 20:25:01 +00:00
|
|
|
@param AResult Date/time value of the cell (or 0.0, if no date/time cell)
|
2012-01-23 13:24:13 +00:00
|
|
|
@return True if the cell is a datetime value, false otherwise
|
|
|
|
}
|
|
|
|
function TsWorksheet.ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean;
|
|
|
|
begin
|
2014-06-21 20:25:01 +00:00
|
|
|
Result := ReadAsDateTime(FindCell(ARow, ACol), AResult);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Reads the contents of a cell and returns the date/time value of the cell.
|
2012-01-23 13:52:43 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ACell Pointer to the cell
|
|
|
|
@param AResult Date/time value of the cell (or 0.0, if no date/time cell)
|
|
|
|
@return True if the cell is a datetime value, false otherwise
|
|
|
|
}
|
|
|
|
function TsWorksheet.ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean;
|
|
|
|
begin
|
2012-01-23 13:52:43 +00:00
|
|
|
if (ACell = nil) or (ACell^.ContentType <> cctDateTime) then
|
|
|
|
begin
|
|
|
|
AResult := 0;
|
|
|
|
Result := False;
|
|
|
|
Exit;
|
|
|
|
end;
|
2012-01-23 13:24:13 +00:00
|
|
|
|
2012-01-23 13:52:43 +00:00
|
|
|
AResult := ACell^.DateTimeValue;
|
|
|
|
Result := True;
|
2012-01-23 13:24:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@ If a cell contains a formula (string formula or RPN formula) the formula
|
|
|
|
is returned as a string in Excel syntax.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@return Formula string in Excel syntax.
|
|
|
|
}
|
2014-06-06 15:48:02 +00:00
|
|
|
function TsWorksheet.ReadFormulaAsString(ACell: PCell): String;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if ACell = nil then
|
|
|
|
exit;
|
|
|
|
if Length(ACell^.RPNFormulaValue) > 0 then
|
|
|
|
Result := ReadRPNFormulaAsString(ACell)
|
|
|
|
else
|
|
|
|
Result := ACell^.FormulaValue.FormulaStr;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
If a cell contains an RPN formula an Excel-like formula string is constructed
|
|
|
|
and returned.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@return Formula string in Excel syntax.
|
|
|
|
}
|
2014-05-23 23:13:49 +00:00
|
|
|
function TsWorksheet.ReadRPNFormulaAsString(ACell: PCell): String;
|
|
|
|
var
|
2014-05-25 16:49:45 +00:00
|
|
|
fs: TFormatSettings;
|
2014-05-23 23:13:49 +00:00
|
|
|
elem: TsFormulaElement;
|
|
|
|
i, j: Integer;
|
|
|
|
L: TStringList;
|
|
|
|
s: String;
|
|
|
|
ptr: Pointer;
|
|
|
|
fek: TFEKind;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if ACell = nil then
|
|
|
|
exit;
|
|
|
|
|
2014-05-25 16:49:45 +00:00
|
|
|
fs := Workbook.FormatSettings;
|
2014-05-23 23:13:49 +00:00
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
for i:=0 to Length(ACell^.RPNFormulaValue)-1 do begin
|
|
|
|
elem := ACell^.RPNFormulaValue[i];
|
|
|
|
ptr := Pointer(elem.ElementKind);
|
|
|
|
case elem.ElementKind of
|
|
|
|
fekNum:
|
2014-05-25 16:49:45 +00:00
|
|
|
L.AddObject(Format('%g', [elem.DoubleValue], fs), ptr);
|
2014-05-23 23:13:49 +00:00
|
|
|
fekInteger:
|
|
|
|
L.AddObject(IntToStr(elem.IntValue), ptr);
|
|
|
|
fekString:
|
|
|
|
L.AddObject('"' + elem.StringValue + '"', ptr);
|
|
|
|
fekBool:
|
2014-05-25 16:49:45 +00:00
|
|
|
L.AddObject(IfThen(boolean(elem.IntValue), 'FALSE', 'TRUE'), ptr);
|
2014-05-23 23:13:49 +00:00
|
|
|
fekCell,
|
|
|
|
fekCellRef:
|
|
|
|
L.AddObject(GetCellString(elem.Row, elem.Col, elem.RelFlags), ptr);
|
|
|
|
fekCellRange:
|
|
|
|
L.AddObject(GetCellRangeString(elem.Row, elem.Col, elem.Row2, elem.Col2, elem.RelFlags), ptr);
|
|
|
|
// Operations:
|
|
|
|
else
|
2014-05-25 16:49:45 +00:00
|
|
|
L.AddObject(FEProps[elem.ElementKind].Symbol, ptr);
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
i := L.Count-1;
|
|
|
|
while (L.Count > 0) and (i >= 0) do begin
|
|
|
|
fek := TFEKind(PtrInt(L.Objects[i]));
|
|
|
|
case fek of
|
|
|
|
fekAdd, fekSub, fekMul, fekDiv, fekPower, fekConcat,
|
|
|
|
fekEqual, fekNotEqual, fekLess, fekLessEqual, fekGreater, fekGreaterEqual:
|
2014-05-25 16:49:45 +00:00
|
|
|
if i+2 < L.Count then begin
|
2014-05-23 23:13:49 +00:00
|
|
|
L.Strings[i] := Format('%s%s%s', [L[i+2], L[i], L[i+1]]);
|
|
|
|
L.Delete(i+2);
|
|
|
|
L.Delete(i+1);
|
2014-05-25 16:49:45 +00:00
|
|
|
L.Objects[i] := pointer(fekString);
|
|
|
|
end else begin
|
|
|
|
Result := '=' + lpErrArgError;
|
|
|
|
exit;
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
|
|
|
fekUPlus, fekUMinus:
|
2014-05-25 16:49:45 +00:00
|
|
|
if i+1 < L.Count then begin
|
2014-05-23 23:13:49 +00:00
|
|
|
L.Strings[i] := L[i]+L[i+1];
|
|
|
|
L.Delete(i+1);
|
2014-05-25 16:49:45 +00:00
|
|
|
L.Objects[i] := Pointer(fekString);
|
|
|
|
end else begin
|
|
|
|
Result := '=' + lpErrArgError;
|
|
|
|
exit;
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
|
|
|
fekPercent:
|
2014-05-25 16:49:45 +00:00
|
|
|
if i+1 < L.Count then begin
|
2014-05-23 23:13:49 +00:00
|
|
|
L.Strings[i] := L[i+1]+L[i];
|
|
|
|
L.Delete(i+1);
|
2014-05-25 16:49:45 +00:00
|
|
|
L.Objects[i] := Pointer(fekString);
|
|
|
|
end else begin
|
|
|
|
Result := '=' + lpErrArgError;
|
|
|
|
exit;
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
|
|
|
fekParen:
|
2014-05-25 16:49:45 +00:00
|
|
|
if i+1 < L.Count then begin
|
2014-05-23 23:13:49 +00:00
|
|
|
L.Strings[i] := Format('(%s)', [L[i+1]]);
|
|
|
|
L.Delete(i+1);
|
2014-05-25 16:49:45 +00:00
|
|
|
L.Objects[i] := pointer(fekString);
|
|
|
|
end else begin
|
|
|
|
Result := '=' + lpErrArgError;
|
|
|
|
exit;
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
|
|
|
else
|
|
|
|
if fek >= fekAdd then begin
|
|
|
|
elem := ACell^.RPNFormulaValue[i];
|
|
|
|
s := '';
|
|
|
|
for j:= i+elem.ParamsNum downto i+1 do begin
|
2014-05-25 16:49:45 +00:00
|
|
|
if j < L.Count then begin
|
|
|
|
s := s + fs.ListSeparator + ' ' + L[j];
|
|
|
|
L.Delete(j);
|
|
|
|
end else begin
|
|
|
|
Result := '=' + lpErrArgError;
|
|
|
|
exit;
|
|
|
|
end;
|
2014-05-23 23:13:49 +00:00
|
|
|
end;
|
2014-05-25 16:49:45 +00:00
|
|
|
Delete(s, 1, 2);
|
2014-05-23 23:13:49 +00:00
|
|
|
L.Strings[i] := Format('%s(%s)', [L[i], s]);
|
|
|
|
L.Objects[i] := pointer(fekString);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
dec(i);
|
|
|
|
end;
|
|
|
|
|
2014-05-25 16:49:45 +00:00
|
|
|
if L.Count > 1 then
|
|
|
|
Result := '=' + lpErrArgError // too many arguments
|
|
|
|
else
|
|
|
|
Result := '=' + L[0];
|
2014-05-23 23:13:49 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Reads the set of used formatting fields of a cell.
|
|
|
|
|
|
|
|
Each cell contains a set of "used formatting fields". Formatting is applied
|
|
|
|
only if the corresponding element is contained in the set.
|
|
|
|
|
|
|
|
@param ARow Row index of the considered cell
|
|
|
|
@param ACol Column index of the considered cell
|
|
|
|
@return Set of elements used in formatting the cell
|
|
|
|
}
|
2013-06-11 14:15:59 +00:00
|
|
|
function TsWorksheet.ReadUsedFormatting(ARow, ACol: Cardinal): TsUsedFormattingFields;
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := FindCell(ARow, ACol);
|
|
|
|
|
|
|
|
if ACell = nil then
|
|
|
|
begin
|
|
|
|
Result := [];
|
|
|
|
Exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := ACell^.UsedFormattingFields;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Returns the background color of a cell as index into the workbook's color palette.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@return Index of the cell background color into the workbook's color palette
|
|
|
|
}
|
2013-06-11 14:15:59 +00:00
|
|
|
function TsWorksheet.ReadBackgroundColor(ARow, ACol: Cardinal): TsColor;
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := FindCell(ARow, ACol);
|
|
|
|
|
|
|
|
if ACell = nil then
|
|
|
|
begin
|
|
|
|
Result := scWhite;
|
|
|
|
Exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := ACell^.BackgroundColor;
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Clears the list of cells and releases their memory.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
procedure TsWorksheet.RemoveAllCells;
|
2009-09-02 22:03:01 +00:00
|
|
|
var
|
|
|
|
Node: TAVLTreeNode;
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2009-09-02 22:03:01 +00:00
|
|
|
Node:=FCells.FindLowest;
|
|
|
|
while Assigned(Node) do begin
|
|
|
|
RemoveCallback(Node.Data,nil);
|
|
|
|
Node.Data:=nil;
|
|
|
|
Node:=FCells.FindSuccessor(Node);
|
|
|
|
end;
|
|
|
|
FCells.Clear;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Writes UTF-8 encoded text to a cell.
|
2009-01-28 17:18:04 +00:00
|
|
|
|
2010-07-30 06:44:53 +00:00
|
|
|
On formats that don't support unicode, the text will be converted
|
|
|
|
to ISO Latin 1.
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
2010-07-30 06:44:53 +00:00
|
|
|
@param AText The text to be written encoded in utf-8
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
2009-01-28 17:18:04 +00:00
|
|
|
procedure TsWorksheet.WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
2008-02-24 13:18:34 +00:00
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
2014-06-06 15:48:02 +00:00
|
|
|
WriteUTF8Text(ACell, AText);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes UTF-8 encoded text to a cell.
|
|
|
|
|
|
|
|
On formats that don't support unicode, the text will be converted
|
|
|
|
to ISO Latin 1.
|
|
|
|
|
|
|
|
@param ACell Poiner to the cell
|
|
|
|
@param AText The text to be written encoded in utf-8
|
|
|
|
}
|
2014-06-06 15:48:02 +00:00
|
|
|
procedure TsWorksheet.WriteUTF8Text(ACell: PCell; AText: ansistring);
|
|
|
|
begin
|
|
|
|
if ACell = nil then
|
|
|
|
exit;
|
2009-01-28 17:18:04 +00:00
|
|
|
ACell^.ContentType := cctUTF8String;
|
|
|
|
ACell^.UTF8StringValue := AText;
|
2014-06-06 15:48:02 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Writes a floating-point number to a cell
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ARow Cell row index
|
|
|
|
@param ACol Cell column index
|
|
|
|
@param ANumber Number to be written
|
|
|
|
@param AFormat Identifier for a built-in number format, e.g. nfFixed (optional)
|
|
|
|
@param ADecimals Number of decimal places used for formatting (optional)
|
|
|
|
@see TsNumberFormat
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
2013-12-22 14:02:04 +00:00
|
|
|
procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
2014-06-20 15:58:22 +00:00
|
|
|
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2);
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
WriteNumber(GetCell(ARow, ACol), ANumber, AFormat, ADecimals);
|
2014-05-23 15:45:07 +00:00
|
|
|
end;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a floating-point number to a cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell
|
|
|
|
@param ANumber Number to be written
|
|
|
|
@param AFormat Identifier for a built-in number format, e.g. nfFixed (optional)
|
|
|
|
@param ADecimals Number of decimal places used for formatting (optional)
|
|
|
|
@see TsNumberFormat
|
|
|
|
}
|
2014-05-23 15:45:07 +00:00
|
|
|
procedure TsWorksheet.WriteNumber(ACell: PCell; ANumber: Double;
|
2014-06-20 15:58:22 +00:00
|
|
|
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2);
|
2014-05-23 15:45:07 +00:00
|
|
|
begin
|
2014-06-12 22:20:45 +00:00
|
|
|
if IsDateTimeFormat(AFormat) or IsCurrencyFormat(AFormat) then
|
|
|
|
raise Exception.Create(lpInvalidNumberFormat);
|
|
|
|
|
2014-05-23 15:45:07 +00:00
|
|
|
if ACell <> nil then begin
|
|
|
|
ACell^.ContentType := cctNumber;
|
|
|
|
ACell^.NumberValue := ANumber;
|
2014-06-23 09:15:56 +00:00
|
|
|
ACell^.NumberFormat := AFormat;
|
2014-05-23 15:45:07 +00:00
|
|
|
|
|
|
|
if AFormat <> nfGeneral then begin
|
|
|
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormatStr := BuildNumberFormatString(ACell^.NumberFormat,
|
2014-06-12 22:20:45 +00:00
|
|
|
Workbook.FormatSettings, ADecimals);
|
2014-06-05 21:57:23 +00:00
|
|
|
end else begin
|
|
|
|
Exclude(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormatStr := '';
|
2014-05-23 15:45:07 +00:00
|
|
|
end;
|
2014-05-21 12:12:16 +00:00
|
|
|
|
2014-05-23 15:45:07 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
2013-12-22 14:02:04 +00:00
|
|
|
end;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
{@@
|
|
|
|
Writes a floating point number to the cell and uses a custom number format
|
|
|
|
specified by the format string.
|
2014-06-21 20:25:01 +00:00
|
|
|
Note that fpspreadsheet may not be able to detect the formatting when reading
|
|
|
|
the file.
|
|
|
|
|
|
|
|
@param ARow Cell row index
|
|
|
|
@param ACol Cell column index
|
|
|
|
@param ANumber Number to be written
|
|
|
|
@param AFormat Format identifier (nfCustom)
|
|
|
|
@param AFormatString String of formatting codes (such as 'dd/mmm'
|
|
|
|
}
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: Double;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormat: TsNumberFormat; AFormatString: String);
|
|
|
|
begin
|
|
|
|
WriteNumber(GetCell(ARow, ACol), ANumber, AFormat, AFormatString);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a floating point number to the cell and uses a custom number format
|
|
|
|
specified by the format string.
|
|
|
|
Note that fpspreadsheet may not be able to detect the formatting when reading
|
|
|
|
the file.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param ANumber Number to be written
|
|
|
|
@param AFormat Format identifier (nfCustom)
|
|
|
|
@param AFormatString String of formatting codes (such as 'dd/mmm'
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteNumber(ACell: PCell; ANumber: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String);
|
|
|
|
var
|
2014-05-20 16:13:48 +00:00
|
|
|
parser: TsNumFormatParser;
|
2014-05-14 15:24:02 +00:00
|
|
|
begin
|
2014-06-12 22:20:45 +00:00
|
|
|
if ACell <> nil then begin
|
|
|
|
parser := TsNumFormatParser.Create(Workbook, AFormatString);
|
|
|
|
try
|
|
|
|
// Format string ok?
|
|
|
|
if parser.Status <> psOK then
|
|
|
|
raise Exception.Create(lpNoValidNumberFormatString);
|
|
|
|
// Make sure that we do not write a date/time value here
|
|
|
|
if parser.IsDateTimeFormat
|
|
|
|
then raise Exception.Create(lpInvalidNumberFormat);
|
|
|
|
// If format string matches a built-in format use its format identifier,
|
|
|
|
// All this is considered when calling Builtin_NumFormat of the parser.
|
|
|
|
finally
|
|
|
|
parser.Free;
|
|
|
|
end;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
ACell^.ContentType := cctNumber;
|
|
|
|
ACell^.NumberValue := ANumber;
|
2014-06-23 09:15:56 +00:00
|
|
|
ACell^.NumberFormat := AFormat;
|
|
|
|
if AFormat <> nfGeneral then begin
|
|
|
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormatStr := AFormatString;
|
|
|
|
end else begin
|
|
|
|
Exclude(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
2014-05-20 16:13:48 +00:00
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
|
2014-04-21 21:43:43 +00:00
|
|
|
{@@
|
|
|
|
Writes as empty cell
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
2014-06-30 10:39:49 +00:00
|
|
|
Note: Empty cells are useful when, for example, a border line extends
|
|
|
|
along a range of cells including empty cells.
|
2014-04-21 21:43:43 +00:00
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteBlank(ARow, ACol: Cardinal);
|
|
|
|
begin
|
2014-06-30 10:39:49 +00:00
|
|
|
WriteBlank(GetCell(ARow, ACol));
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Writes as empty cell
|
|
|
|
|
|
|
|
@param ACel Pointer to the cell
|
|
|
|
Note: Empty cells are useful when, for example, a border line extends
|
|
|
|
along a range of cells including empty cells.
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteBlank(ACell: PCell);
|
|
|
|
begin
|
|
|
|
if ACell <> nil then begin
|
|
|
|
ACell^.ContentType := cctEmpty;
|
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
2014-04-21 21:43:43 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-14 23:17:46 +00:00
|
|
|
{@@
|
|
|
|
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);
|
|
|
|
begin
|
2014-06-29 09:55:47 +00:00
|
|
|
WriteBoolValue(GetCell(ARow, ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Writes as boolean cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell
|
|
|
|
@param AValue The boolean value
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteBoolValue(ACell: PCell; AValue: Boolean);
|
|
|
|
begin
|
|
|
|
if ACell <> nil then begin
|
|
|
|
ACell^.ContentType := cctBool;
|
|
|
|
ACell^.BoolValue := AValue;
|
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
2014-05-14 23:17:46 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 13:49:12 +00:00
|
|
|
{@@
|
|
|
|
Writes data defined as a string into a cell. Depending on the structure of the
|
|
|
|
string, the worksheet tries to guess whether it is a number, a date/time or
|
|
|
|
a text and calls the corresponding writing method.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param AValue Value to be written into the cell given as a string. Depending
|
|
|
|
on the structure of the string, however, the value is written
|
|
|
|
as a number, a date/time or a text.
|
|
|
|
}
|
2014-06-22 13:49:48 +00:00
|
|
|
procedure TsWorksheet.WriteCellValueAsString(ARow, ACol: Cardinal;
|
|
|
|
AValue: String);
|
|
|
|
begin
|
|
|
|
WriteCellValueAsString(GetCell(ARow, ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
2014-06-23 13:49:12 +00:00
|
|
|
{@@
|
|
|
|
Writes data defined as a string into a cell. Depending on the structure of the
|
|
|
|
string, the worksheet tries to guess whether it is a number, a date/time or
|
|
|
|
a text and calls the corresponding writing method.
|
|
|
|
|
|
|
|
@param ACell Poiner to the cell
|
|
|
|
@param AValue Value to be written into the cell given as a string. Depending
|
|
|
|
on the structure of the string, however, the value is written
|
|
|
|
as a number, a date/time or a text.
|
|
|
|
}
|
2014-06-22 13:49:48 +00:00
|
|
|
procedure TsWorksheet.WriteCellValueAsString(ACell: PCell; AValue: String);
|
|
|
|
var
|
|
|
|
isPercent: Boolean;
|
|
|
|
number: Double;
|
|
|
|
begin
|
|
|
|
if ACell = nil then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
if AValue = '' then begin
|
|
|
|
WriteBlank(ACell^.Row, ACell^.Col);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
isPercent := Pos('%', AValue) = Length(AValue);
|
|
|
|
if isPercent then Delete(AValue, Length(AValue), 1);
|
|
|
|
|
|
|
|
if TryStrToFloat(AValue, number) then begin
|
|
|
|
if isPercent then
|
|
|
|
WriteNumber(ACell, number/100, nfPercentage)
|
|
|
|
else begin
|
|
|
|
if IsDateTimeFormat(ACell^.NumberFormat) then begin
|
|
|
|
ACell^.NumberFormat := nfGeneral;
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
|
|
|
WriteNumber(ACell, number, ACell^.NumberFormat, ACell^.NumberFormatStr);
|
|
|
|
end;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if TryStrToDateTime(AValue, number) then begin
|
|
|
|
if number < 1.0 then begin // this is a time alone
|
|
|
|
if not IsTimeFormat(ACell^.NumberFormat) then begin
|
|
|
|
ACell^.NumberFormat := nfLongTime;
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
|
|
|
end else
|
|
|
|
if frac(number) = 0.0 then begin // this is a date alone
|
|
|
|
if not (ACell^.NumberFormat in [nfShortDate, nfLongDate, nfShortDateTime])
|
|
|
|
then begin
|
|
|
|
ACell^.NumberFormat := nfShortDate;
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
|
|
|
end else begin
|
|
|
|
if not IsDateTimeFormat(ACell^.NumberFormat) then begin
|
|
|
|
ACell^.NumberFormat := nfShortDateTime;
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
WriteDateTime(ACell, number, ACell^.NumberFormat, ACell^.NumberFormatStr);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
WriteUTF8Text(ACell, AValue);
|
|
|
|
end;
|
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
{@@
|
|
|
|
Writes a currency value to a given cell. Its number format can be provided
|
2014-06-21 20:25:01 +00:00
|
|
|
optionally by specifying various parameters.
|
|
|
|
|
|
|
|
@param ARow Cell row index
|
|
|
|
@param ACol Cell column index
|
|
|
|
@param AValue Number value to be written
|
2014-06-23 09:15:56 +00:00
|
|
|
@param AFormat Format identifier, must be nfCurrency, or nfCurrencyRed.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ADecimals Number of decimal places
|
|
|
|
@param APosCurrFormat Code specifying the order of value, currency symbol
|
|
|
|
and spaces (see pcfXXXX constants)
|
|
|
|
@param ANegCurrFormat Code specifying the order of value, currency symbol,
|
|
|
|
spaces, and how negative values are shown
|
|
|
|
(see ncfXXXX constants)
|
|
|
|
@param ACurrencySymbol String to be shown as currency, such as '$', or 'EUR'.
|
|
|
|
In case of '?' the currency symbol defined in the
|
|
|
|
workbook's FormatSettings is used.
|
2014-06-12 22:20:45 +00:00
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
|
|
|
|
ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
|
|
|
|
ANegCurrFormat: Integer = -1);
|
|
|
|
begin
|
|
|
|
WriteCurrency(GetCell(ARow, ACol), AValue, AFormat, ADecimals, ACurrencySymbol,
|
|
|
|
APosCurrFormat, ANegCurrFormat);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a currency value to a given cell. Its number format can be provided
|
|
|
|
optionally by specifying various parameters.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param AValue Number value to be written
|
2014-06-23 09:15:56 +00:00
|
|
|
@param AFormat Format identifier, must be nfCurrency or nfCurrencyRed.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ADecimals Number of decimal places
|
|
|
|
@param APosCurrFormat Code specifying the order of value, currency symbol
|
|
|
|
and spaces (see pcfXXXX constants)
|
|
|
|
@param ANegCurrFormat Code specifying the order of value, currency symbol,
|
|
|
|
spaces, and how negative values are shown
|
|
|
|
(see ncfXXXX constants)
|
|
|
|
@param ACurrencySymbol String to be shown as currency, such as '$', or 'EUR'.
|
|
|
|
In case of '?' the currency symbol defined in the
|
|
|
|
workbook's FormatSettings is used.
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteCurrency(ACell: PCell; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
|
|
|
|
ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
|
|
|
|
ANegCurrFormat: Integer = -1);
|
|
|
|
var
|
|
|
|
fmt: String;
|
|
|
|
begin
|
|
|
|
if ADecimals = -1 then
|
|
|
|
ADecimals := Workbook.FormatSettings.CurrencyDecimals;
|
|
|
|
if APosCurrFormat = -1 then
|
|
|
|
APosCurrFormat := Workbook.FormatSettings.CurrencyFormat;
|
|
|
|
if ANegCurrFormat = -1 then
|
|
|
|
ANegCurrFormat := Workbook.FormatSettings.NegCurrFormat;
|
|
|
|
if ACurrencySymbol = '?' then
|
2014-06-13 10:03:29 +00:00
|
|
|
ACurrencySymbol := AnsiToUTF8(Workbook.FormatSettings.CurrencyString);
|
2014-06-12 22:20:45 +00:00
|
|
|
|
|
|
|
fmt := BuildCurrencyFormatString(
|
2014-06-13 10:03:29 +00:00
|
|
|
nfdDefault,
|
|
|
|
AFormat,
|
2014-06-12 22:20:45 +00:00
|
|
|
Workbook.FormatSettings,
|
|
|
|
ADecimals,
|
|
|
|
APosCurrFormat, ANegCurrFormat,
|
|
|
|
ACurrencySymbol);
|
|
|
|
|
|
|
|
WriteCurrency(ACell, AValue, AFormat, fmt);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a currency value to a given cell. Its number format is specified by
|
|
|
|
means of a format string.
|
|
|
|
|
|
|
|
@param ARow Cell row index
|
|
|
|
@param ACol Cell column index
|
|
|
|
@param AValue Number value to be written
|
2014-06-23 09:15:56 +00:00
|
|
|
@param AFormat Format identifier, must be nfCurrency or nfCurrencyRed.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param AFormatString String of formatting codes, including currency symbol.
|
|
|
|
Can contain sections for different formatting of positive
|
|
|
|
and negative number. Example: '"EUR" #,##0.00;("EUR" #,##0.00)'
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String);
|
|
|
|
begin
|
|
|
|
WriteCurrency(GetCell(ARow, ACol), AValue, AFormat, AFormatString);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a currency value to a given cell. Its number format is specified by
|
|
|
|
means of a format string.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param AValue Number value to be written
|
2014-06-23 09:15:56 +00:00
|
|
|
@param AFormat Format identifier, must be nfCurrency or nfCurrencyRed.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param AFormatString String of formatting codes, including currency symbol.
|
|
|
|
Can contain sections for different formatting of positive
|
|
|
|
and negative number. Example: '"EUR" #,##0.00;("EUR" #,##0.00)'
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteCurrency(ACell: PCell; AValue: Double;
|
|
|
|
AFormat: TsNumberFormat; AFormatString: String);
|
|
|
|
begin
|
|
|
|
if (ACell <> nil) and IsCurrencyFormat(AFormat) then begin
|
|
|
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.ContentType := cctNumber;
|
|
|
|
ACell^.NumberValue := AValue;
|
|
|
|
ACell^.NumberFormat := AFormat;
|
|
|
|
ACell^.NumberFormatStr := AFormatString;
|
|
|
|
|
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2013-12-07 13:42:22 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Writes a date/time value to a cell
|
2013-12-07 13:42:22 +00:00
|
|
|
|
2013-12-22 14:02:04 +00:00
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AValue The date/time/datetime to be written
|
|
|
|
@param AFormat The format specifier, e.g. nfShortDate (optional)
|
2014-06-04 22:11:17 +00:00
|
|
|
If not specified format is not changed.
|
2014-06-12 22:20:45 +00:00
|
|
|
@param AFormatStr Format string, used only for nfCustom or nfTimeInterval.
|
2013-12-07 13:42:22 +00:00
|
|
|
|
|
|
|
Note: at least Excel xls does not recognize a separate datetime cell type:
|
2014-06-12 22:20:45 +00:00
|
|
|
a datetime is stored as a (floating point) number, and the cell is formatted
|
2013-12-07 13:42:22 +00:00
|
|
|
as a date (either built-in or a custom format).
|
|
|
|
}
|
2013-12-22 14:02:04 +00:00
|
|
|
procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
2012-01-23 13:24:13 +00:00
|
|
|
begin
|
2014-05-23 15:45:07 +00:00
|
|
|
WriteDateTime(GetCell(ARow, ACol), AValue, AFormat, AFormatStr);
|
|
|
|
end;
|
2012-01-23 13:24:13 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a date/time value to a cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param AValue The date/time/datetime to be written
|
|
|
|
@param AFormat The format specifier, e.g. nfShortDate (optional)
|
|
|
|
If not specified format is not changed.
|
|
|
|
@param AFormatStr Format string, used only for nfCustom or nfTimeInterval.
|
|
|
|
|
|
|
|
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
|
|
|
|
as a date (either built-in or a custom format).
|
|
|
|
}
|
2014-05-23 15:45:07 +00:00
|
|
|
procedure TsWorksheet.WriteDateTime(ACell: PCell; AValue: TDateTime;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
|
|
|
|
var
|
|
|
|
parser: TsNumFormatParser;
|
2014-05-23 15:45:07 +00:00
|
|
|
begin
|
|
|
|
if ACell <> nil then begin
|
|
|
|
ACell^.ContentType := cctDateTime;
|
|
|
|
ACell^.DateTimeValue := AValue;
|
2014-06-04 22:11:17 +00:00
|
|
|
|
2014-05-23 15:45:07 +00:00
|
|
|
// Date/time is actually a number field in Excel.
|
|
|
|
// To make sure it gets saved correctly, set a date format (instead of General).
|
|
|
|
// The user can choose another date format if he wants to
|
2014-06-12 22:20:45 +00:00
|
|
|
|
|
|
|
if AFormatStr = '' then
|
2014-06-18 08:39:54 +00:00
|
|
|
AFormatStr := BuildDateTimeFormatString(AFormat, Workbook.FormatSettings, AFormatStr)
|
|
|
|
else
|
|
|
|
if AFormat = nfTimeInterval then
|
|
|
|
AFormatStr := AddIntervalBrackets(AFormatStr);
|
2014-06-12 22:20:45 +00:00
|
|
|
|
|
|
|
// Check whether the formatstring is for date/times.
|
|
|
|
if AFormatStr <> '' then begin
|
|
|
|
parser := TsNumFormatParser.Create(Workbook, AFormatStr);
|
|
|
|
try
|
|
|
|
// Format string ok?
|
|
|
|
if parser.Status <> psOK then
|
|
|
|
raise Exception.Create(lpNoValidNumberFormatString);
|
|
|
|
// Make sure that we do not use a number format for date/times values.
|
|
|
|
if not parser.IsDateTimeFormat
|
|
|
|
then raise Exception.Create(lpInvalidDateTimeFormat);
|
|
|
|
// Avoid possible duplication of standard formats
|
|
|
|
if AFormat = nfCustom then
|
|
|
|
AFormat := parser.NumFormat;
|
|
|
|
finally
|
|
|
|
parser.Free;
|
|
|
|
end;
|
|
|
|
end;
|
2014-06-04 22:11:17 +00:00
|
|
|
|
2014-05-23 15:45:07 +00:00
|
|
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormat := AFormat;
|
|
|
|
ACell^.NumberFormatStr := AFormatStr;
|
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
2012-01-23 13:24:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a date/time value to a cell
|
|
|
|
|
|
|
|
@param ARow The row index of the cell
|
|
|
|
@param ACol The column index of the cell
|
|
|
|
@param AValue The date/time/datetime to be written
|
|
|
|
@param AFormatStr Format string (the format identifier nfCustom is used to classify the format).
|
|
|
|
|
|
|
|
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
|
|
|
|
as a date (either built-in or a custom format).
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
|
|
|
|
AFormatStr: String);
|
|
|
|
begin
|
|
|
|
WriteDateTime(GetCell(ARow, ACol), AValue, AFormatStr);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes a date/time value to a cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param AValue The date/time/datetime to be written
|
|
|
|
@param AFormatStr Format string (the format identifier nfCustom is used to classify the format).
|
|
|
|
|
|
|
|
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
|
|
|
|
as a date (either built-in or a custom format).
|
|
|
|
}
|
2014-06-12 22:20:45 +00:00
|
|
|
procedure TsWorksheet.WriteDateTime(ACell: PCell; AValue: TDateTime;
|
|
|
|
AFormatStr: String);
|
|
|
|
begin
|
|
|
|
WriteDateTime(ACell, AValue, nfCustom, AFormatStr);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Formats the number in a cell to show a given count of decimal places.
|
|
|
|
Is ignored for non-decimal formats (such as most date/time formats).
|
|
|
|
|
|
|
|
@param ARow Row indows of the cell considered
|
|
|
|
@param ACol Column indows of the cell considered
|
|
|
|
@param ADecimals Number of decimal places to be displayed
|
|
|
|
@see TsNumberFormat
|
|
|
|
}
|
2014-05-15 22:41:14 +00:00
|
|
|
procedure TsWorksheet.WriteDecimals(ARow, ACol: Cardinal; ADecimals: Byte);
|
|
|
|
begin
|
|
|
|
WriteDecimals(FindCell(ARow, ACol), ADecimals);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Formats the number in a cell to show a given count of decimal places.
|
|
|
|
Is ignored for non-decimal formats (such as most date/time formats).
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param ADecimals Number of decimal places to be displayed
|
|
|
|
@see TsNumberFormat
|
|
|
|
}
|
2014-05-15 22:41:14 +00:00
|
|
|
procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte);
|
2014-06-12 22:20:45 +00:00
|
|
|
var
|
|
|
|
parser: TsNumFormatParser;
|
2014-05-15 22:41:14 +00:00
|
|
|
begin
|
2014-05-21 12:12:16 +00:00
|
|
|
if (ACell <> nil) and (ACell^.ContentType = cctNumber) and (ACell^.NumberFormat <> nfCustom)
|
|
|
|
then begin
|
2014-06-12 22:20:45 +00:00
|
|
|
parser := TsNumFormatParser.Create(Workbook, ACell^.NumberFormatStr);
|
|
|
|
try
|
|
|
|
parser.Decimals := ADecimals;
|
|
|
|
ACell^.NumberFormatStr := parser.FormatString[nfdDefault];
|
|
|
|
finally
|
|
|
|
parser.Free;
|
|
|
|
end;
|
2014-05-15 22:41:14 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-14 23:17:46 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Writes an error value to a cell.
|
2014-05-14 23:17:46 +00:00
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AValue The error code value
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@see TsErrorValue
|
2014-05-14 23:17:46 +00:00
|
|
|
}
|
2014-05-25 16:49:45 +00:00
|
|
|
procedure TsWorksheet.WriteErrorValue(ARow, ACol: Cardinal; AValue: TsErrorValue);
|
2014-05-14 23:17:46 +00:00
|
|
|
begin
|
2014-05-23 13:16:01 +00:00
|
|
|
WriteErrorValue(GetCell(ARow, ACol), AValue);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes an error value to a cell.
|
|
|
|
|
|
|
|
@param ACol Pointer to the cell considered
|
|
|
|
@param AValue The error code value
|
|
|
|
|
|
|
|
@see TsErrorValue
|
|
|
|
}
|
2014-05-25 16:49:45 +00:00
|
|
|
procedure TsWorksheet.WriteErrorValue(ACell: PCell; AValue: TsErrorValue);
|
2014-05-23 13:16:01 +00:00
|
|
|
begin
|
|
|
|
if ACell <> nil then begin
|
|
|
|
ACell^.ContentType := cctError;
|
2014-05-25 16:49:45 +00:00
|
|
|
ACell^.ErrorValue := AValue;
|
2014-05-23 13:16:01 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
|
|
|
end;
|
2014-05-14 23:17:46 +00:00
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-12 22:20:45 +00:00
|
|
|
Writes a formula to a given cell
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
2009-02-02 09:58:51 +00:00
|
|
|
@param AFormula The formula to be written
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
2009-02-02 09:58:51 +00:00
|
|
|
procedure TsWorksheet.WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
2008-02-24 13:18:34 +00:00
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.ContentType := cctFormula;
|
|
|
|
ACell^.FormulaValue := AFormula;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2013-12-07 13:42:22 +00:00
|
|
|
{@@
|
|
|
|
Adds number format to the formatting of a cell
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param ANumberFormat Identifier of the format to be applied
|
|
|
|
@param AFormatString optional string of formatting codes. Is only considered
|
|
|
|
if ANumberFormat is nfCustom.
|
2013-12-07 13:42:22 +00:00
|
|
|
|
|
|
|
@see TsNumberFormat
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal;
|
2014-05-15 22:41:14 +00:00
|
|
|
ANumberFormat: TsNumberFormat; const AFormatString: String = '');
|
2013-12-07 13:42:22 +00:00
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
2014-06-05 21:57:23 +00:00
|
|
|
WriteNumberFormat(ACell, ANumberFormat, AFormatString);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Adds a number format to the formatting of a cell
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell considered
|
|
|
|
@param ANumberFormat Identifier of the format to be applied
|
|
|
|
@param AFormatString optional string of formatting codes. Is only considered
|
|
|
|
if ANumberFormat is nfCustom.
|
|
|
|
|
|
|
|
@see TsNumberFormat
|
|
|
|
}
|
2014-06-05 21:57:23 +00:00
|
|
|
procedure TsWorksheet.WriteNumberFormat(ACell: PCell;
|
|
|
|
ANumberFormat: TsNumberFormat; const AFormatString: String = '');
|
|
|
|
begin
|
|
|
|
if ACell = nil then
|
|
|
|
exit;
|
2014-06-23 13:49:12 +00:00
|
|
|
|
2013-12-07 13:42:22 +00:00
|
|
|
ACell^.NumberFormat := ANumberFormat;
|
2014-06-23 13:49:12 +00:00
|
|
|
if ANumberFormat <> nfGeneral then begin
|
|
|
|
Include(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
if (AFormatString = '') then
|
|
|
|
ACell^.NumberFormatStr := BuildNumberFormatString(ANumberFormat, Workbook.FormatSettings)
|
|
|
|
else
|
|
|
|
ACell^.NumberFormatStr := AFormatString;
|
|
|
|
end else begin
|
|
|
|
Exclude(ACell^.UsedFormattingFields, uffNumberFormat);
|
|
|
|
ACell^.NumberFormatStr := '';
|
|
|
|
end;
|
2014-06-05 21:57:23 +00:00
|
|
|
ChangedCell(ACell^.Row, ACell^.Col);
|
2013-12-07 13:42:22 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Writes an RPN formula to a cell. An RPN formula is an array of tokens
|
|
|
|
describing the calculation to be performed.
|
|
|
|
|
|
|
|
@param ARow Row indows of the cell considered
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param AFormula Array of TsFormulaElements. The array can be created by
|
|
|
|
using "CreateRPNFormla".
|
|
|
|
|
|
|
|
@see TsNumberFormat
|
|
|
|
@see TsFormulaElements
|
|
|
|
@see CreateRPNFormula
|
|
|
|
}
|
2009-06-09 11:19:10 +00:00
|
|
|
procedure TsWorksheet.WriteRPNFormula(ARow, ACol: Cardinal;
|
|
|
|
AFormula: TsRPNFormula);
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.ContentType := cctRPNFormula;
|
|
|
|
ACell^.RPNFormulaValue := AFormula;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2009-06-09 11:19:10 +00:00
|
|
|
end;
|
|
|
|
|
2014-04-22 23:10:32 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Adds font specification to the formatting of a cell. Looks in the workbook's
|
|
|
|
FontList and creates an new entry if the font is not used so far. Returns the
|
|
|
|
index of the font in the font list.
|
2014-04-22 23:10:32 +00:00
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AFontName Name of the font
|
|
|
|
@param AFontSize Size of the font, in points
|
|
|
|
@param AFontStyle Set with font style attributes
|
|
|
|
(don't use those of unit "graphics" !)
|
2014-06-21 20:25:01 +00:00
|
|
|
@return Index of the font in the workbook's font list.
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
function TsWorksheet.WriteFont(ARow, ACol: Cardinal; const AFontName: String;
|
|
|
|
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
Include(lCell^.UsedFormattingFields, uffFont);
|
|
|
|
Result := FWorkbook.FindFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
|
|
|
if Result = -1 then
|
|
|
|
result := FWorkbook.AddFont(AFontName, AFontSize, AFontStyle, AFontColor);
|
|
|
|
lCell^.FontIndex := Result;
|
2014-05-08 21:52:04 +00:00
|
|
|
ChangedFont(ARow, ACol);
|
2014-04-22 23:10:32 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Applies a font to the formatting of a cell. The font is determined by its
|
|
|
|
index in the workbook's font list:
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AFontIndex Index of the font in the workbook's font list
|
|
|
|
}
|
2014-04-22 23:10:32 +00:00
|
|
|
procedure TsWorksheet.WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
if (AFontIndex >= 0) and (AFontIndex < Workbook.GetFontCount) and (AFontIndex <> 4)
|
|
|
|
// note: Font index 4 is not defined in BIFF
|
|
|
|
then begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
Include(lCell^.UsedFormattingFields, uffFont);
|
|
|
|
lCell^.FontIndex := AFontIndex;
|
2014-05-08 21:52:04 +00:00
|
|
|
ChangedFont(ARow, ACol);
|
2014-04-22 23:10:32 +00:00
|
|
|
end else
|
|
|
|
raise Exception.Create(lpInvalidFontIndex);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Replaces the text color used in formatting of a cell. Looks in the workbook's
|
|
|
|
font list if this modified font has already been used. If not a new font entry
|
|
|
|
is created. Returns the index of this font in the font list.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AFontColor Index into the workbook's color palette identifying the
|
|
|
|
new text color.
|
|
|
|
@return Index of the font in the workbook's font list.
|
|
|
|
}
|
2014-04-23 22:29:32 +00:00
|
|
|
function TsWorksheet.WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
fnt := Workbook.GetFont(lCell^.FontIndex);
|
|
|
|
Result := WriteFont(ARow, ACol, fnt.FontName, fnt.Size, fnt.Style, AFontColor);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Replaces the font used in formatting of a cell considering only the font face
|
|
|
|
and leaving font size, style and color unchanged. Looks in the workbook's
|
|
|
|
font list if this modified font has already been used. If not a new font entry
|
|
|
|
is created. Returns the index of this font in the font list.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AFontName Name of the new font to be used
|
|
|
|
@return Index of the font in the workbook's font list.
|
|
|
|
}
|
2014-05-11 16:16:59 +00:00
|
|
|
function TsWorksheet.WriteFontName(ARow, ACol: Cardinal; AFontName: String): Integer;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
fnt := Workbook.GetFont(lCell^.FontIndex);
|
|
|
|
result := WriteFont(ARow, ACol, AFontName, fnt.Size, fnt.Style, fnt.Color);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Replaces the font size in formatting of a cell. Looks in the workbook's
|
|
|
|
font list if this modified font has already been used. If not a new font entry
|
|
|
|
is created. Returns the index of this font in the font list.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param ASize Size of the font to be used (in points).
|
|
|
|
@return Index of the font in the workbook's font list.
|
|
|
|
}
|
2014-05-11 16:16:59 +00:00
|
|
|
function TsWorksheet.WriteFontSize(ARow, ACol: Cardinal; ASize: Single): Integer;
|
2014-04-23 22:29:32 +00:00
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
fnt := Workbook.GetFont(lCell^.FontIndex);
|
|
|
|
Result := WriteFont(ARow, ACol, fnt.FontName, ASize, fnt.Style, fnt.Color);
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Replaces the font style (bold, italic, etc) in formatting of a cell.
|
|
|
|
Looks in the workbook's font list if this modified font has already been used.
|
|
|
|
If not a new font entry is created.
|
|
|
|
Returns the index of this font in the font list.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AStyle New font style to be used
|
|
|
|
@return Index of the font in the workbook's font list.
|
|
|
|
|
|
|
|
@see TsFontStyle
|
|
|
|
}
|
2014-05-05 19:36:45 +00:00
|
|
|
function TsWorksheet.WriteFontStyle(ARow, ACol: Cardinal;
|
|
|
|
AStyle: TsFontStyles): Integer;
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
fnt := Workbook.GetFont(lCell^.FontIndex);
|
|
|
|
Result := WriteFont(ARow, ACol, fnt.FontName, fnt.Size, AStyle, fnt.Color);
|
|
|
|
end;
|
|
|
|
|
2010-07-30 06:44:53 +00:00
|
|
|
{@@
|
|
|
|
Adds text rotation to the formatting of a cell
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param ARotation How to rotate the text
|
|
|
|
|
|
|
|
@see TsTextRotation
|
|
|
|
}
|
|
|
|
procedure TsWorksheet.WriteTextRotation(ARow, ACol: Cardinal;
|
|
|
|
ARotation: TsTextRotation);
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
Include(ACell^.UsedFormattingFields, uffTextRotation);
|
|
|
|
ACell^.TextRotation := ARotation;
|
2014-05-08 21:52:04 +00:00
|
|
|
ChangedFont(ARow, ACol);
|
2010-07-30 06:44:53 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Directly modifies the used formatting fields of a cell.
|
|
|
|
Only formatting corresponding to items included in this set is executed.
|
|
|
|
|
|
|
|
@param ARow The row of the cell
|
|
|
|
@param ACol The column of the cell
|
|
|
|
@param AUsedFormatting set of the used formatting fields
|
|
|
|
|
|
|
|
@see TsUsedFormattingFields
|
|
|
|
@see TCell
|
|
|
|
}
|
2010-12-07 12:59:17 +00:00
|
|
|
procedure TsWorksheet.WriteUsedFormatting(ARow, ACol: Cardinal;
|
|
|
|
AUsedFormatting: TsUsedFormattingFields);
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.UsedFormattingFields := AUsedFormatting;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2010-12-07 12:59:17 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets the color of a background color of a cell.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param AColor Index of the new background color into the workbook's
|
2014-06-23 13:49:12 +00:00
|
|
|
color palette. Use the color index scTransparent to
|
|
|
|
erase an existing background color.
|
2014-06-21 20:25:01 +00:00
|
|
|
}
|
2013-06-11 14:15:59 +00:00
|
|
|
procedure TsWorksheet.WriteBackgroundColor(ARow, ACol: Cardinal;
|
|
|
|
AColor: TsColor);
|
|
|
|
var
|
|
|
|
ACell: PCell;
|
|
|
|
begin
|
|
|
|
ACell := GetCell(ARow, ACol);
|
2014-06-23 13:49:12 +00:00
|
|
|
if AColor = scTransparent then
|
|
|
|
Exclude(ACell^.UsedFormattingFields, uffBackgroundColor)
|
|
|
|
else begin
|
|
|
|
Include(ACell^.UsedFormattingFields, uffBackgroundColor);
|
|
|
|
ACell^.BackgroundColor := AColor;
|
|
|
|
end;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2013-06-11 14:15:59 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets the color of a cell border line.
|
|
|
|
Note: the border must be included in Borders set in order to be shown!
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param ABorder Indicates to which border (left/top etc) this color is
|
|
|
|
to be applied
|
|
|
|
@param AColor Index of the new border color into the workbook's
|
|
|
|
color palette.
|
|
|
|
}
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure TsWorksheet.WriteBorderColor(ARow, ACol: Cardinal;
|
|
|
|
ABorder: TsCellBorder; AColor: TsColor);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
lCell^.BorderStyles[ABorder].Color := AColor;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-05-03 17:00:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets the linestyle of a cell border.
|
|
|
|
Note: the border must be included in the "Borders" set in order to be shown!
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param ABorder Indicates to which border (left/top etc) this color is
|
|
|
|
to be applied
|
|
|
|
@param ALineStyle Identifier of the new line style to be applied.
|
|
|
|
|
|
|
|
@see TsLineStyle
|
|
|
|
}
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure TsWorksheet.WriteBorderLineStyle(ARow, ACol: Cardinal;
|
|
|
|
ABorder: TsCellBorder; ALineStyle: TsLineStyle);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
lCell^.BorderStyles[ABorder].LineStyle := ALineStyle;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-05-03 17:00:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Shows the cell borders included in the set ABorders. No border lines are drawn
|
|
|
|
for those not included.
|
|
|
|
|
|
|
|
The borders are drawn using the "BorderStyles" assigned to the cell.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param ABorders Set with elements to identify the border(s) to will be shown
|
|
|
|
@see TsCellBorder
|
|
|
|
}
|
2014-04-21 21:43:43 +00:00
|
|
|
procedure TsWorksheet.WriteBorders(ARow, ACol: Cardinal; ABorders: TsCellBorders);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
Include(lCell^.UsedFormattingFields, uffBorder);
|
|
|
|
lCell^.Border := ABorders;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-04-21 21:43:43 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets the style of a cell border, i.e. line style and line color.
|
|
|
|
Note: the border must be included in the "Borders" set in order to be shown!
|
|
|
|
|
|
|
|
@param ARow Row index of the cell considered
|
|
|
|
@param ACol Column index of the cell considered
|
|
|
|
@param ABorder Identifies the border to be modified (left/top/right/bottom)
|
|
|
|
@param AStyle record of parameters controlling how the border line is drawn
|
|
|
|
(line style, line color)
|
|
|
|
}
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure TsWorksheet.WriteBorderStyle(ARow, ACol: Cardinal;
|
|
|
|
ABorder: TsCellBorder; AStyle: TsCellBorderStyle);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
lCell^.BorderStyles[ABorder] := AStyle;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-05-03 17:00:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets line style and line color of a cell border.
|
|
|
|
Note: the border must be included in the "Borders" set in order to be shown!
|
|
|
|
|
|
|
|
@param ARow Row index of the considered cell
|
|
|
|
@param ACol Column index of the considered cell
|
|
|
|
@param ABorder Identifier of the border to be modified
|
|
|
|
@param ALineStyle Identifier for the new line style of the border
|
|
|
|
@param AColor Palette index for the color of the border line
|
|
|
|
|
|
|
|
@see WriteBorderStyles
|
|
|
|
}
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure TsWorksheet.WriteBorderStyle(ARow, ACol: Cardinal;
|
|
|
|
ABorder: TsCellBorder; ALineStyle: TsLinestyle; AColor: TsColor);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
lCell^.BorderStyles[ABorder].LineStyle := ALineStyle;
|
|
|
|
lCell^.BorderStyles[ABorder].Color := AColor;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-05-03 17:00:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Sets the style of all cell border of a cell, i.e. line style and line color.
|
|
|
|
Note: Only those borders included in the "Borders" set are shown!
|
|
|
|
|
|
|
|
@param ARow Row index of the considered cell
|
|
|
|
@param ACol Column index of the considered cell
|
|
|
|
@param AStyles Array of CellBorderStyles for each cell border.
|
|
|
|
|
|
|
|
@see WriteBorderStyle
|
|
|
|
}
|
2014-05-03 17:00:00 +00:00
|
|
|
procedure TsWorksheet.WriteBorderStyles(ARow, ACol: Cardinal;
|
|
|
|
const AStyles: TsCellBorderStyles);
|
|
|
|
var
|
|
|
|
b: TsCellBorder;
|
|
|
|
cell: PCell;
|
|
|
|
begin
|
|
|
|
cell := GetCell(ARow, ACol);
|
|
|
|
for b in TsCellBorder do cell^.BorderStyles[b] := AStyles[b];
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-05-03 17:00:00 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Defines the horizontal alignment of text in a cell.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell considered
|
|
|
|
@param ACol Column index of the cell considered
|
|
|
|
@param AValue Parameter for horizontal text alignment (haDefault, vaLeft, haCenter, haRight)
|
|
|
|
By default, texts are left-aligned, numbers and dates are right-aligned.
|
|
|
|
}
|
2014-04-20 20:31:36 +00:00
|
|
|
procedure TsWorksheet.WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
2014-06-23 13:49:12 +00:00
|
|
|
Include(lCell^.UsedFormattingFields, uffHorAlign);
|
2014-04-20 20:31:36 +00:00
|
|
|
lCell^.HorAlignment := AValue;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-04-20 20:31:36 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Defines the vertical alignment of text in a cell.
|
|
|
|
|
|
|
|
@param ARow Row index of the cell considered
|
|
|
|
@param ACol Column index of the cell considered
|
|
|
|
@param AValue Parameter for vertical text alignment (vaDefault, vaTop, vaCenter, vaBottom)
|
|
|
|
By default, texts are bottom-aligned.
|
|
|
|
}
|
2014-04-20 20:31:36 +00:00
|
|
|
procedure TsWorksheet.WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment);
|
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
2014-06-23 13:49:12 +00:00
|
|
|
Include(lCell^.UsedFormattingFields, uffVertAlign);
|
2014-04-20 20:31:36 +00:00
|
|
|
lCell^.VertAlignment := AValue;
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-04-20 20:31:36 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Enables or disables the word-wrapping feature for a cell.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param ARow Row index of the cell considered
|
|
|
|
@param ACol Column index of the cell considered
|
2014-06-21 20:25:01 +00:00
|
|
|
@param AValue true = word-wrapping enabled, false = disabled.
|
2014-06-20 23:06:29 +00:00
|
|
|
}
|
2014-06-21 20:25:01 +00:00
|
|
|
procedure TsWorksheet.WriteWordwrap(ARow, ACol: Cardinal; AValue: boolean);
|
2014-04-29 21:58:48 +00:00
|
|
|
var
|
|
|
|
lCell: PCell;
|
|
|
|
begin
|
|
|
|
lCell := GetCell(ARow, ACol);
|
|
|
|
if AValue then
|
|
|
|
Include(lCell^.UsedFormattingFields, uffWordwrap)
|
|
|
|
else
|
|
|
|
Exclude(lCell^.UsedFormattingFields, uffWordwrap);
|
2014-05-07 22:44:00 +00:00
|
|
|
ChangedCell(ARow, ACol);
|
2014-04-29 21:58:48 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-05 21:57:23 +00:00
|
|
|
function TsWorksheet.GetFormatSettings: TFormatSettings;
|
|
|
|
begin
|
|
|
|
Result := FWorkbook.FormatSettings;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Calculates the optimum height of a given row. Depends on the font size
|
|
|
|
of the individual cells in the row.
|
|
|
|
|
|
|
|
@param ARow Index of the row to be considered
|
|
|
|
@return Row height in line count of the default font.
|
|
|
|
}
|
2014-06-17 09:06:34 +00:00
|
|
|
function TsWorksheet.CalcAutoRowHeight(ARow: Cardinal): Single;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
col: Integer;
|
|
|
|
h0: Single;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
h0 := Workbook.GetDefaultFontSize;
|
|
|
|
for col := 0 to GetLastColIndex do begin
|
|
|
|
cell := FindCell(ARow, col);
|
|
|
|
if cell <> nil then
|
|
|
|
Result := Max(Result, Workbook.GetFont(cell^.FontIndex).Size / h0);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Checks if a row record exists for the given row index and returns a pointer
|
|
|
|
to the row record, or nil if not found
|
|
|
|
|
|
|
|
@param ARow Index of the row looked for
|
|
|
|
@return Pointer to the row record with this row index, or nil if not found }
|
2012-06-13 15:24:44 +00:00
|
|
|
function TsWorksheet.FindRow(ARow: Cardinal): PRow;
|
|
|
|
var
|
|
|
|
LElement: TRow;
|
|
|
|
AVLNode: TAVGLVLTreeNode;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
LElement.Row := ARow;
|
|
|
|
AVLNode := FRows.Find(@LElement);
|
|
|
|
if Assigned(AVLNode) then
|
|
|
|
result := PRow(AVLNode.Data);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Checks if a column record exists for the given column index and returns a pointer
|
|
|
|
to the TCol record, or nil if not found
|
|
|
|
|
|
|
|
@param ACol Index of the column looked for
|
|
|
|
@return Pointer to the column record with this column index, or nil if not found }
|
2012-06-13 15:24:44 +00:00
|
|
|
function TsWorksheet.FindCol(ACol: Cardinal): PCol;
|
|
|
|
var
|
|
|
|
LElement: TCol;
|
|
|
|
AVLNode: TAVGLVLTreeNode;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
LElement.Col := ACol;
|
2014-04-17 20:59:00 +00:00
|
|
|
AVLNode := FCols.Find(@LElement);
|
2012-06-13 15:24:44 +00:00
|
|
|
if Assigned(AVLNode) then
|
|
|
|
result := PCol(AVLNode.Data);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Checks if a row record exists for the given row index and creates it if not found.
|
|
|
|
|
|
|
|
@param ARow Index of the row looked for
|
|
|
|
@return Pointer to the row record with this row index. It can safely be
|
|
|
|
assumed that this row record exists. }
|
2012-06-13 15:24:44 +00:00
|
|
|
function TsWorksheet.GetRow(ARow: Cardinal): PRow;
|
|
|
|
begin
|
|
|
|
Result := FindRow(ARow);
|
2014-05-07 18:31:27 +00:00
|
|
|
if (Result = nil) then begin
|
2012-06-13 15:24:44 +00:00
|
|
|
Result := GetMem(SizeOf(TRow));
|
|
|
|
FillChar(Result^, SizeOf(TRow), #0);
|
|
|
|
Result^.Row := ARow;
|
2013-11-21 16:13:02 +00:00
|
|
|
FRows.Add(Result);
|
2012-06-13 15:24:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Checks if a column record exists for the given column index and creates it
|
|
|
|
if not found.
|
|
|
|
|
|
|
|
@param ACol Index of the column looked for
|
|
|
|
@return Pointer to the TCol record with this column index. It can safely be
|
|
|
|
assumed that this column record exists. }
|
2012-06-13 15:24:44 +00:00
|
|
|
function TsWorksheet.GetCol(ACol: Cardinal): PCol;
|
|
|
|
begin
|
|
|
|
Result := FindCol(ACol);
|
2014-05-07 18:31:27 +00:00
|
|
|
if (Result = nil) then begin
|
2012-06-13 15:24:44 +00:00
|
|
|
Result := GetMem(SizeOf(TCol));
|
|
|
|
FillChar(Result^, SizeOf(TCol), #0);
|
|
|
|
Result^.Col := ACol;
|
|
|
|
FCols.Add(Result);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Counts how many cells exist in the given column. Blank cells do contribute
|
2014-06-21 20:25:01 +00:00
|
|
|
to the sum, as well as formatted cells.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param ACol Index of the column considered
|
|
|
|
@return Count of cells with value or format in this column }
|
2014-05-31 21:04:53 +00:00
|
|
|
function TsWorksheet.GetCellCountInCol(ACol: Cardinal): Cardinal;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
r: Cardinal;
|
|
|
|
row: PRow;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
for r := 0 to GetLastRowIndex do begin
|
|
|
|
cell := FindCell(r, ACol);
|
|
|
|
if cell <> nil then
|
|
|
|
inc(Result)
|
|
|
|
else begin
|
|
|
|
row := FindRow(r);
|
|
|
|
if row <> nil then inc(Result);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Counts how many cells exist in the given row. Blank cells do contribute
|
2014-06-21 20:25:01 +00:00
|
|
|
to the sum, as well as formatted cell.s
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param ARow Index of the row considered
|
|
|
|
@return Count of cells with value or format in this row
|
|
|
|
}
|
2014-05-31 21:04:53 +00:00
|
|
|
function TsWorksheet.GetCellCountInRow(ARow: Cardinal): Cardinal;
|
|
|
|
var
|
|
|
|
cell: PCell;
|
|
|
|
c: Cardinal;
|
|
|
|
col: PCol;
|
|
|
|
begin
|
|
|
|
Result := 0;
|
|
|
|
for c := 0 to GetLastColIndex do begin
|
|
|
|
cell := FindCell(ARow, c);
|
|
|
|
if cell <> nil then
|
|
|
|
inc(Result)
|
|
|
|
else begin
|
|
|
|
col := FindCol(c);
|
|
|
|
if col <> nil then inc(Result);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Returns the width of the given column. If there is no column record then
|
|
|
|
the default column width is returned.
|
|
|
|
|
|
|
|
@param ACol Index of the column considered
|
|
|
|
@return Width of the column (in count of "0" characters of the default font)
|
|
|
|
}
|
2014-05-31 21:04:53 +00:00
|
|
|
function TsWorksheet.GetColWidth(ACol: Cardinal): Single;
|
|
|
|
var
|
|
|
|
col: PCol;
|
|
|
|
begin
|
|
|
|
col := FindCol(ACol);
|
|
|
|
if col <> nil then
|
|
|
|
Result := col^.Width
|
|
|
|
else
|
|
|
|
Result := FWorkbook.DefaultColWidth;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Returns the height of the given row. If there is no row record then the
|
|
|
|
default row height is returned
|
|
|
|
|
|
|
|
@param ARow Index of the row considered
|
|
|
|
@return Height of the row (in line count of the default font).
|
|
|
|
}
|
2014-05-31 21:04:53 +00:00
|
|
|
function TsWorksheet.GetRowHeight(ARow: Cardinal): Single;
|
|
|
|
var
|
|
|
|
row: PRow;
|
|
|
|
begin
|
|
|
|
row := FindRow(ARow);
|
|
|
|
if row <> nil then
|
|
|
|
Result := row^.Height
|
|
|
|
else
|
2014-06-17 11:57:03 +00:00
|
|
|
//Result := CalcAutoRowHeight(ARow);
|
|
|
|
Result := FWorkbook.DefaultRowHeight;
|
2014-05-31 21:04:53 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Removes all row records from the worksheet and frees the occupied memory.
|
|
|
|
Note: Cells are retained.
|
|
|
|
}
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure TsWorksheet.RemoveAllRows;
|
|
|
|
var
|
2014-04-17 20:59:00 +00:00
|
|
|
Node: Pointer;
|
2012-06-13 15:24:44 +00:00
|
|
|
i: Integer;
|
|
|
|
begin
|
2014-05-07 18:31:27 +00:00
|
|
|
for i := FRows.Count-1 downto 0 do begin
|
2014-04-17 20:59:00 +00:00
|
|
|
Node := FRows.Items[i];
|
|
|
|
FreeMem(Node, SizeOf(TRow));
|
2012-06-13 15:24:44 +00:00
|
|
|
end;
|
|
|
|
FRows.Clear;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Removes all column records from the worksheet and frees the occupied memory.
|
|
|
|
Note: Cells are retained.
|
|
|
|
}
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure TsWorksheet.RemoveAllCols;
|
|
|
|
var
|
2014-04-17 20:59:00 +00:00
|
|
|
Node: Pointer;
|
2012-06-13 15:24:44 +00:00
|
|
|
i: Integer;
|
|
|
|
begin
|
2014-05-07 18:31:27 +00:00
|
|
|
for i := FCols.Count-1 downto 0 do begin
|
2014-04-17 20:59:00 +00:00
|
|
|
Node := FCols.Items[i];
|
|
|
|
FreeMem(Node, SizeOf(TCol));
|
2012-06-13 15:24:44 +00:00
|
|
|
end;
|
|
|
|
FCols.Clear;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Writes a row record for the row at a given index to the spreadsheet.
|
|
|
|
Currently the row record contains only the row height (and the row index, of course).
|
|
|
|
|
|
|
|
Creates a new row record if it does not yet exist.
|
|
|
|
|
|
|
|
@param ARow Index of the row record which will be created or modified
|
|
|
|
@param AData Data to be written.
|
|
|
|
}
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure TsWorksheet.WriteRowInfo(ARow: Cardinal; AData: TRow);
|
|
|
|
var
|
|
|
|
AElement: PRow;
|
|
|
|
begin
|
|
|
|
AElement := GetRow(ARow);
|
|
|
|
AElement^.Height := AData.Height;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Sets the row height for a given row. Creates a new row record if it
|
|
|
|
does not yet exist.
|
|
|
|
|
|
|
|
@param ARow Index of the row to be considered
|
|
|
|
@param AHeight Row height to be assigned to the row. The row height is
|
|
|
|
expressed as the line count of the default font size.
|
|
|
|
}
|
2014-05-07 18:31:27 +00:00
|
|
|
procedure TsWorksheet.WriteRowHeight(ARow: Cardinal; AHeight: Single);
|
|
|
|
var
|
|
|
|
AElement: PRow;
|
|
|
|
begin
|
|
|
|
AElement := GetRow(ARow);
|
|
|
|
AElement^.Height := AHeight;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Writes a column record for the column at a given index to the spreadsheet.
|
|
|
|
Currently the column record contains only the column width (and the column
|
|
|
|
index, of course).
|
|
|
|
|
|
|
|
Creates a new column record if it does not yet exist.
|
|
|
|
|
|
|
|
@param ACol Index of the column record which will be created or modified
|
|
|
|
@param AData Data to be written (essentially column width).
|
|
|
|
}
|
2012-06-13 15:24:44 +00:00
|
|
|
procedure TsWorksheet.WriteColInfo(ACol: Cardinal; AData: TCol);
|
|
|
|
var
|
|
|
|
AElement: PCol;
|
|
|
|
begin
|
|
|
|
AElement := GetCol(ACol);
|
|
|
|
AElement^.Width := AData.Width;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Sets the column width for a given column. Creates a new column record if it
|
|
|
|
does not yet exist.
|
|
|
|
|
|
|
|
@param ACol Index of the column to be considered
|
|
|
|
@param AWidth Width to be assigned to the column. The column width is
|
|
|
|
expressed as the count of "0" characters of the default font.
|
|
|
|
}
|
2014-04-24 23:05:00 +00:00
|
|
|
procedure TsWorksheet.WriteColWidth(ACol: Cardinal; AWidth: Single);
|
|
|
|
var
|
|
|
|
AElement: PCol;
|
|
|
|
begin
|
|
|
|
AElement := GetCol(ACol);
|
|
|
|
AElement^.Width := AWidth;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ TsWorkbook }
|
|
|
|
|
2014-06-27 14:24:23 +00:00
|
|
|
{@@
|
|
|
|
Helper method called before saving the workbook. Calculates the formulas
|
|
|
|
in all worksheets having the option soCalcBeforeSaving set.
|
|
|
|
}
|
|
|
|
procedure TsWorkbook.PrepareBeforeSaving;
|
|
|
|
var
|
|
|
|
sheet: TsWorksheet;
|
|
|
|
begin
|
|
|
|
for sheet in FWorksheets do
|
|
|
|
if (soCalcBeforeSaving in sheet.Options) then
|
|
|
|
sheet.CalcFormulas;
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
|
|
|
Helper method for clearing the spreadsheet list.
|
|
|
|
}
|
2014-04-22 23:10:32 +00:00
|
|
|
procedure TsWorkbook.RemoveWorksheetsCallback(data, arg: pointer);
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(arg);
|
2008-02-24 13:18:34 +00:00
|
|
|
TsWorksheet(data).Free;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-20 23:06:29 +00:00
|
|
|
Constructor of the workbook class. Among others, it initializes the built-in
|
|
|
|
fonts, defines the default font, and sets up the FormatSettings for localization
|
|
|
|
of some number formats.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
constructor TsWorkbook.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
FWorksheets := TFPList.Create;
|
2014-06-13 08:17:31 +00:00
|
|
|
FFormat := sfExcel8;
|
2014-05-31 21:04:53 +00:00
|
|
|
FDefaultColWidth := 12;
|
|
|
|
FDefaultRowHeight := 1;
|
2014-05-17 15:13:08 +00:00
|
|
|
FormatSettings := DefaultFormatSettings;
|
2014-06-12 22:20:45 +00:00
|
|
|
FormatSettings.ShortDateFormat := MakeShortDateFormat(FormatSettings.ShortDateFormat);
|
|
|
|
FormatSettings.LongDateFormat := MakeLongDateFormat(FormatSettings.ShortDateFormat);
|
2014-04-22 23:10:32 +00:00
|
|
|
FFontList := TFPList.Create;
|
|
|
|
SetDefaultFont('Arial', 10.0);
|
|
|
|
InitFonts;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-20 23:06:29 +00:00
|
|
|
Destructor of the workbook class
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
destructor TsWorkbook.Destroy;
|
|
|
|
begin
|
|
|
|
RemoveAllWorksheets;
|
2014-04-22 23:10:32 +00:00
|
|
|
RemoveAllFonts;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
FWorksheets.Free;
|
2014-04-22 23:10:32 +00:00
|
|
|
FFontList.Free;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
2014-04-18 13:17:22 +00:00
|
|
|
|
2011-08-11 14:30:25 +00:00
|
|
|
{@@
|
|
|
|
Helper method for determining the spreadsheet type from the file type extension
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
@param AFileName Name of the file to be considered
|
|
|
|
@param SheetType File format found from analysis of the extension (output)
|
|
|
|
@return True if the file matches any of the known formats, false otherwise
|
2011-08-11 14:30:25 +00:00
|
|
|
}
|
2014-06-19 19:25:40 +00:00
|
|
|
class function TsWorkbook.GetFormatFromFileName(const AFileName: TFileName;
|
|
|
|
out SheetType: TsSpreadsheetFormat): Boolean;
|
2011-08-11 14:30:25 +00:00
|
|
|
var
|
|
|
|
suffix: String;
|
|
|
|
begin
|
|
|
|
Result := True;
|
2014-04-20 20:31:36 +00:00
|
|
|
suffix := Lowercase(ExtractFileExt(AFileName));
|
2011-08-11 14:30:25 +00:00
|
|
|
if suffix = STR_EXCEL_EXTENSION then SheetType := sfExcel8
|
|
|
|
else if suffix = STR_OOXML_EXCEL_EXTENSION then SheetType := sfOOXML
|
|
|
|
else if suffix = STR_OPENDOCUMENT_CALC_EXTENSION then SheetType := sfOpenDocument
|
|
|
|
else if suffix = STR_COMMA_SEPARATED_EXTENSION then SheetType := sfCSV
|
2013-06-11 14:15:59 +00:00
|
|
|
else if suffix = STR_WIKITABLE_PIPES then SheetType := sfWikiTable_Pipes
|
|
|
|
else if suffix = STR_WIKITABLE_WIKIMEDIA then SheetType := sfWikiTable_WikiMedia
|
2011-08-11 14:30:25 +00:00
|
|
|
else Result := False;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Convenience method which creates the correct reader object for a given
|
|
|
|
spreadsheet format.
|
|
|
|
|
|
|
|
@param AFormat File format which is assumed when reading a document into
|
|
|
|
to workbook. An exception is raised when the document has
|
|
|
|
a different format.
|
|
|
|
|
|
|
|
@return An instance of a TsCustomSpreadReader descendent which is able to
|
|
|
|
read thi given file format.
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
|
|
|
|
for i := 0 to Length(GsSpreadFormats) - 1 do
|
|
|
|
if GsSpreadFormats[i].Format = AFormat then
|
|
|
|
begin
|
2014-04-23 22:29:32 +00:00
|
|
|
Result := GsSpreadFormats[i].ReaderClass.Create(self);
|
2009-01-10 21:47:59 +00:00
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if Result = nil then raise Exception.Create(lpUnsupportedReadFormat);
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Convenience method which creates the correct writer object for a given
|
|
|
|
spreadsheet format.
|
|
|
|
|
|
|
|
@param AFormat File format to be used for writing the workbook
|
|
|
|
|
|
|
|
@return An instance of a TsCustomSpreadWriter descendent which is able to
|
|
|
|
write the given file format.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
|
|
|
|
for i := 0 to Length(GsSpreadFormats) - 1 do
|
|
|
|
if GsSpreadFormats[i].Format = AFormat then
|
|
|
|
begin
|
2014-04-23 22:29:32 +00:00
|
|
|
Result := GsSpreadFormats[i].WriterClass.Create(self);
|
2008-02-24 13:18:34 +00:00
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
if Result = nil then raise Exception.Create(lpUnsupportedWriteFormat);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Reads the document from a file. It is assumed to have a given file format.
|
|
|
|
|
|
|
|
@param AFileName Name of the file to be read
|
|
|
|
@param AFormat File format assumed
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.ReadFromFile(AFileName: string;
|
|
|
|
AFormat: TsSpreadsheetFormat);
|
|
|
|
var
|
|
|
|
AReader: TsCustomSpreadReader;
|
|
|
|
begin
|
|
|
|
AReader := CreateSpreadReader(AFormat);
|
|
|
|
try
|
|
|
|
AReader.ReadFromFile(AFileName, Self);
|
2014-04-21 21:43:43 +00:00
|
|
|
FFormat := AFormat;
|
2009-01-10 21:47:59 +00:00
|
|
|
finally
|
|
|
|
AReader.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2011-05-25 13:52:46 +00:00
|
|
|
{@@
|
|
|
|
Reads the document from a file. This method will try to guess the format from
|
|
|
|
the extension. In the case of the ambiguous xls extension, it will simply
|
|
|
|
assume that it is BIFF8. Note that it could be BIFF2, 3, 4 or 5 too.
|
|
|
|
}
|
2011-08-11 14:30:25 +00:00
|
|
|
procedure TsWorkbook.ReadFromFile(AFileName: string); overload;
|
2011-05-25 13:52:46 +00:00
|
|
|
var
|
2011-08-11 14:30:25 +00:00
|
|
|
SheetType: TsSpreadsheetFormat;
|
|
|
|
valid: Boolean;
|
|
|
|
lException: Exception = nil;
|
2011-05-25 13:52:46 +00:00
|
|
|
begin
|
2011-08-11 14:30:25 +00:00
|
|
|
valid := GetFormatFromFileName(AFileName, SheetType);
|
|
|
|
if valid then
|
|
|
|
begin
|
|
|
|
if SheetType = sfExcel8 then
|
|
|
|
begin
|
2011-09-07 05:37:15 +00:00
|
|
|
while True do
|
|
|
|
begin
|
2011-08-11 14:30:25 +00:00
|
|
|
try
|
|
|
|
ReadFromFile(AFileName, SheetType);
|
|
|
|
valid := True;
|
|
|
|
except
|
|
|
|
on E: Exception do
|
|
|
|
begin
|
|
|
|
if SheetType = sfExcel8 then lException := E;
|
|
|
|
valid := False
|
|
|
|
end;
|
|
|
|
end;
|
2011-09-07 05:37:15 +00:00
|
|
|
if valid or (SheetType = sfExcel2) then Break;
|
|
|
|
SheetType := Pred(SheetType);
|
|
|
|
end;
|
2011-08-11 14:30:25 +00:00
|
|
|
|
|
|
|
// A failed attempt to read a file should bring an exception, so re-raise
|
|
|
|
// the exception if necessary. We re-raise the exception brought by Excel 8,
|
|
|
|
// since this is the most common format
|
|
|
|
if (not valid) and (lException <> nil) then raise lException;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
ReadFromFile(AFileName, SheetType);
|
2014-04-20 20:31:36 +00:00
|
|
|
end else
|
|
|
|
raise Exception.CreateFmt(lpNoValidSpreadsheetFile, [AFileName]);
|
2011-05-25 13:52:46 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
|
|
|
Reads the document from a file, but ignores the extension.
|
|
|
|
}
|
2011-12-25 09:03:20 +00:00
|
|
|
procedure TsWorkbook.ReadFromFileIgnoringExtension(AFileName: string);
|
|
|
|
var
|
|
|
|
SheetType: TsSpreadsheetFormat;
|
|
|
|
lException: Exception;
|
|
|
|
begin
|
2014-06-19 19:25:40 +00:00
|
|
|
SheetType := sfExcel8;
|
2014-06-23 21:49:20 +00:00
|
|
|
while (SheetType in [sfExcel2..sfExcel8, sfOpenDocument, sfOOXML]) and (lException <> nil) do
|
2011-12-25 09:03:20 +00:00
|
|
|
begin
|
|
|
|
try
|
|
|
|
Dec(SheetType);
|
|
|
|
ReadFromFile(AFileName, SheetType);
|
|
|
|
lException := nil;
|
|
|
|
except
|
|
|
|
on E: Exception do
|
|
|
|
{ do nothing } ;
|
|
|
|
end;
|
|
|
|
if lException = nil then Break;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
|
|
|
Reads the document from a seekable stream.
|
2014-06-23 21:49:20 +00:00
|
|
|
|
|
|
|
@param AStream Stream being read
|
|
|
|
@param AFormat File format assumed.
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.ReadFromStream(AStream: TStream;
|
|
|
|
AFormat: TsSpreadsheetFormat);
|
|
|
|
var
|
|
|
|
AReader: TsCustomSpreadReader;
|
|
|
|
begin
|
|
|
|
AReader := CreateSpreadReader(AFormat);
|
|
|
|
|
|
|
|
try
|
|
|
|
AReader.ReadFromStream(AStream, Self);
|
|
|
|
finally
|
|
|
|
AReader.Free;
|
|
|
|
end;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Writes the document to a file. If the file doesn't exist, it will be created.
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
@param AFileName Name of the file to be written
|
|
|
|
@param AFormat The file will be written in this file format
|
|
|
|
@param AOverwriteExisting If the file is already existing it will be
|
|
|
|
overwritten in case of AOverwriteExisting = true.
|
|
|
|
If false an exception will be raised.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
2009-11-08 19:21:23 +00:00
|
|
|
procedure TsWorkbook.WriteToFile(const AFileName: string;
|
|
|
|
const AFormat: TsSpreadsheetFormat; const AOverwriteExisting: Boolean = False);
|
2008-02-24 13:18:34 +00:00
|
|
|
var
|
|
|
|
AWriter: TsCustomSpreadWriter;
|
|
|
|
begin
|
|
|
|
AWriter := CreateSpreadWriter(AFormat);
|
|
|
|
try
|
2014-06-27 14:24:23 +00:00
|
|
|
PrepareBeforeSaving;
|
2014-04-23 22:29:32 +00:00
|
|
|
AWriter.WriteToFile(AFileName, AOverwriteExisting);
|
2008-02-24 13:18:34 +00:00
|
|
|
finally
|
|
|
|
AWriter.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2011-08-11 14:30:25 +00:00
|
|
|
{@@
|
2014-06-23 21:49:20 +00:00
|
|
|
Writes the document to file based on the extension.
|
|
|
|
If this was an earlier sfExcel type file, it will be upgraded to sfExcel8.
|
|
|
|
|
|
|
|
@param AFileName Name of the destination file
|
|
|
|
@param AOverwriteExisting If the file already exists it will be overwritten
|
|
|
|
of AOverwriteExisting is true. In case of false, an
|
|
|
|
exception will be raised.
|
2011-08-11 14:30:25 +00:00
|
|
|
}
|
2013-12-07 13:42:22 +00:00
|
|
|
procedure TsWorkbook.WriteToFile(const AFileName: String;
|
|
|
|
const AOverwriteExisting: Boolean);
|
2011-08-11 14:30:25 +00:00
|
|
|
var
|
|
|
|
SheetType: TsSpreadsheetFormat;
|
|
|
|
valid: Boolean;
|
|
|
|
begin
|
|
|
|
valid := GetFormatFromFileName(AFileName, SheetType);
|
|
|
|
if valid then WriteToFile(AFileName, SheetType, AOverwriteExisting)
|
|
|
|
else raise Exception.Create(Format(
|
|
|
|
'[TsWorkbook.WriteToFile] Attempted to save a spreadsheet by extension, but the extension %s is invalid.', [ExtractFileExt(AFileName)]));
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
|
|
|
Writes the document to a stream
|
2014-06-23 21:49:20 +00:00
|
|
|
|
|
|
|
@param AStream Instance of the stream being written to
|
|
|
|
@param AFormat File format being written.
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
|
|
|
var
|
|
|
|
AWriter: TsCustomSpreadWriter;
|
|
|
|
begin
|
|
|
|
AWriter := CreateSpreadWriter(AFormat);
|
|
|
|
try
|
2014-06-27 14:24:23 +00:00
|
|
|
PrepareBeforeSaving;
|
2014-04-23 22:29:32 +00:00
|
|
|
AWriter.WriteToStream(AStream);
|
2008-02-24 13:18:34 +00:00
|
|
|
finally
|
|
|
|
AWriter.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Adds a new worksheet to the workbook
|
|
|
|
|
|
|
|
It is added to the end of the list of worksheets
|
|
|
|
|
|
|
|
@param AName The name of the new worksheet
|
2014-06-24 22:47:15 +00:00
|
|
|
@return The instance of the newly created worksheet
|
|
|
|
@see TsWorksheet
|
2008-02-24 13:18:34 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.AddWorksheet(AName: string): TsWorksheet;
|
|
|
|
begin
|
|
|
|
Result := TsWorksheet.Create;
|
|
|
|
|
|
|
|
Result.Name := AName;
|
2014-04-22 23:10:32 +00:00
|
|
|
Result.FWorkbook := Self;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
FWorksheets.Add(Pointer(Result));
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Quick helper routine which returns the first worksheet
|
|
|
|
|
|
|
|
@return A TsWorksheet instance if at least one is present.
|
|
|
|
nil otherwise.
|
|
|
|
|
|
|
|
@see TsWorkbook.GetWorksheetByIndex
|
2013-12-07 13:42:22 +00:00
|
|
|
@see TsWorkbook.GetWorksheetByName
|
2008-02-24 13:18:34 +00:00
|
|
|
@see TsWorksheet
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetFirstWorksheet: TsWorksheet;
|
|
|
|
begin
|
|
|
|
Result := TsWorksheet(FWorksheets.First);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Gets the worksheet with a given index
|
|
|
|
|
|
|
|
The index is zero-based, so the first worksheet
|
|
|
|
added has index 0, the second 1, etc.
|
|
|
|
|
|
|
|
@param AIndex The index of the worksheet (0-based)
|
|
|
|
|
|
|
|
@return A TsWorksheet instance if one is present at that index.
|
|
|
|
nil otherwise.
|
|
|
|
|
|
|
|
@see TsWorkbook.GetFirstWorksheet
|
2013-12-07 13:42:22 +00:00
|
|
|
@see TsWorkbook.GetWorksheetByName
|
2008-02-24 13:18:34 +00:00
|
|
|
@see TsWorksheet
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet;
|
|
|
|
begin
|
2014-04-22 23:10:32 +00:00
|
|
|
if (integer(AIndex) < FWorksheets.Count) and (integer(AIndex)>=0) then
|
|
|
|
Result := TsWorksheet(FWorksheets.Items[AIndex])
|
|
|
|
else
|
|
|
|
Result := nil;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2013-12-07 13:42:22 +00:00
|
|
|
{@@
|
|
|
|
Gets the worksheet with a given worksheet name
|
|
|
|
|
|
|
|
@param AName The name of the worksheet
|
|
|
|
|
|
|
|
@return A TsWorksheet instance if one is found with that name,
|
|
|
|
nil otherwise.
|
|
|
|
|
|
|
|
@see TsWorkbook.GetFirstWorksheet
|
|
|
|
@see TsWorkbook.GetWorksheetByIndex
|
|
|
|
@see TsWorksheet
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetWorksheetByName(AName: String): TsWorksheet;
|
|
|
|
var
|
|
|
|
i:integer;
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
for i:=0 to FWorksheets.Count-1 do
|
|
|
|
begin
|
|
|
|
if TsWorkSheet(FWorkSheets.Items[i]).Name=AName then
|
|
|
|
begin
|
|
|
|
Result := TsWorksheet(FWorksheets.Items[i]);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
|
|
|
The number of worksheets on the workbook
|
|
|
|
|
|
|
|
@see TsWorksheet
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetWorksheetCount: Cardinal;
|
|
|
|
begin
|
|
|
|
Result := FWorksheets.Count;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Clears the list of Worksheets and releases their memory.
|
|
|
|
}
|
|
|
|
procedure TsWorkbook.RemoveAllWorksheets;
|
|
|
|
begin
|
2014-04-22 23:10:32 +00:00
|
|
|
FWorksheets.ForEachCall(RemoveWorksheetsCallback, nil);
|
|
|
|
end;
|
2014-06-24 22:47:15 +00:00
|
|
|
(*
|
|
|
|
{@@
|
|
|
|
Sets the selected flag for the sheet with the given index.
|
|
|
|
Excel requires one sheet to be selected, otherwise strange things happen when
|
|
|
|
the file is loaded into Excel (cannot print, hanging instance of Excel - see
|
|
|
|
bug 0026386).
|
2014-04-22 23:10:32 +00:00
|
|
|
|
2014-06-24 22:47:15 +00:00
|
|
|
@param AIndex Index of the worksheet to be selected
|
|
|
|
}
|
|
|
|
procedure TsWorkbook.SelectWorksheet(AIndex: Integer);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
sheet: TsWorksheet;
|
|
|
|
begin
|
|
|
|
for i:=0 to FWorksheets.Count-1 do begin
|
|
|
|
sheet := TsWorksheet(FWorksheets.Items[i]);
|
|
|
|
if i = AIndex then
|
|
|
|
sheet.Options := sheet.Options + [soSelected]
|
|
|
|
else
|
|
|
|
sheet.Options := sheet.Options - [soSelected];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
*)
|
2014-04-22 23:10:32 +00:00
|
|
|
|
|
|
|
{ Font handling }
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Adds a font to the font list. Returns the index in the font list.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param AFontName Name of the font (like 'Arial')
|
|
|
|
@param ASize Size of the font in points
|
|
|
|
@param AStyle Style of the font, a combination of TsFontStyle elements
|
|
|
|
@param AColor Color of the font, given by its index into the workbook's palette.
|
|
|
|
@return Index of the font in the workbook's font list
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.AddFont(const AFontName: String; ASize: Single;
|
|
|
|
AStyle: TsFontStyles; AColor: TsColor): Integer;
|
|
|
|
var
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
fnt := TsFont.Create;
|
|
|
|
fnt.FontName := AFontName;
|
|
|
|
fnt.Size := ASize;
|
|
|
|
fnt.Style := AStyle;
|
|
|
|
fnt.Color := AColor;
|
|
|
|
Result := AddFont(fnt);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Adds a font to the font list. Returns the index in the font list.
|
|
|
|
|
|
|
|
@param AFont TsFont record containing all font parameters
|
|
|
|
@return Index of the font in the workbook's font list
|
|
|
|
}
|
2014-04-22 23:10:32 +00:00
|
|
|
function TsWorkbook.AddFont(const AFont: TsFont): Integer;
|
|
|
|
begin
|
|
|
|
// Font index 4 does not exist in BIFF. Avoid that a real font gets this index.
|
|
|
|
if FFontList.Count = 4 then
|
|
|
|
FFontList.Add(nil);
|
|
|
|
result := FFontList.Add(AFont);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-20 23:06:29 +00:00
|
|
|
Copies a font list to the workbook's font list
|
|
|
|
|
|
|
|
@param ASource Font list to be copied
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.CopyFontList(ASource: TFPList);
|
|
|
|
var
|
|
|
|
fnt: TsFont;
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
RemoveAllFonts;
|
|
|
|
for i:=0 to ASource.Count-1 do begin
|
|
|
|
fnt := TsFont(ASource.Items[i]);
|
|
|
|
AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Checks whether the font with the given specification is already contained in
|
2014-06-20 23:06:29 +00:00
|
|
|
the font list. Returns the index, or -1 if not found.
|
|
|
|
|
|
|
|
@param AFontName Name of the font (like 'Arial')
|
|
|
|
@param ASize Size of the font in points
|
|
|
|
@param AStyle Style of the font, a combination of TsFontStyle elements
|
|
|
|
@param AColor Color of the font, given by its index into the workbook's palette.
|
|
|
|
@return Index of the font in the font list, or -1 if not found.
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.FindFont(const AFontName: String; ASize: Single;
|
|
|
|
AStyle: TsFontStyles; AColor: TsColor): Integer;
|
|
|
|
var
|
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
for Result := 0 to FFontList.Count-1 do begin
|
|
|
|
fnt := TsFont(FFontList.Items[Result]);
|
|
|
|
if (fnt <> nil) and
|
|
|
|
SameText(AFontName, fnt.FontName) and
|
|
|
|
(abs(ASize - fnt.Size) < 0.001) and // careful when comparing floating point numbers
|
|
|
|
(AStyle = fnt.Style) and
|
|
|
|
(AColor = fnt.Color)
|
|
|
|
then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-20 23:06:29 +00:00
|
|
|
Initializes the font list. In case of BIFF format, adds 5 fonts:
|
|
|
|
|
|
|
|
0: default font
|
|
|
|
1: like default font, but bold
|
|
|
|
2: like default font, but italic
|
|
|
|
3: like default font, but underlined
|
|
|
|
4: empty (due to a restriction of Excel)
|
|
|
|
5: like default font, but bold and italic
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.InitFonts;
|
|
|
|
var
|
|
|
|
fntName: String;
|
|
|
|
fntSize: Single;
|
|
|
|
begin
|
|
|
|
// Memorize old default font
|
|
|
|
with TsFont(FFontList.Items[0]) do begin
|
|
|
|
fntName := FontName;
|
|
|
|
fntSize := Size;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Remove current font list
|
|
|
|
RemoveAllFonts;
|
|
|
|
|
|
|
|
// Build new font list
|
|
|
|
SetDefaultFont(fntName, fntSize); // Default font (FONT0)
|
|
|
|
AddFont(fntName, fntSize, [fssBold], scBlack); // FONT1 for uffBold
|
|
|
|
|
2014-06-06 08:48:22 +00:00
|
|
|
AddFont(fntName, fntSize, [fssItalic], scBlack); // FONT2 (Italic)
|
|
|
|
AddFont(fntName, fntSize, [fssUnderline], scBlack); // FONT3 (fUnderline)
|
2014-04-22 23:10:32 +00:00
|
|
|
// FONT4 which does not exist in BIFF is added automatically with nil as place-holder
|
2014-06-06 08:48:22 +00:00
|
|
|
AddFont(fntName, fntSize, [fssBold, fssItalic], scBlack); // FONT5 (bold & italic)
|
2014-04-22 23:10:32 +00:00
|
|
|
|
|
|
|
FBuiltinFontCount := FFontList.Count;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Clears the list of fonts and releases their memory.
|
|
|
|
}
|
|
|
|
procedure TsWorkbook.RemoveAllFonts;
|
|
|
|
var
|
2014-06-19 19:25:40 +00:00
|
|
|
i: Integer;
|
2014-04-22 23:10:32 +00:00
|
|
|
fnt: TsFont;
|
|
|
|
begin
|
|
|
|
for i:=FFontList.Count-1 downto 0 do begin
|
|
|
|
fnt := TsFont(FFontList.Items[i]);
|
|
|
|
fnt.Free;
|
|
|
|
FFontList.Delete(i);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Defines the default font. This is the font with index 0 in the FontList.
|
|
|
|
The next built-in fonts will have the same font name and size
|
|
|
|
}
|
|
|
|
procedure TsWorkbook.SetDefaultFont(const AFontName: String; ASize: Single);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
if FFontList.Count = 0 then
|
|
|
|
AddFont(AFontName, ASize, [], scBlack)
|
|
|
|
else
|
|
|
|
for i:=0 to FBuiltinFontCount-1 do begin
|
|
|
|
if (i <> 4) and (i < FFontList.Count) then
|
|
|
|
with TsFont(FFontList[i]) do begin
|
|
|
|
FontName := AFontName;
|
|
|
|
Size := ASize;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-06 13:09:14 +00:00
|
|
|
{@@
|
|
|
|
Returns the default font. This is the first font (index 0) in the font list
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetDefaultFont: TsFont;
|
|
|
|
begin
|
|
|
|
Result := GetFont(0);
|
|
|
|
end;
|
|
|
|
|
2014-05-31 21:04:53 +00:00
|
|
|
{@@
|
|
|
|
Returns the point size of the default font
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetDefaultFontSize: Single;
|
|
|
|
begin
|
|
|
|
Result := GetFont(0).Size;
|
|
|
|
end;
|
|
|
|
|
2014-04-22 23:10:32 +00:00
|
|
|
{@@
|
|
|
|
Returns the font with the given index.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param AIndex Index of the font to be considered
|
|
|
|
@return Record containing all parameters of the font (or nil if not found).
|
2014-04-22 23:10:32 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.GetFont(AIndex: Integer): TsFont;
|
|
|
|
begin
|
|
|
|
if (AIndex >= 0) and (AIndex < FFontList.Count) then
|
|
|
|
Result := FFontList.Items[AIndex]
|
|
|
|
else
|
|
|
|
Result := nil;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Returns the count of registered fonts
|
|
|
|
}
|
|
|
|
function TsWorkbook.GetFontCount: Integer;
|
|
|
|
begin
|
|
|
|
Result := FFontList.Count;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-27 13:09:23 +00:00
|
|
|
{@@
|
|
|
|
Adds a color to the palette and returns its palette index, but only if the
|
|
|
|
color does not already exist - in this case, it returns the index of the
|
2014-05-27 16:21:59 +00:00
|
|
|
existing color entry.
|
|
|
|
The color must in little-endian notation (like TColor of the graphics units)
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param AColorValue Number containing the rgb code of the color to be added
|
|
|
|
@return Index of the new (or already existing) color item
|
2014-05-27 16:21:59 +00:00
|
|
|
}
|
2014-05-27 13:09:23 +00:00
|
|
|
function TsWorkbook.AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
|
|
|
begin
|
2014-05-27 16:21:59 +00:00
|
|
|
// Look look for the color. Is it already in the existing palette?
|
|
|
|
if Length(FPalette) > 0 then
|
|
|
|
for Result := 0 to Length(FPalette)-1 do
|
|
|
|
if FPalette[Result] = AColorValue then
|
|
|
|
exit;
|
2014-05-27 13:09:23 +00:00
|
|
|
|
2014-05-27 16:21:59 +00:00
|
|
|
// No --> Add it to the palette.
|
2014-05-27 13:09:23 +00:00
|
|
|
Result := Length(FPalette);
|
|
|
|
SetLength(FPalette, Result+1);
|
|
|
|
FPalette[Result] := AColorValue;
|
|
|
|
end;
|
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{@@
|
|
|
|
Converts a fpspreadsheet color into into a string RRGGBB.
|
|
|
|
Note that colors are written to xls files as ABGR (where A is 0).
|
|
|
|
if the color is scRGBColor the color value is taken from the argument
|
|
|
|
ARGBColor, otherwise from the palette entry for the color index.
|
|
|
|
}
|
|
|
|
function TsWorkbook.FPSColorToHexString(AColor: TsColor;
|
|
|
|
ARGBColor: TFPColor): string;
|
|
|
|
type
|
|
|
|
TRgba = packed record Red, Green, Blue, A: Byte end;
|
|
|
|
var
|
2014-04-24 21:27:57 +00:00
|
|
|
colorvalue: TsColorValue;
|
2014-04-23 22:29:32 +00:00
|
|
|
r,g,b: Byte;
|
|
|
|
begin
|
|
|
|
if AColor = scRGBColor then begin
|
|
|
|
r := ARGBColor.Red div $100;
|
|
|
|
g := ARGBColor.Green div $100;
|
|
|
|
b := ARGBColor.Blue div $100;
|
|
|
|
end else begin
|
2014-04-24 21:27:57 +00:00
|
|
|
colorvalue := GetPaletteColor(AColor);
|
|
|
|
r := TRgba(colorvalue).Red;
|
|
|
|
g := TRgba(colorvalue).Green;
|
|
|
|
b := TRgba(colorvalue).Blue;
|
2014-04-23 22:29:32 +00:00
|
|
|
end;
|
2014-05-27 16:21:59 +00:00
|
|
|
Result := Format('%.2x%.2x%.2x', [r, g, b]);
|
2014-04-23 22:29:32 +00:00
|
|
|
end;
|
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
{@@
|
|
|
|
Returns the name of the color pointed to by the given color index.
|
|
|
|
If the name is not known the hex string is returned as RRGGBB.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param AColorIndex Palette index of the color considered
|
|
|
|
@return String identifying the color (a color name or, if unknown, a string showing the rgb components
|
2014-04-24 21:27:57 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.GetColorName(AColorIndex: TsColor): string;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
c: TsColorValue;
|
|
|
|
begin
|
|
|
|
// Get color rgb value
|
|
|
|
c := GetPaletteColor(AColorIndex);
|
|
|
|
|
|
|
|
// Find color value in default palette
|
|
|
|
for i:=0 to High(DEFAULT_PALETTE) do
|
|
|
|
if DEFAULT_PALETTE[i] = c then begin
|
|
|
|
// if found: get the color name from the default color names array
|
|
|
|
Result := DEFAULT_COLORNAMES[i];
|
|
|
|
exit;
|
|
|
|
end;
|
2014-04-23 22:29:32 +00:00
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
// if not found: construct a string from rgb byte values.
|
|
|
|
Result := FPSColorToHexString(AColorIndex, colBlack);
|
|
|
|
end;
|
2014-04-23 22:29:32 +00:00
|
|
|
|
|
|
|
{@@
|
|
|
|
Reads the rgb color for the given index from the current palette. Can be
|
|
|
|
type-cast to TColor for usage in GUI applications.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param AColorIndex Index of the color considered
|
|
|
|
@return A number containing the rgb components in little-endian notation.
|
2014-04-23 22:29:32 +00:00
|
|
|
}
|
2014-04-24 21:27:57 +00:00
|
|
|
function TsWorkbook.GetPaletteColor(AColorIndex: TsColor): TsColorValue;
|
2014-04-23 22:29:32 +00:00
|
|
|
begin
|
|
|
|
if (AColorIndex >= 0) and (AColorIndex < GetPaletteSize) then begin
|
|
|
|
if ((FPalette = nil) or (Length(FPalette) = 0)) then
|
2014-04-24 21:27:57 +00:00
|
|
|
Result := DEFAULT_PALETTE[AColorIndex]
|
2014-04-23 22:29:32 +00:00
|
|
|
else
|
|
|
|
Result := FPalette[AColorIndex];
|
|
|
|
end else
|
|
|
|
Result := $000000; // "black" as default
|
|
|
|
end;
|
|
|
|
|
2014-05-27 22:12:48 +00:00
|
|
|
{@@
|
|
|
|
Converts the palette color of the given index to a string that can be used
|
2014-06-20 23:06:29 +00:00
|
|
|
in HTML code. For ODS.
|
|
|
|
|
|
|
|
@param AColorIndex Index of the color considered
|
|
|
|
@return A HTML-compatible string identifying the color. "Red", for example, is returned as '#FF0000';
|
2014-05-27 22:12:48 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.GetPaletteColorAsHTMLStr(AColorIndex: TsColor): String;
|
|
|
|
begin
|
|
|
|
Result := ColorToHTMLColorStr(GetPaletteColor(AColorIndex));
|
|
|
|
end;
|
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{@@
|
2014-04-24 21:27:57 +00:00
|
|
|
Replaces a color value of the current palette by a new value. The color must
|
2014-06-20 23:06:29 +00:00
|
|
|
be given as ABGR (little-endian), with A=0).
|
|
|
|
|
|
|
|
@param AColorIndex Palette index of the color to be replaced
|
|
|
|
@param AColorValue Number containing the rgb components of the new color
|
|
|
|
}
|
2014-04-24 21:27:57 +00:00
|
|
|
procedure TsWorkbook.SetPaletteColor(AColorIndex: TsColor; AColorValue: TsColorValue);
|
|
|
|
begin
|
|
|
|
if (AColorIndex >= 0) and (AColorIndex < GetPaletteSize) then begin
|
|
|
|
if ((FPalette = nil) or (Length(FPalette) = 0)) then
|
|
|
|
DEFAULT_PALETTE[AColorIndex] := AColorValue
|
|
|
|
else
|
|
|
|
FPalette[AColorIndex] := AColorValue;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Returns the count of palette colors
|
2014-04-23 22:29:32 +00:00
|
|
|
}
|
|
|
|
function TsWorkbook.GetPaletteSize: Integer;
|
|
|
|
begin
|
|
|
|
if (FPalette = nil) or (Length(FPalette) = 0) then
|
|
|
|
Result := High(DEFAULT_PALETTE) + 1
|
|
|
|
else
|
|
|
|
Result := Length(FPalette);
|
|
|
|
end;
|
|
|
|
|
2014-05-27 16:21:59 +00:00
|
|
|
{@@
|
|
|
|
Instructs the workbook to take colors from the default palette. Is called
|
|
|
|
from ODS reader because ODS does not have a palette. Without a palette the
|
2014-06-20 23:06:29 +00:00
|
|
|
color constants (scRed etc.) would not be correct any more.
|
|
|
|
}
|
2014-05-27 16:21:59 +00:00
|
|
|
procedure TsWorkbook.UseDefaultPalette;
|
|
|
|
begin
|
|
|
|
UsePalette(@DEFAULT_PALETTE, Length(DEFAULT_PALETTE), false);
|
|
|
|
end;
|
|
|
|
|
2014-04-23 22:29:32 +00:00
|
|
|
{@@
|
2014-06-20 23:06:29 +00:00
|
|
|
Instructs the Workbook to take colors from the palette pointed to by the parameter APalette
|
2014-04-23 22:29:32 +00:00
|
|
|
This palette is only used for writing. When reading the palette found in the
|
|
|
|
file is used.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
|
|
|
@param APalette Pointer to the array of TsColorValue numbers which will
|
|
|
|
become the new palette
|
|
|
|
@param APaletteCount Count of numbers in the source palette
|
|
|
|
@param ABigEnding If true, indicates that the source palette is in
|
|
|
|
big-endian notation. The methods inverts the rgb
|
|
|
|
components to little-endian which is used by fpspreadsheet
|
|
|
|
internally.
|
2014-04-23 22:29:32 +00:00
|
|
|
}
|
|
|
|
procedure TsWorkbook.UsePalette(APalette: PsPalette; APaletteCount: Word;
|
2014-04-24 21:27:57 +00:00
|
|
|
ABigEndian: Boolean);
|
2014-04-23 22:29:32 +00:00
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
{$IFOPT R+}
|
|
|
|
{$DEFINE RNGCHECK}
|
|
|
|
{$ENDIF}
|
|
|
|
SetLength(FPalette, APaletteCount);
|
2014-04-24 21:27:57 +00:00
|
|
|
if ABigEndian then
|
2014-04-23 22:29:32 +00:00
|
|
|
for i:=0 to APaletteCount-1 do
|
|
|
|
{$IFDEF RNGCHECK}
|
|
|
|
{$R-}
|
|
|
|
{$ENDIF}
|
|
|
|
FPalette[i] := LongRGBToExcelPhysical(APalette^[i])
|
|
|
|
{$IFDEF RNGCHECK}
|
|
|
|
{$R+}
|
|
|
|
{$ENDIF}
|
|
|
|
else
|
|
|
|
for i:=0 to APaletteCount-1 do
|
|
|
|
{$IFDEF RNGCHECK}
|
|
|
|
{$R-}
|
|
|
|
{$ENDIF}
|
|
|
|
FPalette[i] := APalette^[i];
|
|
|
|
{$IFDEF RNGCHECK}
|
|
|
|
{$R+}
|
|
|
|
{$ENDIF}
|
|
|
|
end;
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
|
|
|
|
{ TsCustomNumFormatList }
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Constructor of the number format list.
|
|
|
|
@param AWorkbook The workbook is needed to get access to its "FormatSettings"
|
|
|
|
for localization of some formatting strings. }
|
2014-05-20 16:13:48 +00:00
|
|
|
constructor TsCustomNumFormatList.Create(AWorkbook: TsWorkbook);
|
2014-05-14 15:24:02 +00:00
|
|
|
begin
|
|
|
|
inherited Create;
|
2014-05-20 16:13:48 +00:00
|
|
|
FWorkbook := AWorkbook;
|
2014-05-14 15:24:02 +00:00
|
|
|
AddBuiltinFormats;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Destructor of the number format list: clears the list and destroys the
|
|
|
|
format items }
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor TsCustomNumFormatList.Destroy;
|
|
|
|
begin
|
|
|
|
Clear;
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Adds a number format described by the Excel format index, the ODF format
|
|
|
|
name, the format string, and the built-in format identifier to the list
|
|
|
|
and returns the index of the new item.
|
|
|
|
@param AFormatIndex Format index to be used by Excel
|
|
|
|
@param AFormatName Format name to be used by OpenDocument
|
|
|
|
@param AFormatString String of formatting codes
|
|
|
|
@param ANumFormat Identifier for built-in number format
|
|
|
|
@return List index of the new item }
|
2014-05-21 12:12:16 +00:00
|
|
|
function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatName, AFormatString: String; ANumFormat: TsNumberFormat): Integer;
|
2014-05-14 15:24:02 +00:00
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
|
|
|
begin
|
|
|
|
item := TsNumFormatData.Create;
|
|
|
|
item.Index := AFormatIndex;
|
2014-05-26 08:03:36 +00:00
|
|
|
item.Name := AFormatName;
|
2014-05-14 15:24:02 +00:00
|
|
|
item.NumFormat := ANumFormat;
|
|
|
|
item.FormatString := AFormatString;
|
|
|
|
Result := inherited Add(item);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Adds a number format described by the Excel format index, the format string,
|
|
|
|
and the built-in format identifier to the list and returns the index of
|
|
|
|
the new item in the format list. To be used when writing an Excel file.
|
|
|
|
@param AFormatIndex Format index to be used by Excel
|
|
|
|
@param AFormatString String of formatting codes
|
|
|
|
@param ANumFormat Identifier for built-in number format
|
|
|
|
@return Index of the new item in the format list }
|
2014-05-26 08:03:36 +00:00
|
|
|
function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatString: String; ANumFormat: TsNumberFormat): integer;
|
2014-05-26 08:03:36 +00:00
|
|
|
begin
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := AddFormat(AFormatIndex, '', AFormatString, ANumFormat);
|
2014-05-26 08:03:36 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Adds a number format described by the ODF format name, the format string,
|
|
|
|
and the built-in format identifier to the list and returns the index of
|
|
|
|
the new item in the format list. To be used when writing an ODS file.
|
|
|
|
@param AFormatName Format name to be used by OpenDocument
|
|
|
|
@param AFormatString String of formatting codes
|
|
|
|
@param ANumFormat Identifier for built-in number format
|
|
|
|
@return Index of the new item in the format list }
|
2014-05-26 08:03:36 +00:00
|
|
|
function TsCustomNumFormatList.AddFormat(AFormatName, AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat: TsNumberFormat): Integer;
|
2014-05-21 12:12:16 +00:00
|
|
|
begin
|
2014-05-26 22:27:07 +00:00
|
|
|
if (AFormatString = '') and (ANumFormat <> nfGeneral) then begin
|
2014-05-21 12:12:16 +00:00
|
|
|
Result := 0;
|
|
|
|
exit;
|
|
|
|
end;
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := AddFormat(FNextFormatIndex, AFormatName, AFormatString, ANumFormat);
|
2014-05-21 12:12:16 +00:00
|
|
|
inc(FNextFormatIndex);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Adds a number format described by the format string, and the built-in
|
|
|
|
format identifier to the format list and returns the index of the new
|
|
|
|
item in the list. The Excel format index and ODS format name are auto-generated.
|
|
|
|
@param AFormatString String of formatting codes
|
|
|
|
@param ANumFormat Identifier for built-in number format
|
|
|
|
@return Index of the new item in the list }
|
2014-05-26 08:03:36 +00:00
|
|
|
function TsCustomNumFormatList.AddFormat(AFormatString: String;
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat: TsNumberFormat): Integer;
|
2014-05-26 08:03:36 +00:00
|
|
|
begin
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := AddFormat('', AFormatString, ANumFormat);
|
2014-05-26 08:03:36 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Adds the number format used by a given cell to the list.
|
|
|
|
@param AFormatCell Pointer to a cell providing the format to be stored in the list }
|
2014-05-14 15:24:02 +00:00
|
|
|
function TsCustomNumFormatList.AddFormat(AFormatCell: PCell): Integer;
|
|
|
|
begin
|
|
|
|
if AFormatCell = nil then
|
|
|
|
raise Exception.Create('TsCustomNumFormat.Add: No nil pointers please');
|
|
|
|
|
|
|
|
if Count = 0 then
|
|
|
|
raise Exception.Create('TsCustomNumFormatList: Error in program logics: You must provide built-in formats first.');
|
|
|
|
|
2014-05-17 15:13:08 +00:00
|
|
|
Result := AddFormat(FNextFormatIndex,
|
|
|
|
AFormatCell^.NumberFormatStr,
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatCell^.NumberFormat
|
2014-05-17 15:13:08 +00:00
|
|
|
);
|
2014-05-14 15:24:02 +00:00
|
|
|
|
|
|
|
inc(FNextFormatIndex);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Adds the builtin format items to the list. The formats must be specified in
|
|
|
|
a way that is compatible with fpc syntax.
|
|
|
|
|
|
|
|
Conversion of the formatstrings to the syntax used in the destination file
|
|
|
|
can be done by calling "ConvertAfterReadung" bzw. "ConvertBeforeWriting".
|
2014-05-21 12:12:16 +00:00
|
|
|
"AddBuiltInFormats" must be called before user items are added.
|
2014-06-20 23:06:29 +00:00
|
|
|
|
2014-05-15 12:53:56 +00:00
|
|
|
Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. doesn't save formats <164)
|
|
|
|
and must initialize the index of the first user format (FNextFormatIndex)
|
2014-06-20 23:06:29 +00:00
|
|
|
which is automatically incremented when adding user formats.
|
|
|
|
|
|
|
|
In TsCustomNumFormatList nothing is added. }
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomNumFormatList.AddBuiltinFormats;
|
|
|
|
begin
|
2014-05-21 12:12:16 +00:00
|
|
|
// must be overridden - see xlscommon as an example.
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Called from the reader when a format item has been read from an Excel file.
|
|
|
|
Determines the number format type, format string etc and converts the
|
|
|
|
format string to fpc syntax which is used directly for getting the cell text.
|
|
|
|
@param AFormatIndex Excel index of the number format read from the file
|
|
|
|
@param AFormatString String of formatting codes as read fromt the file. }
|
|
|
|
procedure TsCustomNumFormatList.AnalyzeAndAdd(AFormatIndex: Integer;
|
|
|
|
AFormatString: String);
|
|
|
|
var
|
|
|
|
nf: TsNumberFormat = nfGeneral;
|
|
|
|
begin
|
|
|
|
if FindByIndex(AFormatIndex) > -1 then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
// Analyze & convert the format string, extract infos for internal formatting
|
|
|
|
ConvertAfterReading(AFormatIndex, AFormatString, nf);
|
|
|
|
|
|
|
|
// Add the new item
|
|
|
|
AddFormat(AFormatIndex, AFormatString, nf);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@ Clears the number format list and frees memory occupied by the format items. }
|
|
|
|
procedure TsCustomNumFormatList.Clear;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
for i:=0 to Count-1 do RemoveFormat(i);
|
|
|
|
inherited Clear;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Takes the format string as it is read from the file and extracts the
|
|
|
|
built-in number format identifier out of it for use by fpc.
|
|
|
|
The method also converts the format string to a form that can be used
|
|
|
|
by fpc's FormatDateTime and FormatFloat.
|
|
|
|
|
|
|
|
The method should be overridden in a class that knows knows more about the
|
|
|
|
details of the spreadsheet file format.
|
|
|
|
|
|
|
|
@param AFormatIndex Excel index of the number format read
|
|
|
|
@param AFormatString string of formatting codes extracted from the file data
|
|
|
|
@param ANumFormat identifier for built-in fpspreadsheet format extracted
|
|
|
|
from the file data }
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure TsCustomNumFormatList.ConvertAfterReading(AFormatIndex: Integer;
|
2014-06-12 22:20:45 +00:00
|
|
|
var AFormatString: String; var ANumFormat: TsNumberFormat);
|
2014-05-20 16:13:48 +00:00
|
|
|
var
|
|
|
|
parser: TsNumFormatParser;
|
|
|
|
fmt: String;
|
|
|
|
lFormatData: TsNumFormatData;
|
|
|
|
i: Integer;
|
|
|
|
begin
|
2014-05-26 22:27:07 +00:00
|
|
|
i := FindByIndex(AFormatIndex);
|
2014-05-20 16:13:48 +00:00
|
|
|
if i > 0 then begin
|
|
|
|
lFormatData := Items[i];
|
|
|
|
fmt := lFormatData.FormatString;
|
|
|
|
end else
|
|
|
|
fmt := AFormatString;
|
2014-06-02 08:07:56 +00:00
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
// Analyzes the format string and tries to convert it to fpSpreadsheet format.
|
2014-06-20 23:06:29 +00:00
|
|
|
parser := TsNumFormatParser.Create(Workbook, fmt);
|
2014-05-20 16:13:48 +00:00
|
|
|
try
|
|
|
|
if parser.Status = psOK then begin
|
2014-06-12 22:20:45 +00:00
|
|
|
ANumFormat := parser.NumFormat;
|
|
|
|
AFormatString := parser.FormatString[nfdDefault];
|
|
|
|
end else begin
|
|
|
|
// Show an error here?
|
2014-05-21 12:12:16 +00:00
|
|
|
end;
|
|
|
|
finally
|
|
|
|
parser.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Is called before collecting all number formats of the spreadsheet and before
|
|
|
|
writing them to file. Its purpose is to convert the format string as used by fpc
|
2014-06-12 22:20:45 +00:00
|
|
|
to a format compatible with the spreadsheet file format.
|
2014-06-20 23:06:29 +00:00
|
|
|
Nothing is changed in the TsCustomNumFormatList, the method needs to be
|
|
|
|
overridden by a descendant class which known more about the details of the
|
|
|
|
destination file format.
|
|
|
|
|
|
|
|
Needs to be overridden by a class knowing more about the destination file
|
|
|
|
format.
|
|
|
|
|
|
|
|
@param AFormatString String of formatting codes. On input in fpc syntax. Is
|
|
|
|
overwritten on output by format string compatible with
|
|
|
|
the destination file.
|
|
|
|
@param ANumFormat Identifier for built-in fpspreadsheet number format }
|
2014-05-21 12:12:16 +00:00
|
|
|
procedure TsCustomNumFormatList.ConvertBeforeWriting(var AFormatString: String;
|
2014-06-13 13:33:02 +00:00
|
|
|
var ANumFormat: TsNumberFormat);
|
2014-05-21 12:12:16 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AFormatString, ANumFormat);
|
2014-06-12 22:20:45 +00:00
|
|
|
// nothing to do here. But see, e.g., xlscommon.TsBIFFNumFormatList
|
2014-05-20 16:13:48 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Deletes a format item from the list, and makes sure that its memory is
|
|
|
|
released.
|
2014-05-14 15:24:02 +00:00
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
@param AIndex List index of the item to be deleted. }
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomNumFormatList.Delete(AIndex: Integer);
|
|
|
|
begin
|
|
|
|
RemoveFormat(AIndex);
|
|
|
|
Delete(AIndex);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Seeks a format item with the given properties and returns its list index,
|
|
|
|
or -1 if not found.
|
|
|
|
|
|
|
|
@param ANumFormat Built-in format identifier
|
|
|
|
@param AFormatString String of formatting codes
|
|
|
|
@return Index of the format item in the format list, or -1 if not found. }
|
2014-05-14 15:24:02 +00:00
|
|
|
function TsCustomNumFormatList.Find(ANumFormat: TsNumberFormat;
|
2014-06-12 22:20:45 +00:00
|
|
|
AFormatString: String): Integer;
|
2014-05-14 15:24:02 +00:00
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
2014-06-12 22:20:45 +00:00
|
|
|
begin
|
2014-05-21 16:23:38 +00:00
|
|
|
for Result := Count-1 downto 0 do begin
|
2014-05-14 15:24:02 +00:00
|
|
|
item := Items[Result];
|
2014-06-12 22:20:45 +00:00
|
|
|
if (item <> nil) and (item.NumFormat = ANumFormat) and (item.FormatString = AFormatString)
|
|
|
|
then exit;
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Finds the item with the given format string and returns its index in the
|
|
|
|
format list, or -1 if not found.
|
|
|
|
|
|
|
|
@param AFormatString string of formatting codes to be searched in the list.
|
|
|
|
@return Index of the format item in the format list, or -1 if not found. }
|
2014-05-26 22:27:07 +00:00
|
|
|
function TsCustomNumFormatList.Find(AFormatString: String): integer;
|
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
|
|
|
begin
|
|
|
|
{ We search backwards to find user-defined items first. They usually are
|
|
|
|
more appropriate than built-in items. }
|
|
|
|
for Result := Count-1 downto 0 do begin
|
|
|
|
item := Items[Result];
|
|
|
|
if item.FormatString = AFormatString then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Finds the item with the given Excel format index and returns its index in
|
|
|
|
the format list, or -1 if not found.
|
|
|
|
Is used by BIFF file formats.
|
|
|
|
|
|
|
|
@param AFormatIndex Excel format index to the searched
|
|
|
|
@return Index of the format item in the format list, or -1 if not found. }
|
2014-05-26 22:27:07 +00:00
|
|
|
function TsCustomNumFormatList.FindByIndex(AFormatIndex: Integer): integer;
|
2014-05-14 15:24:02 +00:00
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
|
|
|
begin
|
|
|
|
for Result := 0 to Count-1 do begin
|
|
|
|
item := Items[Result];
|
|
|
|
if item.Index = AFormatIndex then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Finds the item with the given ODS format name and returns its index in
|
|
|
|
the format list (or -1, if not found)
|
|
|
|
To be used by OpenDocument file format.
|
|
|
|
|
|
|
|
@param AFormatName Format name as used by OpenDocument to identify a number format
|
|
|
|
@return Index of the format item in the list, or -1 if not found }
|
2014-05-26 22:27:07 +00:00
|
|
|
function TsCustomNumFormatList.FindByName(AFormatName: String): integer;
|
2014-05-21 12:12:16 +00:00
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
|
|
|
begin
|
2014-05-26 22:27:07 +00:00
|
|
|
for Result := 0 to Count-1 do begin
|
2014-05-21 12:12:16 +00:00
|
|
|
item := Items[Result];
|
2014-05-26 22:27:07 +00:00
|
|
|
if item.Name = AFormatName then
|
2014-05-21 12:12:16 +00:00
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Determines whether the format attributed to the given cell is already
|
|
|
|
contained in the list and returns its list index, or -1 if not found
|
|
|
|
|
|
|
|
@param AFormatCell Pointer to a spreadsheet cell having the number format that is looked for.
|
|
|
|
@return Index of the format item in the list, or -1 if not found. }
|
2014-05-21 23:01:07 +00:00
|
|
|
function TsCustomNumFormatList.FindFormatOf(AFormatCell: PCell): integer;
|
|
|
|
begin
|
|
|
|
if AFormatCell = nil then
|
|
|
|
Result := -1
|
|
|
|
else
|
2014-06-12 22:20:45 +00:00
|
|
|
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr);
|
2014-05-21 23:01:07 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Determines the format string to be written into the spreadsheet file. Calls
|
2014-06-12 22:20:45 +00:00
|
|
|
ConvertBeforeWriting in order to convert the fpc format strings to the dialect
|
2014-06-20 23:06:29 +00:00
|
|
|
used in the file.
|
|
|
|
|
|
|
|
@param AIndex The number format at this item is considered.
|
|
|
|
@return String of formatting codes that will be written to the file. }
|
2014-05-14 15:24:02 +00:00
|
|
|
function TsCustomNumFormatList.FormatStringForWriting(AIndex: Integer): String;
|
|
|
|
var
|
|
|
|
item: TsNumFormatdata;
|
2014-06-12 22:20:45 +00:00
|
|
|
nf: TsNumberFormat;
|
2014-05-14 15:24:02 +00:00
|
|
|
begin
|
|
|
|
item := Items[AIndex];
|
2014-06-12 22:20:45 +00:00
|
|
|
if item <> nil then begin
|
|
|
|
Result := item.FormatString;
|
2014-06-13 13:33:02 +00:00
|
|
|
nf := item.NumFormat;
|
|
|
|
ConvertBeforeWriting(Result, nf);
|
2014-06-12 22:20:45 +00:00
|
|
|
end else
|
|
|
|
Result := '';
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function TsCustomNumFormatList.GetItem(AIndex: Integer): TsNumFormatData;
|
|
|
|
begin
|
|
|
|
Result := TsNumFormatData(inherited Items[AIndex]);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@
|
|
|
|
Deletes the memory occupied by the formatting data, but keeps an empty item in
|
|
|
|
the list to retain the indexes of following items.
|
|
|
|
|
|
|
|
@param AIndex The number format item at this index will be removed. }
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomNumFormatList.RemoveFormat(AIndex: Integer);
|
|
|
|
var
|
|
|
|
item: TsNumFormatData;
|
|
|
|
begin
|
|
|
|
item := GetItem(AIndex);
|
|
|
|
if item <> nil then begin
|
|
|
|
item.Free;
|
|
|
|
SetItem(AIndex, nil);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsCustomNumFormatList.SetItem(AIndex: Integer; AValue: TsNumFormatData);
|
|
|
|
begin
|
|
|
|
inherited Items[AIndex] := AValue;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function CompareNumFormatData(Item1, Item2: Pointer): Integer;
|
|
|
|
begin
|
|
|
|
Result := CompareValue(TsNumFormatData(Item1).Index, TsNumFormatData(Item2).Index);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
{@@ Sorts the format data items in ascending order of the Excel format indexes. }
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomNumFormatList.Sort;
|
|
|
|
begin
|
|
|
|
inherited Sort(@CompareNumFormatData);
|
|
|
|
end;
|
|
|
|
|
2014-06-20 23:06:29 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{ TsCustomSpreadReader }
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Constructor of the reader. Has the workbook to be read as a parameter to
|
|
|
|
apply the localization information found in its FormatSettings.
|
|
|
|
Creates an internal instance of the number format list according to the
|
|
|
|
file format being read.
|
|
|
|
|
|
|
|
@param AWorkbook Workbook into which the file is being read. This parameter
|
|
|
|
is passed from the workbook which creates the reader. }
|
2014-04-23 22:29:32 +00:00
|
|
|
constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook);
|
2012-01-23 13:24:13 +00:00
|
|
|
begin
|
|
|
|
inherited Create;
|
2014-04-23 22:29:32 +00:00
|
|
|
FWorkbook := AWorkbook;
|
2014-05-14 15:24:02 +00:00
|
|
|
CreateNumFormatList;
|
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Destructor of the reader. Destroys the internal number format list. }
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor TsCustomSpreadReader.Destroy;
|
|
|
|
begin
|
|
|
|
FNumFormatList.Free;
|
|
|
|
inherited Destroy;
|
2012-01-23 13:24:13 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
This method creates an instance of the number format list according to the
|
|
|
|
file format being read. The method has to be overridden because the
|
|
|
|
descendants know the special requirements of the file format. }
|
2014-05-15 12:53:56 +00:00
|
|
|
procedure TsCustomSpreadReader.CreateNumFormatList;
|
|
|
|
begin
|
2014-06-23 15:16:30 +00:00
|
|
|
// nothing to do here
|
2014-05-15 12:53:56 +00:00
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
|
|
|
Default file reading method.
|
|
|
|
|
|
|
|
Opens the file and calls ReadFromStream
|
|
|
|
|
|
|
|
@param AFileName The input file name.
|
|
|
|
@param AData The Workbook to be filled with information from the file.
|
|
|
|
@see TsWorkbook
|
|
|
|
}
|
2008-02-24 13:18:34 +00:00
|
|
|
procedure TsCustomSpreadReader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
2009-01-10 21:47:59 +00:00
|
|
|
var
|
|
|
|
InputFile: TFileStream;
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2009-01-10 21:47:59 +00:00
|
|
|
InputFile := TFileStream.Create(AFileName, fmOpenRead);
|
|
|
|
try
|
|
|
|
ReadFromStream(InputFile, AData);
|
|
|
|
finally
|
|
|
|
InputFile.Free;
|
|
|
|
end;
|
|
|
|
end;
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
2014-06-23 15:16:30 +00:00
|
|
|
This routine has the purpose to read the workbook data from the stream.
|
|
|
|
It should be overriden in descendent classes.
|
|
|
|
|
|
|
|
Its basic implementation here assumes that the stream is a TStringStream and
|
|
|
|
the data are provided by calling ReadFromStrings. This mechanism is valid
|
|
|
|
for wikitables.
|
|
|
|
|
|
|
|
@param AStream Stream containing the workbook data
|
|
|
|
@param AData Workbook which is filled by the data from the stream.
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
|
|
|
procedure TsCustomSpreadReader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
|
2013-06-11 14:15:59 +00:00
|
|
|
var
|
|
|
|
AStringStream: TStringStream;
|
|
|
|
AStrings: TStringList;
|
|
|
|
begin
|
|
|
|
AStringStream := TStringStream.Create('');
|
|
|
|
AStrings := TStringList.Create;
|
|
|
|
try
|
|
|
|
AStringStream.CopyFrom(AStream, AStream.Size);
|
|
|
|
AStringStream.Seek(0, soFromBeginning);
|
|
|
|
AStrings.Text := AStringStream.DataString;
|
|
|
|
ReadFromStrings(AStrings, AData);
|
|
|
|
finally
|
|
|
|
AStringStream.Free;
|
|
|
|
AStrings.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Reads workbook data from a string list. This abstract implementation does
|
|
|
|
nothing and raises an exception. Must be overridden, like for wikitables.
|
|
|
|
}
|
2013-06-11 14:15:59 +00:00
|
|
|
procedure TsCustomSpreadReader.ReadFromStrings(AStrings: TStrings;
|
|
|
|
AData: TsWorkbook);
|
2009-01-10 21:47:59 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStrings, AData);
|
2009-01-10 21:47:59 +00:00
|
|
|
raise Exception.Create(lpUnsupportedReadFormat);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{ TsCustomSpreadWriter }
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ Constructor of the writer. Has the workbook to be written as a parameter to
|
|
|
|
apply the localization information found in its FormatSettings.
|
|
|
|
Creates an internal number format list to collect unique samples of all the
|
|
|
|
number formats found in the workbook.
|
|
|
|
|
|
|
|
@param AWorkbook Workbook which is to be written to file/stream.
|
|
|
|
This parameter is passed from the workbook which creates the
|
|
|
|
writer.
|
|
|
|
}
|
2014-04-23 22:29:32 +00:00
|
|
|
constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
|
2012-04-27 08:01:15 +00:00
|
|
|
begin
|
|
|
|
inherited Create;
|
2014-04-23 22:29:32 +00:00
|
|
|
FWorkbook := AWorkbook;
|
2014-05-14 15:24:02 +00:00
|
|
|
CreateNumFormatList;
|
2014-06-13 13:33:02 +00:00
|
|
|
// FNumFormatList.FWorkbook := AWorkbook;
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@ Destructor of the writer. Destroys the internal number format list. }
|
2014-05-14 15:24:02 +00:00
|
|
|
destructor TsCustomSpreadWriter.Destroy;
|
|
|
|
begin
|
|
|
|
FNumFormatList.Free;
|
|
|
|
inherited Destroy;
|
2012-04-27 08:01:15 +00:00
|
|
|
end;
|
|
|
|
|
2011-05-27 13:14:14 +00:00
|
|
|
{@@
|
2014-06-23 15:16:30 +00:00
|
|
|
Checks if the formatting style of a cell is in the list of manually added
|
|
|
|
FFormattingStyles and returns its index, or -1 if it isn't
|
|
|
|
|
|
|
|
@param AFormat Cell containing the formatting styles which are seeked in the
|
|
|
|
FFormattingStyles array.
|
2011-05-27 13:14:14 +00:00
|
|
|
}
|
|
|
|
function TsCustomSpreadWriter.FindFormattingInList(AFormat: PCell): Integer;
|
|
|
|
var
|
2014-06-12 22:20:45 +00:00
|
|
|
i, n: Integer;
|
2014-05-03 17:00:00 +00:00
|
|
|
b: TsCellBorder;
|
|
|
|
equ: Boolean;
|
2011-05-27 13:14:14 +00:00
|
|
|
begin
|
|
|
|
Result := -1;
|
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
n := Length(FFormattingStyles);
|
|
|
|
for i := n - 1 downto 0 do begin
|
2011-05-27 13:14:14 +00:00
|
|
|
if (FFormattingStyles[i].UsedFormattingFields <> AFormat^.UsedFormattingFields) then Continue;
|
|
|
|
|
2014-04-20 20:31:36 +00:00
|
|
|
if uffHorAlign in AFormat^.UsedFormattingFields then
|
|
|
|
if (FFormattingStyles[i].HorAlignment <> AFormat^.HorAlignment) then Continue;
|
|
|
|
|
|
|
|
if uffVertAlign in AFormat^.UsedFormattingFields then
|
|
|
|
if (FFormattingStyles[i].VertAlignment <> AFormat^.VertAlignment) then Continue;
|
|
|
|
|
2011-05-27 13:14:14 +00:00
|
|
|
if uffTextRotation in AFormat^.UsedFormattingFields then
|
|
|
|
if (FFormattingStyles[i].TextRotation <> AFormat^.TextRotation) then Continue;
|
|
|
|
|
2014-05-03 17:00:00 +00:00
|
|
|
if uffBorder in AFormat^.UsedFormattingFields then begin
|
2011-05-27 13:14:14 +00:00
|
|
|
if (FFormattingStyles[i].Border <> AFormat^.Border) then Continue;
|
2014-05-03 17:00:00 +00:00
|
|
|
equ := true;
|
|
|
|
for b in TsCellBorder do begin
|
|
|
|
if FFormattingStyles[i].BorderStyles[b].LineStyle <> AFormat^.BorderStyles[b].LineStyle
|
|
|
|
then begin
|
|
|
|
equ := false;
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
if FFormattingStyles[i].BorderStyles[b].Color <> AFormat^.BorderStyles[b].Color
|
|
|
|
then begin
|
|
|
|
equ := false;
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if not equ then Continue;
|
|
|
|
end;
|
2011-05-27 13:14:14 +00:00
|
|
|
|
|
|
|
if uffBackgroundColor in AFormat^.UsedFormattingFields then
|
|
|
|
if (FFormattingStyles[i].BackgroundColor <> AFormat^.BackgroundColor) then Continue;
|
|
|
|
|
2013-12-22 14:02:04 +00:00
|
|
|
if uffNumberFormat in AFormat^.UsedFormattingFields then begin
|
2013-12-07 13:42:22 +00:00
|
|
|
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
|
2014-06-12 22:20:45 +00:00
|
|
|
if (FFormattingStyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
|
2013-12-22 14:02:04 +00:00
|
|
|
end;
|
2013-12-07 13:42:22 +00:00
|
|
|
|
2014-04-22 23:10:32 +00:00
|
|
|
if uffFont in AFormat^.UsedFormattingFields then
|
|
|
|
if (FFormattingStyles[i].FontIndex <> AFormat^.FontIndex) then Continue;
|
|
|
|
|
2011-05-27 13:14:14 +00:00
|
|
|
// If we arrived here it means that the styles match
|
|
|
|
Exit(i);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
If formatting features of a cell are not supported by the destination file
|
2014-05-14 15:24:02 +00:00
|
|
|
format of the writer, here is the place to apply replacements.
|
2014-06-23 15:16:30 +00:00
|
|
|
Must be overridden by descendants, nothin happens here. See BIFF2.
|
|
|
|
|
|
|
|
@param ACell Pointer to the cell being investigated. Note that this cell
|
|
|
|
does not belong to the workbook, but is a cell of the
|
|
|
|
FFormattingStyles array.
|
|
|
|
}
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
|
2014-05-21 12:12:16 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(ACell);
|
2014-05-21 12:12:16 +00:00
|
|
|
// to be overridden
|
|
|
|
end;
|
2014-05-14 15:24:02 +00:00
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Each descendent should define its own default formats, if any.
|
|
|
|
Always add the normal, unformatted style first to speed things up.
|
|
|
|
|
|
|
|
To be overridden by descendants.
|
|
|
|
}
|
2011-05-27 13:14:14 +00:00
|
|
|
procedure TsCustomSpreadWriter.AddDefaultFormats();
|
|
|
|
begin
|
|
|
|
SetLength(FFormattingStyles, 0);
|
|
|
|
NextXFIndex := 0;
|
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
2014-06-24 16:10:01 +00:00
|
|
|
Creates an instance of the number format list which contains prototypes of
|
2014-06-23 15:16:30 +00:00
|
|
|
all number formats found in the workbook.
|
|
|
|
|
2014-06-24 16:10:01 +00:00
|
|
|
Create a descendant that knows about the details how to write the
|
2014-06-23 15:16:30 +00:00
|
|
|
formats correctly to the destination file. }
|
2014-05-15 12:53:56 +00:00
|
|
|
procedure TsCustomSpreadWriter.CreateNumFormatList;
|
|
|
|
begin
|
2014-06-23 15:16:30 +00:00
|
|
|
// nothing to do here
|
2014-05-15 12:53:56 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
|
|
|
Callback function for collecting all formatting styles found in the worksheet.
|
|
|
|
|
|
|
|
@param ACell Pointer to the worksheet cell being tested whether its format
|
|
|
|
already has been found in the array FFormattingStyles.
|
|
|
|
@param AStream Stream to which the workbook is written
|
|
|
|
}
|
2011-05-27 13:14:14 +00:00
|
|
|
procedure TsCustomSpreadWriter.ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
|
|
|
|
var
|
|
|
|
Len: Integer;
|
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStream);
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
FixFormat(ACell);
|
2011-05-27 13:14:14 +00:00
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
if ACell^.UsedFormattingFields = [] then Exit;
|
2011-05-27 13:14:14 +00:00
|
|
|
if FindFormattingInList(ACell) <> -1 then Exit;
|
|
|
|
|
|
|
|
Len := Length(FFormattingStyles);
|
|
|
|
SetLength(FFormattingStyles, Len+1);
|
|
|
|
FFormattingStyles[Len] := ACell^;
|
2014-05-21 12:12:16 +00:00
|
|
|
|
|
|
|
// 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.
|
2011-05-27 13:14:14 +00:00
|
|
|
FFormattingStyles[Len].Row := NextXFIndex;
|
|
|
|
Inc(NextXFIndex);
|
|
|
|
end;
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
{@@
|
|
|
|
This method collects all formatting styles found in the worksheet and
|
|
|
|
stores unique prototypes in the array FFormattingStyles.
|
|
|
|
}
|
2014-04-23 22:29:32 +00:00
|
|
|
procedure TsCustomSpreadWriter.ListAllFormattingStyles;
|
2011-05-27 13:14:14 +00:00
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
SetLength(FFormattingStyles, 0);
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
// Add default styles which are required to be there by the destination file
|
2011-05-27 13:14:14 +00:00
|
|
|
AddDefaultFormats();
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
// Iterate through all cells and collect the individual styles
|
2014-04-23 22:29:32 +00:00
|
|
|
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
|
|
|
IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllFormattingStylesCallback);
|
2011-05-27 13:14:14 +00:00
|
|
|
end;
|
|
|
|
|
2014-05-14 15:24:02 +00:00
|
|
|
{@@
|
|
|
|
Adds the number format of the given cell to the NumFormatList, but only if
|
|
|
|
it does not yet exist in the list.
|
|
|
|
}
|
|
|
|
procedure TsCustomSpreadWriter.ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
|
2014-05-21 12:12:16 +00:00
|
|
|
var
|
|
|
|
fmt: string;
|
|
|
|
nf: TsNumberFormat;
|
2014-05-14 15:24:02 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStream);
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
if ACell^.NumberFormat = nfGeneral then
|
|
|
|
exit;
|
|
|
|
|
2014-06-12 22:20:45 +00:00
|
|
|
// The builtin format list is in fpc dialect.
|
2014-05-21 12:12:16 +00:00
|
|
|
fmt := ACell^.NumberFormatStr;
|
|
|
|
nf := ACell^.NumberFormat;
|
|
|
|
|
|
|
|
// Seek the format string in the current number format list.
|
|
|
|
// If not found add the format to the list.
|
2014-06-12 22:20:45 +00:00
|
|
|
if FNumFormatList.Find(nf, fmt) = -1 then
|
|
|
|
FNumFormatList.AddFormat(fmt, nf);
|
2014-05-14 15:24:02 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
2014-06-12 22:20:45 +00:00
|
|
|
Iterates through all cells and collects the number formats in
|
2014-05-14 15:24:02 +00:00
|
|
|
FNumFormatList (without duplicates).
|
2014-06-12 22:20:45 +00:00
|
|
|
The index of the list item is needed for the field FormatIndex of the XF record.
|
|
|
|
At the time when the method is called the formats are still in fpc dialect. }
|
2014-05-14 15:24:02 +00:00
|
|
|
procedure TsCustomSpreadWriter.ListAllNumFormats;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
for i:=0 to Workbook.GetWorksheetCount-1 do
|
|
|
|
IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllNumFormatsCallback);
|
|
|
|
NumFormatList.Sort;
|
|
|
|
end;
|
|
|
|
|
2009-02-02 09:58:51 +00:00
|
|
|
{@@
|
|
|
|
Expands a formula, separating it in it's constituent parts,
|
|
|
|
so that it is already partially parsed and it is easier to
|
|
|
|
convert it into the format supported by the writer module
|
|
|
|
}
|
|
|
|
function TsCustomSpreadWriter.ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
|
|
|
|
var
|
|
|
|
StrPos: Integer;
|
|
|
|
ResPos: Integer;
|
|
|
|
begin
|
|
|
|
ResPos := -1;
|
|
|
|
SetLength(Result, 0);
|
|
|
|
|
2014-05-21 12:12:16 +00:00
|
|
|
// The formula needs to start with a "=" character.
|
2009-02-02 09:58:51 +00:00
|
|
|
if AFormula.FormulaStr[1] <> '=' then raise Exception.Create('Formula doesn''t start with =');
|
|
|
|
|
|
|
|
StrPos := 2;
|
|
|
|
|
|
|
|
while Length(AFormula.FormulaStr) <= StrPos do
|
|
|
|
begin
|
|
|
|
// Checks for cell with the format [Letter][Number]
|
|
|
|
{ if (AFormula.FormulaStr[StrPos] in [a..zA..Z]) and
|
|
|
|
(AFormula.FormulaStr[StrPos + 1] in [0..9]) then
|
|
|
|
begin
|
|
|
|
Inc(ResPos);
|
|
|
|
SetLength(Result, ResPos + 1);
|
|
|
|
Result[ResPos].ElementKind := fekCell;
|
|
|
|
// Result[ResPos].Col1 := fekCell;
|
|
|
|
Result[ResPos].Row1 := AFormula.FormulaStr[StrPos + 1];
|
|
|
|
|
|
|
|
Inc(StrPos);
|
|
|
|
end
|
|
|
|
// Checks for arithmetical operations
|
|
|
|
else} if AFormula.FormulaStr[StrPos] = '+' then
|
|
|
|
begin
|
|
|
|
Inc(ResPos);
|
|
|
|
SetLength(Result, ResPos + 1);
|
|
|
|
Result[ResPos].ElementKind := fekAdd;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Inc(StrPos);
|
|
|
|
end;
|
|
|
|
end;
|
2014-05-21 23:01:07 +00:00
|
|
|
|
2008-02-24 13:18:34 +00:00
|
|
|
{@@
|
2014-06-23 15:16:30 +00:00
|
|
|
Helper function for the spreadsheet writers. Writes the cell value to the
|
|
|
|
stream. Calls the WriteNumber method of the worksheet for writing a number,
|
|
|
|
the WriteDateTime method for writing a date/time etc.
|
|
|
|
|
|
|
|
@param ACell Pointer to the worksheet cell being written
|
|
|
|
@param AStream Stream to which data are written
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
@see TsCustomSpreadWriter.WriteCellsToStream
|
|
|
|
}
|
2011-05-25 15:50:18 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteCellCallback(ACell: PCell; AStream: TStream);
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2014-06-28 19:40:28 +00:00
|
|
|
if Length(ACell^.RPNFormulaValue) > 0 then
|
|
|
|
WriteRPNFormula(AStream, ACell^.Row, ACell^.Col, ACell^.RPNFormulaValue, ACell)
|
|
|
|
else
|
2008-02-24 13:18:34 +00:00
|
|
|
case ACell.ContentType of
|
2014-06-28 19:40:28 +00:00
|
|
|
cctEmpty : WriteBlank(AStream, ACell^.Row, ACell^.Col, ACell);
|
|
|
|
cctDateTime : WriteDateTime(AStream, ACell^.Row, ACell^.Col, ACell^.DateTimeValue, ACell);
|
|
|
|
cctNumber : WriteNumber(AStream, ACell^.Row, ACell^.Col, ACell^.NumberValue, ACell);
|
|
|
|
cctUTF8String : WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
|
|
|
|
cctFormula : WriteFormula(AStream, ACell^.Row, ACell^.Col, ACell^.FormulaValue, ACell);
|
|
|
|
// cctRPNFormula: WriteRPNFormula(AStream, ACell^.Row, ACell^.Col, ACell^.RPNFormulaValue, ACell);
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Helper function for the spreadsheet writers.
|
|
|
|
|
|
|
|
Iterates all cells on a list, calling the appropriate write method for them.
|
|
|
|
|
|
|
|
@param AStream The output stream.
|
|
|
|
@param ACells List of cells to be writeen
|
|
|
|
}
|
2009-09-02 22:03:01 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
|
2011-05-25 15:50:18 +00:00
|
|
|
begin
|
|
|
|
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
|
|
|
end;
|
|
|
|
|
2011-05-30 09:22:08 +00:00
|
|
|
{@@
|
|
|
|
A generic method to iterate through all cells in a worksheet and call a callback
|
|
|
|
routine for each cell.
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
@param AStream The output stream, passed to the callback routine.
|
|
|
|
@param ACells List of cells to be iterated
|
|
|
|
@param ACallback Callback routine; it requires as arguments a pointer to the
|
|
|
|
cell as well as the destination stream.
|
2011-05-30 09:22:08 +00:00
|
|
|
}
|
2011-05-25 15:50:18 +00:00
|
|
|
procedure TsCustomSpreadWriter.IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
2009-09-02 22:03:01 +00:00
|
|
|
var
|
|
|
|
AVLNode: TAVLTreeNode;
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2009-09-02 22:03:01 +00:00
|
|
|
AVLNode := ACells.FindLowest;
|
|
|
|
While Assigned(AVLNode) do
|
|
|
|
begin
|
2011-05-25 15:50:18 +00:00
|
|
|
ACallback(PCell(AVLNode.Data), AStream);
|
2009-09-02 22:03:01 +00:00
|
|
|
AVLNode := ACells.FindSuccessor(AVLNode);
|
|
|
|
end;
|
2008-02-24 13:18:34 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Default file writting method.
|
|
|
|
|
|
|
|
Opens the file and calls WriteToStream
|
2014-04-23 22:29:32 +00:00
|
|
|
The workbook written is the one specified in the constructor of the writer.
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
@param AFileName The output file name.
|
|
|
|
@param AOverwriteExisting If the file already exists it will be replaced.
|
2008-02-24 13:18:34 +00:00
|
|
|
|
|
|
|
@see TsWorkbook
|
|
|
|
}
|
2009-11-08 19:21:23 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteToFile(const AFileName: string;
|
2014-04-23 22:29:32 +00:00
|
|
|
const AOverwriteExisting: Boolean = False);
|
2008-02-24 13:18:34 +00:00
|
|
|
var
|
|
|
|
OutputFile: TFileStream;
|
2009-11-08 19:21:23 +00:00
|
|
|
lMode: Word;
|
2008-02-24 13:18:34 +00:00
|
|
|
begin
|
2009-11-08 19:21:23 +00:00
|
|
|
if AOverwriteExisting then lMode := fmCreate or fmOpenWrite
|
|
|
|
else lMode := fmCreate;
|
|
|
|
|
|
|
|
OutputFile := TFileStream.Create(AFileName, lMode);
|
2008-02-24 13:18:34 +00:00
|
|
|
try
|
2014-04-23 22:29:32 +00:00
|
|
|
WriteToStream(OutputFile);
|
2008-02-24 13:18:34 +00:00
|
|
|
finally
|
|
|
|
OutputFile.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-01-10 21:47:59 +00:00
|
|
|
{@@
|
2014-06-23 15:16:30 +00:00
|
|
|
This routine has the purpose to write the workbook to a stream.
|
|
|
|
Present implementation writes to a stringlists by means of WriteToStrings;
|
|
|
|
this behavior is required for wikitables.
|
|
|
|
Must be overriden in descendent classes for all other cases.
|
|
|
|
|
|
|
|
@param AStream Stream to which the workbook is written
|
2009-01-10 21:47:59 +00:00
|
|
|
}
|
2014-04-23 22:29:32 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteToStream(AStream: TStream);
|
2013-06-11 14:15:59 +00:00
|
|
|
var
|
|
|
|
lStringList: TStringList;
|
2009-01-10 21:47:59 +00:00
|
|
|
begin
|
2013-06-11 14:15:59 +00:00
|
|
|
lStringList := TStringList.Create;
|
|
|
|
try
|
2014-04-23 22:29:32 +00:00
|
|
|
WriteToStrings(lStringList);
|
2013-06-11 14:15:59 +00:00
|
|
|
lStringList.SaveToStream(AStream);
|
|
|
|
finally
|
|
|
|
lStringList.Free;
|
|
|
|
end;
|
|
|
|
end;
|
2009-01-10 21:47:59 +00:00
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Writes the worksheet to a list of strings. Not implemented here, needs to
|
|
|
|
be overridden by descendants. See wikitables.
|
|
|
|
}
|
2014-04-23 22:29:32 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteToStrings(AStrings: TStrings);
|
2013-06-11 14:15:59 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStrings);
|
2013-06-11 14:15:59 +00:00
|
|
|
raise Exception.Create(lpUnsupportedWriteFormat);
|
2009-01-10 21:47:59 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Basic method which is called when writing a string formula to a stream.
|
|
|
|
Present implementation does nothing. Needs to be overridden by descendants.
|
|
|
|
|
|
|
|
@param AStream Stream to be written
|
|
|
|
@param ARow Row index of the cell containing the formula
|
|
|
|
@param ACol Column index of the cell containing the formula
|
|
|
|
@param AFormula String formula given as an Excel-like string, such as '=A1+B1'
|
|
|
|
@param ACell Pointer to the cell containing the formula and being written
|
|
|
|
to the stream
|
|
|
|
}
|
2009-06-09 11:19:10 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteFormula(AStream: TStream; const ARow,
|
2013-12-07 13:42:22 +00:00
|
|
|
ACol: Cardinal; const AFormula: TsFormula; ACell: PCell);
|
2009-06-09 11:19:10 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStream, ARow, ACol);
|
|
|
|
Unused(AFormula, ACell);
|
2013-12-07 13:42:22 +00:00
|
|
|
// Silently dump the formula; child classes should implement their own support
|
2009-06-09 11:19:10 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{@@
|
|
|
|
Basic method which is called when writing an RPN formula to a stream.
|
|
|
|
Present implementation does nothing. Needs to be overridden by descendants.
|
|
|
|
|
|
|
|
RPN formula are used by the BIFF file format.
|
|
|
|
|
|
|
|
@param AStream Stream to be written
|
|
|
|
@param ARow Row index of the cell containing the formula
|
|
|
|
@param ACol Column index of the cell containing the formula
|
|
|
|
@param AFormula RPN formula given as an array of RPN tokens
|
|
|
|
@param ACell Pointer to the cell containing the formula and being written
|
|
|
|
to the stream
|
|
|
|
}
|
2009-06-09 11:19:10 +00:00
|
|
|
procedure TsCustomSpreadWriter.WriteRPNFormula(AStream: TStream; const ARow,
|
2013-12-07 13:42:22 +00:00
|
|
|
ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell);
|
2009-06-09 11:19:10 +00:00
|
|
|
begin
|
2014-06-20 15:58:22 +00:00
|
|
|
Unused(AStream, ARow, ACol);
|
|
|
|
Unused(AFormula, ACell);
|
2013-12-07 13:42:22 +00:00
|
|
|
// Silently dump the formula; child classes should implement their own support
|
2009-06-09 11:19:10 +00:00
|
|
|
end;
|
|
|
|
|
2013-12-22 14:02:04 +00:00
|
|
|
|
2014-06-23 15:16:30 +00:00
|
|
|
{******************************************************************************}
|
|
|
|
{ Simplified creation of RPN formulas }
|
|
|
|
{******************************************************************************}
|
2014-04-08 09:48:30 +00:00
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Creates a pointer to a new RPN item. This represents an element in the array
|
|
|
|
of token of an RPN formula.
|
|
|
|
|
|
|
|
@return Pointer the the RPN item
|
|
|
|
}
|
2014-04-08 09:48:30 +00:00
|
|
|
function NewRPNItem: PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := GetMem(SizeOf(TRPNItem));
|
|
|
|
FillChar(Result^.FE, SizeOf(Result^.FE), 0);
|
|
|
|
Result^.FE.StringValue := '';
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Destroys an RPN item
|
|
|
|
}
|
2014-04-08 09:48:30 +00:00
|
|
|
procedure DisposeRPNItem(AItem: PRPNItem);
|
|
|
|
begin
|
|
|
|
if AItem <> nil then
|
|
|
|
FreeMem(AItem, SizeOf(TRPNItem));
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates a boolean value entry in the RPN array.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AValue Boolean value to be stored in the RPN item
|
|
|
|
@next ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNBool(AValue: Boolean; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekBool;
|
|
|
|
if AValue then Result^.FE.DoubleValue := 1.0 else Result^.FE.DoubleValue := 0.0;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a cell value, specifed by its
|
|
|
|
address, e.g. 'A1'. Takes care of absolute and relative cell addresses.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ACellAddress Adress of the cell given in Excel A1 notation
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellValue(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
|
|
|
var
|
|
|
|
r,c: Integer;
|
|
|
|
flags: TsRelFlags;
|
|
|
|
begin
|
|
|
|
if not ParseCellString(ACellAddress, r, c, flags) then
|
|
|
|
raise Exception.CreateFmt('"%s" is not a valid cell address.', [ACellAddress]);
|
|
|
|
Result := RPNCellValue(r,c, flags, ANext);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a cell value, specifed by its
|
|
|
|
row and column index and a flag containing information on relative addresses.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param AFlags Flags specifying absolute or relative cell addresses
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellValue(ARow, ACol: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekCell;
|
|
|
|
Result^.FE.Row := ARow;
|
|
|
|
Result^.FE.Col := ACol;
|
|
|
|
Result^.FE.RelFlags := AFlags;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a cell reference, specifed by its
|
|
|
|
address, e.g. 'A1'. Takes care of absolute and relative cell addresses.
|
|
|
|
"Cell reference" means that all properties of the cell can be handled.
|
|
|
|
Note that most Excel formulas with cells require the cell value only
|
|
|
|
(--> RPNCellValue)
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ACellAddress Adress of the cell given in Excel A1 notation
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellRef(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
|
|
|
var
|
|
|
|
r,c: Integer;
|
|
|
|
flags: TsRelFlags;
|
|
|
|
begin
|
|
|
|
if not ParseCellString(ACellAddress, r, c, flags) then
|
2014-05-24 19:44:40 +00:00
|
|
|
raise Exception.CreateFmt(lpNoValidCellAddress, [ACellAddress]);
|
2014-04-08 09:48:30 +00:00
|
|
|
Result := RPNCellRef(r,c, flags, ANext);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a cell reference, specifed by its
|
|
|
|
row and column index and flags containing information on relative addresses.
|
|
|
|
"Cell reference" means that all properties of the cell can be handled.
|
|
|
|
Note that most Excel formulas with cells require the cell value only
|
|
|
|
(--> RPNCellValue)
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ARow Row index of the cell
|
|
|
|
@param ACol Column index of the cell
|
|
|
|
@param AFlags Flags specifying absolute or relative cell addresses
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellRef(ARow, ACol: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekCellRef;
|
|
|
|
Result^.FE.Row := ARow;
|
|
|
|
Result^.FE.Col := ACol;
|
|
|
|
Result^.FE.RelFlags := AFlags;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a range of cells, specified by an
|
|
|
|
Excel-style address, e.g. A1:G5. As in Excel, use a $ sign to indicate
|
|
|
|
absolute addresses.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ACellRangeAddress Adress of the cell range given in Excel notation, such as A1:G5
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellRange(ACellRangeAddress: String; ANext: PRPNItem): PRPNItem;
|
|
|
|
var
|
|
|
|
r1,c1, r2,c2: Integer;
|
|
|
|
flags: TsRelFlags;
|
|
|
|
begin
|
|
|
|
if not ParseCellRangeString(ACellRangeAddress, r1,c1, r2,c2, flags) then
|
2014-05-24 19:44:40 +00:00
|
|
|
raise Exception.CreateFmt(lpNoValidCellRangeAddress, [ACellRangeAddress]);
|
2014-04-08 09:48:30 +00:00
|
|
|
Result := RPNCellRange(r1,c1, r2,c2, flags, ANext);
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a range of cells, specified by the
|
|
|
|
row/column indexes of the top/left and bottom/right corners of the block.
|
|
|
|
The flags indicate relative indexes.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ARow Row index of the top/left cell
|
|
|
|
@param ACol Column index of the top/left cell
|
|
|
|
@param ARow2 Row index of the bottom/right cell
|
|
|
|
@param ACol2 Column index of the bottom/right cell
|
|
|
|
@param AFlags Flags specifying absolute or relative cell addresses
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNCellRange(ARow, ACol, ARow2, ACol2: Integer; AFlags: TsRelFlags;
|
|
|
|
ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekCellRange;
|
|
|
|
Result^.FE.Row := ARow;
|
|
|
|
Result^.FE.Col := ACol;
|
|
|
|
Result^.FE.Row2 := ARow2;
|
|
|
|
Result^.FE.Col2 := ACol2;
|
|
|
|
Result^.FE.RelFlags := AFlags;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
2014-05-23 13:16:01 +00:00
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array with an error value.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AErrCode Error code to be inserted (see TsErrorValue
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
|
|
|
@see TsErrorValue
|
2014-05-23 13:16:01 +00:00
|
|
|
}
|
|
|
|
function RPNErr(AErrCode: Byte; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekErr;
|
|
|
|
Result^.FE.IntValue := AErrCode;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a 2-byte unsigned integer
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AValue Integer value to be inserted into the formula
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-05-23 13:16:01 +00:00
|
|
|
}
|
|
|
|
function RPNInteger(AValue: Word; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekInteger;
|
|
|
|
Result^.FE.IntValue := AValue;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
2014-04-08 09:48:30 +00:00
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a missing argument in of function call.
|
2014-06-21 20:25:01 +00:00
|
|
|
Use this in a formula to indicate a missing argument
|
|
|
|
|
|
|
|
@param ANext Pointer to the next RPN item in the list.
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNMissingArg(ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekMissingArg;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a number. Integers and floating-point
|
|
|
|
values can be used likewise.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AValue Number value to be inserted into the formula
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNNumber(AValue: Double; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekNum;
|
|
|
|
Result^.FE.DoubleValue := AValue;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
2014-05-23 23:13:49 +00:00
|
|
|
{@@
|
2014-06-21 20:25:01 +00:00
|
|
|
Creates an entry in the RPN array which puts the current operator in parenthesis.
|
2014-05-23 23:13:49 +00:00
|
|
|
For display purposes only, does not affect calculation.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-05-23 23:13:49 +00:00
|
|
|
}
|
|
|
|
function RPNParenthesis(ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekParen;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
2014-04-08 09:48:30 +00:00
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for a string.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AValue String to be inserted into the formula
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNString(AValue: String; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := fekString;
|
|
|
|
Result^.FE.StringValue := AValue;
|
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for an Excel function or operation
|
|
|
|
specified by its TokenID (--> TFEKind). Note that array elements for all
|
|
|
|
needed parameters must have been created before.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AToken Formula element indicating the function to be executed,
|
2014-06-23 21:49:20 +00:00
|
|
|
see the TFEKind enumeration for possible values.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ANext Pointer to the next RPN item in the list
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
@see TFEKind
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNFunc(AToken: TFEKind; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
2014-05-24 17:11:05 +00:00
|
|
|
if FEProps[AToken].MinParams <> FEProps[AToken].MaxParams then
|
|
|
|
raise Exception.CreateFmt(lpSpecifyNumberOfParams, [FEProps[AToken].Symbol]);
|
2014-05-23 23:13:49 +00:00
|
|
|
|
2014-05-24 17:11:05 +00:00
|
|
|
Result := RPNFunc(AToken, FEProps[AToken].MinParams, ANext);
|
2014-04-08 09:48:30 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an entry in the RPN array for an Excel function or operation
|
|
|
|
specified by its TokenID (--> TFEKind). Specify the number of parameters used.
|
|
|
|
They must have been created before.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AToken Formula element indicating the function to be executed,
|
2014-06-23 21:49:20 +00:00
|
|
|
see the TFEKind enumeration for possible values.
|
2014-06-21 20:25:01 +00:00
|
|
|
@param ANumParams Number of arguments used in the formula
|
|
|
|
@param ANext Pointer to the next RPN item in the list
|
|
|
|
|
2014-06-23 21:49:20 +00:00
|
|
|
@see TFEKind
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function RPNFunc(AToken: TFEKind; ANumParams: Byte; ANext: PRPNItem): PRPNItem;
|
|
|
|
begin
|
2014-05-24 17:11:05 +00:00
|
|
|
if ord(AToken) < ord(fekAdd) then
|
|
|
|
raise Exception.Create('No basic tokens allowed here.');
|
|
|
|
|
|
|
|
if (ANumParams < FEProps[AToken].MinParams) or (ANumParams > FEProps[AToken].MaxParams) then
|
|
|
|
raise Exception.CreateFmt(lpIncorrectParamCount, [
|
|
|
|
FEProps[AToken].Symbol, FEProps[AToken].MinParams, FEProps[AToken].MaxParams
|
|
|
|
]);
|
|
|
|
|
|
|
|
Result := NewRPNItem;
|
|
|
|
Result^.FE.ElementKind := AToken;
|
2014-04-08 09:48:30 +00:00
|
|
|
Result^.FE.ParamsNum := ANumParams;
|
2014-05-24 17:11:05 +00:00
|
|
|
Result^.Next := ANext;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Returns if the function defined by the token requires a fixed number of parameter.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
@param AElementKind Identifier of the formula function considered
|
2014-05-24 17:11:05 +00:00
|
|
|
}
|
|
|
|
function FixedParamCount(AElementKind: TFEKind): Boolean;
|
|
|
|
begin
|
|
|
|
Result := (FEProps[AElementKind].MinParams = FEProps[AElementKind].MaxParams)
|
|
|
|
and (FEProps[AElementKind].MinParams >= 0);
|
2014-04-08 09:48:30 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Creates an RPN formula by a single call using nested RPN items.
|
2014-06-21 20:25:01 +00:00
|
|
|
|
|
|
|
For each formula element, use one of the RPNxxxx functions implemented here.
|
|
|
|
They are designed to be nested into each other. Terminate the chain by using nil.
|
|
|
|
|
|
|
|
@param AItem Pointer to the first RPN item representing the formula.
|
|
|
|
Each item contains a pointer to the next item in the list.
|
|
|
|
The list is terminated by nil.
|
|
|
|
|
|
|
|
@example
|
|
|
|
The RPN formula for the string expression "$A1+2" can be created as follows:
|
|
|
|
<pre>
|
|
|
|
var
|
|
|
|
f: TsRPNFormula;
|
|
|
|
begin
|
|
|
|
f := CreateRPNFormula(
|
|
|
|
RPNCellValue('$A1',
|
|
|
|
RPNNumber(2,
|
|
|
|
RPNFunc(fekAdd,
|
|
|
|
nil))));
|
|
|
|
</pre>
|
2014-04-08 09:48:30 +00:00
|
|
|
}
|
|
|
|
function CreateRPNFormula(AItem: PRPNItem): TsRPNFormula;
|
|
|
|
var
|
|
|
|
item: PRPNItem;
|
|
|
|
nextitem: PRPNItem;
|
|
|
|
n: Integer;
|
|
|
|
begin
|
|
|
|
// Determine count of RPN elements
|
|
|
|
n := 0;
|
|
|
|
item := AItem;
|
|
|
|
while item <> nil do begin
|
|
|
|
inc(n);
|
|
|
|
item := item^.Next;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Set array length of TsRPNFormula result
|
|
|
|
SetLength(Result, n);
|
|
|
|
|
|
|
|
// Copy FormulaElements to result and free temporary RPNItems
|
|
|
|
item := AItem;
|
|
|
|
n := 0;
|
|
|
|
while item <> nil do begin
|
|
|
|
nextitem := item^.Next;
|
|
|
|
Result[n] := item^.FE;
|
|
|
|
inc(n);
|
|
|
|
DisposeRPNItem(item);
|
|
|
|
item := nextitem;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-21 20:25:01 +00:00
|
|
|
{@@
|
|
|
|
Destroys the RPN formula starting with the given RPN item.
|
|
|
|
|
|
|
|
@param AItem Pointer to the first RPN items representing the formula.
|
|
|
|
Each item contains a pointer to the next item in the list.
|
|
|
|
The list is terminated by nil.
|
|
|
|
}
|
2014-05-23 13:16:01 +00:00
|
|
|
procedure DestroyRPNFormula(AItem: PRPNItem);
|
|
|
|
var
|
|
|
|
nextitem: PRPNItem;
|
|
|
|
begin
|
|
|
|
while AItem <> nil do begin
|
|
|
|
nextitem := AItem^.Next;
|
|
|
|
DisposeRPNItem(AItem);
|
|
|
|
AItem := nextitem;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-05-24 17:11:05 +00:00
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
initialization
|
|
|
|
MakeLEPalette(@DEFAULT_PALETTE, Length(DEFAULT_PALETTE));
|
2008-02-24 13:18:34 +00:00
|
|
|
|
2014-04-24 21:27:57 +00:00
|
|
|
finalization
|
2008-02-24 13:18:34 +00:00
|
|
|
SetLength(GsSpreadFormats, 0);
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
2014-05-21 23:01:07 +00:00
|
|
|
{ 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.
|
|
|
|
|
|
|
|
- For writing, the writer creates a TsNumFormatList which stores all formats
|
|
|
|
in file syntax.
|
2014-06-13 20:32:58 +00:00
|
|
|
- The built-in formats of the file types are coded in the fpc syntax.
|
2014-05-21 23:01:07 +00:00
|
|
|
- The method "ConvertBeforeWriting" converts the cell formats from the
|
|
|
|
fpspreadsheet to the file syntax.
|
|
|
|
|
|
|
|
- For reading, the reader creates another TsNumFormatList.
|
2014-06-13 20:32:58 +00:00
|
|
|
- The built-in formats of the file types are coded again in fpc syntax.
|
|
|
|
- After reading, the formats are converted to fpc syntax by means of
|
|
|
|
"ConvertAfterReading".
|
|
|
|
|
|
|
|
- Format conversion is done internally by means of the TsNumFormatParser.
|
2014-05-21 23:01:07 +00:00
|
|
|
}
|
|
|
|
|