fpspreadsheet: add support for writing currency formats to ods files. Fix "red" option for negative numbers.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3186 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-06-17 09:06:34 +00:00
parent 0b809fbbfd
commit 1e5fa19f94
6 changed files with 248 additions and 30 deletions

View File

@ -44,6 +44,9 @@ begin
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet1); MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet1);
MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines]; MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines];
number := 10000;
(*
{ {
MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes]; MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
myWorksheet.LeftPaneWidth := 1; myWorksheet.LeftPaneWidth := 1;
@ -307,12 +310,12 @@ begin
MyWorksheet.WriteCurrency(r, 1, number, nfCurrency, 0, 'USD'); MyWorksheet.WriteCurrency(r, 1, number, nfCurrency, 0, 'USD');
MyWorksheet.WriteCurrency(r, 2, -number, nfCurrency, 0, 'USD'); MyWorksheet.WriteCurrency(r, 2, -number, nfCurrency, 0, 'USD');
MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrency, 0, 'USD'); MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrency, 0, 'USD');
inc(r); inc(r); *)
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs'); MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs');
MyWorksheet.WriteCurrency(r, 1, number, nfCurrencyRed, 0, 'USD'); MyWorksheet.WriteCurrency(r, 1, number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteCurrency(r, 2, -number, nfCurrencyRed, 0, 'USD'); MyWorksheet.WriteCurrency(r, 2, -number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrencyRed, 0, 'USD'); MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrencyRed, 0, 'USD');
inc(r); inc(r); (*
MyWorksheet.WriteUTF8Text(r, 0, 'nfAccounting, 0 decs'); MyWorksheet.WriteUTF8Text(r, 0, 'nfAccounting, 0 decs');
MyWorksheet.WriteCurrency(r, 1, number, nfAccounting, 0, 'USD'); MyWorksheet.WriteCurrency(r, 1, number, nfAccounting, 0, 'USD');
MyWorksheet.WriteCurrency(r, 2, -number, nfAccounting, 0, 'USD'); MyWorksheet.WriteCurrency(r, 2, -number, nfAccounting, 0, 'USD');
@ -413,7 +416,7 @@ begin
MyWorksheet.WriteUTF8Text(0, 3, Str_Fourth); MyWorksheet.WriteUTF8Text(0, 3, Str_Fourth);
MyWorksheet.WriteTextRotation(0, 0, rt90DegreeClockwiseRotation); MyWorksheet.WriteTextRotation(0, 0, rt90DegreeClockwiseRotation);
MyWorksheet.WriteUsedFormatting(0, 1, [uffBold]); MyWorksheet.WriteUsedFormatting(0, 1, [uffBold]);
*)
// Save the spreadsheet to a file // Save the spreadsheet to a file
MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8, true); MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8, true);
MyWorkbook.Free; MyWorkbook.Free;

View File

@ -36,7 +36,7 @@ begin
MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet'); MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
// Write some cells // Write some cells
MyWorksheet.WriteNumber(0, 0, 1.0);// A1 //MyWorksheet.WriteNumber(0, 0, 1.0);// A1
MyWorksheet.WriteNumber(0, 1, 2.0);// B1 MyWorksheet.WriteNumber(0, 1, 2.0);// B1
MyWorksheet.WriteNumber(0, 2, 3.0);// C1 MyWorksheet.WriteNumber(0, 2, 3.0);// C1
MyWorksheet.WriteNumber(0, 3, 4.0);// D1 MyWorksheet.WriteNumber(0, 3, 4.0);// D1
@ -191,6 +191,26 @@ begin
MyWorksheet.WriteNumber(row, 6, number6, nfSci, 2); MyWorksheet.WriteNumber(row, 6, number6, nfSci, 2);
MyWorksheet.WriteNumber(row, 7, number7, nfSci, 2); MyWorksheet.WriteNumber(row, 7, number7, nfSci, 2);
MyWorksheet.WriteNumber(row, 8, number8, nfSci, 2); MyWorksheet.WriteNumber(row, 8, number8, nfSci, 2);
inc(row);
MyWorksheet.WriteUTF8Text(row, 0, 'nfCurrency, 2 decimals');
MyWorksheet.WriteCurrency(row, 1, number1, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 2, number2, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 3, number3, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 4, number4, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 5, number5, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 6, number6, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 7, number7, nfCurrency, 2, '$');
MyWorksheet.WriteCurrency(row, 8, number8, nfCurrency, 2, '$');
inc(row);
MyWorksheet.WriteUTF8Text(row, 0, 'nfCurrencyRed, 2 decimals, +:$ 1000, -:($ 1000)');
MyWorksheet.WriteCurrency(row, 1, number1, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 2, number2, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 3, number3, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 4, number4, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 5, number5, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 6, number6, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 7, number7, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
MyWorksheet.WriteCurrency(row, 8, number8, nfCurrencyRed, 2, '$', pcfCSV, ncfBCSVB);
// Creates a new worksheet // Creates a new worksheet
MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2'); MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');

View File

@ -73,6 +73,7 @@ type
FStart: PChar; FStart: PChar;
FEnd: PChar; FEnd: PChar;
FCurrSection: Integer; FCurrSection: Integer;
FHasRedSection: Boolean;
FStatus: Integer; FStatus: Integer;
function GetCurrencySymbol: String; function GetCurrencySymbol: String;
function GetDecimals: byte; function GetDecimals: byte;
@ -126,13 +127,13 @@ type
// NumberFormat // NumberFormat
procedure EvalNumFormatOfSection(ASection: Integer; out ANumFormat: TsNumberFormat; procedure EvalNumFormatOfSection(ASection: Integer; out ANumFormat: TsNumberFormat;
out ADecimals: byte; out ACurrencySymbol: String; out AColor: TsColor); out ADecimals: byte; out ACurrencySymbol: String; out AColor: TsColor);
function IsCurrencyAt(ASection, AIndex: Integer; out ANumFormat: TsNumberFormat; function IsCurrencyAt(ASection: Integer; out ANumFormat: TsNumberFormat;
out ADecimals: byte; out ACurrencySymbol: String; out AColor: TsColor): Boolean; out ADecimals: byte; out ACurrencySymbol: String; out AColor: TsColor): Boolean;
function IsDateAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat; function IsDateAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat;
var ANextIndex: Integer): Boolean; var ANextIndex: Integer): Boolean;
function IsNumberAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat; function IsNumberAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat;
var ADecimals: Byte; var ANextIndex: Integer): Boolean; var ADecimals: Byte; var ANextIndex: Integer): Boolean;
function IsSciAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat; function IsSciAt(ASection, AIndex: Integer; var ANumberFormat: TsNumberFormat;
var ADecimals: Byte; var ANextIndex: Integer): Boolean; var ADecimals: Byte; var ANextIndex: Integer): Boolean;
function IsTextAt(AText: string; ASection, AIndex: Integer): Boolean; function IsTextAt(AText: string; ASection, AIndex: Integer): Boolean;
function IsTimeAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat; function IsTimeAt(ASection,AIndex: Integer; var ANumberFormat: TsNumberFormat;
@ -140,8 +141,10 @@ type
function IsTokenAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Boolean; function IsTokenAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Boolean;
public public
constructor Create(AWorkbook: TsWorkbook; const AFormatString: String); constructor Create(AWorkbook: TsWorkbook; const AFormatString: String;
const ANumFormat: TsNumberFormat = nfGeneral);
destructor Destroy; override; destructor Destroy; override;
procedure ClearAll;
function GetDateTimeCode(ASection: Integer): String; function GetDateTimeCode(ASection: Integer): String;
function IsDateTimeFormat: Boolean; function IsDateTimeFormat: Boolean;
procedure LimitDecimals; procedure LimitDecimals;
@ -170,19 +173,24 @@ const
{ TsNumFormatParser } { TsNumFormatParser }
{ Creates a number format parser for analyzing a formatstring that has been read { Creates a number format parser for analyzing a formatstring that has been read
from a spreadsheet file. } from a spreadsheet file.
In case of "red" number formats we also have to specify the number format
because the format string might not contain the color information, and we
extract it from the NumFormat in this case. }
constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook; constructor TsNumFormatParser.Create(AWorkbook: TsWorkbook;
const AFormatString: String); const AFormatString: String; const ANumFormat: TsNumberFormat = nfGeneral);
begin begin
inherited Create; inherited Create;
FCreateMethod := 0; FCreateMethod := 0;
FWorkbook := AWorkbook; FWorkbook := AWorkbook;
FHasRedSection := (ANumFormat in [nfCurrencyRed, nfAccountingRed]);
Parse(AFormatString); Parse(AFormatString);
end; end;
destructor TsNumFormatParser.Destroy; destructor TsNumFormatParser.Destroy;
begin begin
FSections := nil; FSections := nil;
// ClearAll;
inherited Destroy; inherited Destroy;
end; end;
@ -295,8 +303,10 @@ function TsNumFormatParser.BuildFormatStringFromSection(ASection: Integer;
var var
element: TsNumFormatElement; element: TsNumFormatElement;
i: Integer; i: Integer;
colorAdded: Boolean;
begin begin
Result := ''; Result := '';
colorAdded := false;
if (ASection < 0) and (ASection >= GetParsedSectionCount) then if (ASection < 0) and (ASection >= GetParsedSectionCount) then
exit; exit;
@ -354,7 +364,7 @@ begin
nftRepeat: nftRepeat:
if element.TextValue <> '' then Result := Result + '*' + element.TextValue; if element.TextValue <> '' then Result := Result + '*' + element.TextValue;
nftColor: nftColor:
if ADialect = nfdExcel then if ADialect = nfdExcel then begin
case element.IntValue of case element.IntValue of
scBlack : Result := '[black]'; scBlack : Result := '[black]';
scWhite : Result := '[white]'; scWhite : Result := '[white]';
@ -366,8 +376,17 @@ begin
scCyan : Result := '[cyan]'; scCyan : Result := '[cyan]';
else Result := Format('[Color%d]', [element.IntValue]); else Result := Format('[Color%d]', [element.IntValue]);
end; end;
colorAdded := true;
end; end;
end; end;
end;
{
if (ADialect = nfdExcel)
and (not colorAdded) and
(FSections[ASection].NumFormat in [nfCurrencyRed, nfAccountingRed])
then
Result := '[red]'+Result;
}
end; end;
procedure TsNumFormatParser.CheckSections; procedure TsNumFormatParser.CheckSections;
@ -459,6 +478,20 @@ begin
); );
end; end;
procedure TsNumFormatParser.ClearAll;
var
i, j: Integer;
begin
for i:=0 to Length(FSections)-1 do begin
for j:=0 to Length(FSections[i].Elements) do
if FSections[i].Elements <> nil then
FSections[i].Elements[j].TextValue := '';
FSections[i].Elements := nil;
FSections[i].CurrencySymbol := '';
end;
FSections := nil;
end;
procedure TsNumFormatParser.DeleteElement(ASection, AIndex: Integer); procedure TsNumFormatParser.DeleteElement(ASection, AIndex: Integer);
var var
i, n: Integer; i, n: Integer;
@ -562,15 +595,16 @@ begin
exit; exit;
end; end;
end; end;
// nfCurrency
if IsCurrencyAt(ASection, 0, ANumFormat, ADecimals, ACurrencySymbol, AColor)
then exit;
end; end;
// Look for scientific format // Look for scientific format
if IsSciAt(ASection, 0, ANumFormat, ADecimals, next) then if IsSciAt(ASection, 0, ANumFormat, ADecimals, next) then
exit; exit;
// Currency?
if IsCurrencyAt(ASection, ANumFormat, ADecimals, ACurrencySymbol, AColor)
then exit;
// Look for date formats // Look for date formats
if IsDateAt(ASection, 0, ANumFormat, next) then begin if IsDateAt(ASection, 0, ANumFormat, next) then begin
if (next = Length(Elements)) then if (next = Length(Elements)) then
@ -658,11 +692,14 @@ begin
Result := FSections[0].NumFormat; Result := FSections[0].NumFormat;
if (Result in [nfCurrency, nfAccounting]) then begin if (Result in [nfCurrency, nfAccounting]) then begin
if Length(FSections) = 2 then begin if Length(FSections) = 2 then begin
Result := FSections[1].NumFormat;
if FSections[1].CurrencySymbol <> FSections[0].CurrencySymbol then begin if FSections[1].CurrencySymbol <> FSections[0].CurrencySymbol then begin
Result := nfCustom; Result := nfCustom;
exit; exit;
end; end;
if (FSections[0].NumFormat = nfCurrency) and (FSections[1].NumFormat = nfCurrency) then if (FSections[0].NumFormat in [nfCurrency, nfCurrencyRed]) and
(FSections[1].NumFormat in [nfCurrency, nfCurrencyRed])
then
exit; exit;
if FSections[1].NumFormat = nfAccounting then begin if FSections[1].NumFormat = nfAccounting then begin
Result := nfAccounting; Result := nfAccounting;
@ -670,14 +707,16 @@ begin
end; end;
end else end else
if Length(FSections) = 3 then begin if Length(FSections) = 3 then begin
Result := FSections[1].NumFormat;
if (FSections[0].CurrencySymbol <> FSections[1].CurrencySymbol) or if (FSections[0].CurrencySymbol <> FSections[1].CurrencySymbol) or
(FSections[1].CurrencySymbol <> FSections[2].CurrencySymbol) (FSections[1].CurrencySymbol <> FSections[2].CurrencySymbol)
then begin then begin
Result := nfCustom; Result := nfCustom;
exit; exit;
end; end;
if (FSections[0].NumFormat = nfCurrency) and (FSections[1].NumFormat = nfCurrency) and if (FSections[0].NumFormat in [nfCurrency, nfCurrencyRed]) and
(FSections[2].NumFormat = nfCurrency) (FSections[1].NumFormat in [nfCurrency, nfCurrencyRed]) and
(FSections[2].NumFormat in [nfCurrency, nfCurrencyRed])
then then
exit; exit;
if (FSections[1].NumFormat = nfAccounting) and if (FSections[1].NumFormat = nfAccounting) and
@ -709,13 +748,15 @@ end;
the numberformat code, the count of decimals, the currency sambol, and the the numberformat code, the count of decimals, the currency sambol, and the
color. color.
Note that the check is not very exact, but should cover most cases. } Note that the check is not very exact, but should cover most cases. }
function TsNumFormatParser.IsCurrencyAt(ASection, AIndex: Integer; function TsNumFormatParser.IsCurrencyAt(ASection: Integer;
out ANumFormat: TsNumberFormat; out ADecimals: byte; out ANumFormat: TsNumberFormat; out ADecimals: byte;
out ACurrencySymbol: String; out AColor: TsColor): Boolean; out ACurrencySymbol: String; out AColor: TsColor): Boolean;
var var
isAccounting : Boolean; isAccounting : Boolean;
hasCurrSymbol: Boolean; hasCurrSymbol: Boolean;
hasColor: Boolean;
next: Integer; next: Integer;
el: Integer;
begin begin
Result := false; Result := false;
@ -723,7 +764,75 @@ begin
ACurrencySymbol := ''; ACurrencySymbol := '';
ADecimals := 0; ADecimals := 0;
AColor := scNotDefined; AColor := scNotDefined;
isAccounting := false;
hasColor := false;
// Looking for the currency symbol: it is the unique identifier of the
// currency format.
for el := 0 to High(FSections[ASection].Elements) do
if FSections[ASection].Elements[el].Token = nftCurrSymbol then begin
Result := true;
break;
end;
if not Result then
exit;
{ When the format string comes from fpc it does not contain a color token.
Color would be lost when saving. Therefore, we take the color from the
knowledge of the NumFormat passed on creation: nfCurrencyRed has color red
in the second section! }
if (ASection = 1) and FHasRedSection then
AColor := scRed;
// Now that we know that it is a currency format analyze the elements again
// and determine color, decimals and currency symbol.
el := 0;
while (el < Length(FSections[ASection].Elements)) do begin
case FSections[ASection].Elements[el].Token of
nftColor:
begin
AColor := FSections[ASection].Elements[el].IntValue;
hasColor := true;
end;
nftRepeat:
isAccounting := true;
nftCurrSymbol:
ACurrencySymbol := FSections[ASection].Elements[el].TextValue;
nftOptDigit:
if IsNumberAt(ASection, el, ANumFormat, ADecimals, el) then
dec(el)
else begin
Result := false;
exit;
end;
nftDigit:
if IsNumberAt(ASection, el, ANumFormat, ADecimals, el) then
dec(el)
else begin
Result := false;
exit;
end;
end;
inc(el);
end;
if (ASection = 1) and FHasRedSection and not hasColor then
InsertElement(ASection, 0, nftColor, scRed);
Result := hasCurrSymbol and ((ANumFormat = nfFixedTh) or (ASection = 2));
if Result then begin
if isAccounting then begin
if AColor = scNotDefined then ANumFormat := nfAccounting else
if AColor = scRed then ANumFormat := nfAccountingRed;
end else begin
if AColor = scNotDefined then ANumFormat := nfCurrency else
if AColor = scRed then ANumFormat := nfCurrencyRed;
end;
end else
ANumFormat := nfCustom;
(*
if IsTokenAt(nftColor, ASection, AIndex) then begin if IsTokenAt(nftColor, ASection, AIndex) then begin
AIndex := AIndex + 1; AIndex := AIndex + 1;
AColor := FSections[ASection].Elements[AIndex].IntValue; AColor := FSections[ASection].Elements[AIndex].IntValue;
@ -760,6 +869,7 @@ begin
end; end;
end else end else
ANumFormat := nfCustom; ANumFormat := nfCustom;
*)
end; end;
function TsNumFormatParser.IsDateAt(ASection,AIndex: Integer; function TsNumFormatParser.IsDateAt(ASection,AIndex: Integer;

View File

@ -299,12 +299,14 @@ type
procedure TsSpreadOpenDocNumFormatList.AddBuiltinFormats; procedure TsSpreadOpenDocNumFormatList.AddBuiltinFormats;
begin begin
AddFormat('N0', '', nfGeneral); AddFormat('N0', '', nfGeneral);
{
AddFormat('N1', '0', nfFixed); AddFormat('N1', '0', nfFixed);
AddFormat('N2', '0.00', nfFixed); AddFormat('N2', '0.00', nfFixed);
AddFormat('N3', '#,##0', nfFixedTh); AddFormat('N3', '#,##0', nfFixedTh);
AddFormat('N4', '#,##0.00', nfFixed); AddFormat('N4', '#,##0.00', nfFixedTh);
AddFormat('N10', '0%', nfPercentage); AddFormat('N10', '0%', nfPercentage);
AddFormat('N11', '0.00%', nfPercentage); AddFormat('N11', '0.00%', nfPercentage);
}
end; end;
@ -313,10 +315,14 @@ end;
function TsSpreadOpenDocNumFormatParser.BuildXMLAsString(AIndent, function TsSpreadOpenDocNumFormatParser.BuildXMLAsString(AIndent,
AFormatName: String): String; AFormatName: String): String;
var var
i, ns: Integer; i: Integer;
begin begin
Result := ''; Result := '';
for i := Length(FSections)-1 downto 0 do { When there is only one section the next statement is the only one executed.
When there are several sections the file contains at first the
positive section (index 0), then the negative section (index 1), and
finally the zero section (index 2) which contains the style-map. }
for i:=0 to Length(FSections)-1 do
Result := Result + BuildXMLAsStringFromSection(i, AIndent, AFormatName); Result := Result + BuildXMLAsStringFromSection(i, AIndent, AFormatName);
end; end;
@ -333,6 +339,8 @@ var
ns: Integer; ns: Integer;
clr: TsColorvalue; clr: TsColorvalue;
el: Integer; el: Integer;
s: String;
begin begin
Result := ''; Result := '';
sGrouping := ''; sGrouping := '';
@ -340,20 +348,23 @@ begin
sStyleMap := ''; sStyleMap := '';
ns := Length(FSections); ns := Length(FSections);
if (ns = 0) then
exit;
if (ns > 1) then begin if (ns > 1) then begin
if (ASection = ns - 1) then if (ASection = ns - 1) then
case ns of case ns of
2: sStyleMap := AIndent + 2: sStyleMap := AIndent +
' <style:map ' + ' <style:map ' +
'style:apply-style-name="' + AFormatName + 'P0" ' + 'style:apply-style-name="' + AFormatName + 'P0" ' +
'style:condition="value()>=0" />' + LineEnding; // >= 0 'style:condition="value()&gt;=0" />' + LineEnding; // >= 0
3: sStyleMap := AIndent + 3: sStyleMap := AIndent +
' <style:map '+ ' <style:map '+
'style:apply-style-name="' + AFormatName + 'P0" ' + // > 0 'style:apply-style-name="' + AFormatName + 'P0" ' + // > 0
'style:condition="value()>0" />' + LineEnding + AIndent + 'style:condition="value()&gt;0" />' + LineEnding + AIndent +
' <style:map '+ ' <style:map '+
'style:apply-style-name="' + AFormatName + 'P1" ' + // < 0 'style:apply-style-name="' + AFormatName + 'P1" ' + // < 0
'style:condition="value()<0" />' + LineEnding; 'style:condition="value()&lt;0" />' + LineEnding;
else else
raise Exception.Create('At most 3 format sections allowed.'); raise Exception.Create('At most 3 format sections allowed.');
end end
@ -427,14 +438,17 @@ begin
end; end;
end; end;
// nfSci: not supported by ods, use nfExp instead. // If the program gets here the format can only be nfSci, nfCurrency/Accounting,
// or date/time.
el := 0; el := 0;
decs := 0; decs := 0;
while el < Length(Elements) do begin while el < Length(Elements) do begin
case Elements[el].Token of case Elements[el].Token of
nftDecs: nftDecs:
decs := Elements[el].IntValue; decs := Elements[el].IntValue;
nftExpChar: nftExpChar:
// nfSci: not supported by ods, use nfExp instead.
begin begin
while el < Length(Elements) do begin while el < Length(Elements) do begin
if Elements[el].Token = nftExpDigits then begin if Elements[el].Token = nftExpDigits then begin
@ -453,6 +467,57 @@ begin
end; end;
exit; exit;
end; end;
nftCurrSymbol:
begin
Result := AIndent +
'<number:currency-style style:name="' + AFormatName + '">' + LineEnding;
el := 0;
while el < Length(Elements) do begin
case Elements[el].Token of
nftColor:
begin
clr := FWorkbook.GetPaletteColor(Elements[el].IntValue);
Result := Result + AIndent +
' <style:text-properties fo:color="' + ColorToHTMLColorStr(clr) + '" />' + LineEnding;
inc(el);
end;
nftSign, nftSignBracket:
begin
Result := Result + AIndent +
' <number:text>' + Elements[el].TextValue + '</number:text>' + LineEnding;
inc(el);
end;
nftSpace:
begin
Result := Result + AIndent +
' <number:text><![CDATA[ ]]></number:text>' + LineEnding;
inc(el);
end;
nftCurrSymbol:
begin
Result := Result + AIndent +
' <number:currency-symbol>' + Elements[el].TextValue +
'</number:currency-symbol>' + LineEnding;
inc(el);
end;
nftOptDigit:
if IsNumberAt(ASection, el, nf, decs, el) then
Result := Result + AIndent +
' <number:number decimal-places="' + IntToStr(decs) +
'" number:min-integer-digits="1" number:grouping="true" />'
+ LineEnding;
nftDigit:
if IsNumberAt(ASection, el, nf, decs, el) then
Result := Result + AIndent +
' <number:number decimal-places="' + IntToStr(decs) +
'" number:min-integer-digits="1" />' + LineEnding;
else
inc(el);
end; // case
end; // while
Result := Result + sStyleMap + AIndent + '</number:currency-style>' + LineEnding;
end;
end; end;
inc(el); inc(el);
end; end;
@ -2096,9 +2161,10 @@ var
lRowStylesCode: String; lRowStylesCode: String;
lNumFmtCode: String; lNumFmtCode: String;
begin begin
ListAllNumFormats;
ListAllFormattingStyles;
ListAllColumnStyles; ListAllColumnStyles;
ListAllRowStyles; ListAllRowStyles;
ListAllFormattingStyles;
lNumFmtCode := WriteNumFormatsXMLAsString; lNumFmtCode := WriteNumFormatsXMLAsString;
@ -2347,10 +2413,10 @@ var
parser: TsSpreadOpenDocNumFormatParser; parser: TsSpreadOpenDocNumFormatParser;
begin begin
Result := ''; Result := '';
ListAllNumFormats;
for i:=0 to FNumFormatList.Count-1 do begin for i:=0 to FNumFormatList.Count-1 do begin
fmtItem := FNumFormatList.Items[i]; fmtItem := FNumFormatList.Items[i];
parser := TsSpreadOpenDocNumFormatParser.Create(Workbook, fmtItem.FormatString); parser := TsSpreadOpenDocNumFormatParser.Create(Workbook, fmtItem.FormatString,
fmtItem.NumFormat);
try try
numFmtXML := parser.BuildXMLAsString(' ', fmtItem.Name); numFmtXML := parser.BuildXMLAsString(' ', fmtItem.Name);
if numFmtXML <> '' then if numFmtXML <> '' then
@ -2888,7 +2954,9 @@ begin
lIndex := FindFormattingInList(ACell); lIndex := FindFormattingInList(ACell);
lStyle := ' table:style-name="ce' + IntToStr(lIndex) + '" '; lStyle := ' table:style-name="ce' + IntToStr(lIndex) + '" ';
if pos('%', ACell^.NumberFormatStr) <> 0 then if pos('%', ACell^.NumberFormatStr) <> 0 then
valType := 'percentage'; valType := 'percentage'
else if IsCurrencyFormat(ACell^.NumberFormat) then
valType := 'currency';
end else end else
lStyle := ''; lStyle := '';

View File

@ -545,6 +545,7 @@ type
function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex'; function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex';
{ Data manipulation methods - For Rows and Cols } { Data manipulation methods - For Rows and Cols }
function CalcAutoRowHeight(ARow: Cardinal): Single;
function FindRow(ARow: Cardinal): PRow; function FindRow(ARow: Cardinal): PRow;
function FindCol(ACol: Cardinal): PCol; function FindCol(ACol: Cardinal): PCol;
function GetCellCountInRow(ARow: Cardinal): Cardinal; function GetCellCountInRow(ARow: Cardinal): Cardinal;
@ -2505,6 +2506,22 @@ begin
Result := FWorkbook.FormatSettings; Result := FWorkbook.FormatSettings;
end; end;
function TsWorksheet.CalcAutoRowHeight(ARow: Cardinal): Single;
var
cell: PCell;
fnt: TsFont;
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;
function TsWorksheet.FindRow(ARow: Cardinal): PRow; function TsWorksheet.FindRow(ARow: Cardinal): PRow;
var var
LElement: TRow; LElement: TRow;
@ -2614,7 +2631,7 @@ begin
if row <> nil then if row <> nil then
Result := row^.Height Result := row^.Height
else else
Result := FWorkbook.DefaultRowHeight; Result := CalcAutoRowHeight(ARow); //FWorkbook.DefaultRowHeight;
end; end;
procedure TsWorksheet.RemoveAllRows; procedure TsWorksheet.RemoveAllRows;

View File

@ -764,7 +764,7 @@ var
parser: TsNumFormatParser; parser: TsNumFormatParser;
fmt: String; fmt: String;
begin begin
parser := TsNumFormatParser.Create(Workbook, AFormatString); parser := TsNumFormatParser.Create(Workbook, AFormatString, ANumFormat);
try try
if parser.Status = psOK then begin if parser.Status = psOK then begin
// For writing, we have to convert the fpc format string to Excel dialect // For writing, we have to convert the fpc format string to Excel dialect