fpspreadsheet: Fix unreadable xlsx file created by hyperlinkdemo/collectlinks demo project

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4083 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-04-18 17:37:20 +00:00
parent 03b7dedde7
commit 06ae0f91dc
4 changed files with 27 additions and 338 deletions

View File

@ -31,7 +31,7 @@ var
begin
// Just for the demo: create the file "source.xls". It contains hyperlinks to
// some the "test" files created in the XXXXdemo projects
// some of the "test" files created in the XXXXdemo projects
Write('Creating source workbook...');
srcWorkbook := TsWorkbook.Create;
try

View File

@ -1,5 +1,5 @@
This sample project demonstrates how to use fpspreadsheet can follow the hyperlinks
This sample project demonstrates how fpspreadsheet can follow the hyperlinks
to other spreadsheet files and copy the linked sheets to a new document.
Please run the write demos ooxmldemo/ooxmlwrite and excel8demp/excel8write before
running this project in order to generate required spreadsheet files.
Please run the write demos ../ooxmldemo/ooxmlwrite and ../excel8demo/excel8write
before running this project in order to generate required spreadsheet files.

View File

@ -50,12 +50,6 @@ type
{ TsSpreadOpenDocNumFormatParser }
TsSpreadOpenDocNumFormatParser = class(TsNumFormatParser)
{
private
function BuildCurrencyXMLAsString(ASection: Integer): String;
function BuildDateTimeXMLAsString(ASection: Integer;
out AIsTimeOnly, AIsInterval: Boolean): String;
}
protected
function BuildXMLAsStringFromSection(ASection: Integer;
AFormatName: String): String;
@ -71,7 +65,6 @@ type
FColumnList: TFPList;
FRowStyleList: TFPList;
FRowList: TFPList;
// FVolatileNumFmtList: TStringList;
FDateMode: TDateMode;
// Applies internally stored column widths to current worksheet
procedure ApplyColWidths;
@ -298,194 +291,10 @@ type
*)
{------------------------------------------------------------------------------}
{******************************************************************************}
{ TsSpreadOpenDocNumFormatParser }
{------------------------------------------------------------------------------}
{******************************************************************************}
(*
function TsSpreadOpenDocNumFormatParser.BuildCurrencyXMLAsString(ASection: Integer): String;
var
el, next: Integer;
clr: TsColorValue;
nf: TsNumberFormat;
decs: byte;
s: String;
n: Integer;
begin
Result := '';
el := 0;
with FSections[ASection] do
while el < Length(Elements) do
begin
case Elements[el].Token of
nftColor:
begin
clr := FWorkbook.GetPaletteColor(Elements[el].IntValue);
Result := Result +
' <style:text-properties fo:color="' + ColorToHTMLColorStr(clr) + '" />';
inc(el);
end;
nftSign, nftSignBracket:
begin
Result := Result +
' <number:text>' + Elements[el].TextValue + '</number:text>';
inc(el);
end;
nftSpace:
begin
Result := Result +
' <number:text><![CDATA[ ]]></number:text>';
inc(el);
end;
nftCurrSymbol:
begin
Result := Result +
' <number:currency-symbol>' + Elements[el].TextValue +
'</number:currency-symbol>';
inc(el);
end;
nftIntTh:
if IsNumberAt(ASection, el, nf, decs, next) then
begin
Result := Result + Format(
' <number:number decimal-places="%d" ' +
'number:min-integer-digits="%d" number:grouping="true" />',
[decs, Elements[el].IntValue]);
el := next;
end;
nftIntZeroDigit:
if IsNumberAt(ASection, el, nf, decs, next) then
begin
Result := Result + Format(
' <number:number decimal-places="%d" ' +
'number:min-integer-digits="%d" />',
[decs, elements[el].IntValue]);
el := next;
end;
nftIntOptDigit, nftIntSpaceDigit: // To do: SpaceDigit not correct here
if IsNumberAt(ASection, el, nf, decs, next) then
begin
Result := Result +
' <number:number decimal-places="' + IntToStr(decs) +
'" number:min-integer-digits="0" />';
el := next;
end;
nftRepeat:
begin
if FSections[ASection].Elements[el].TextValue = ' ' then
s := '<![CDATA[ ]]>' else
s := FSections[ASection].Elements[el].TextValue;
Result := Result +
' <number:text>' + s + '</number:text>';
inc(el);
end
else
inc(el);
end; // case
end; // while
end;
function TsSpreadOpenDocNumFormatParser.BuildDateTimeXMLAsString(ASection: Integer;
out AIsTimeOnly, AIsInterval: boolean): String;
var
el: Integer;
s: String;
prevTok: TsNumFormatToken;
begin
Result := '';
AIsTimeOnly := true;
AIsInterval := false;
with FSections[ASection] do
begin
el := 0;
while el < Length(Elements) do
begin
case Elements[el].Token of
nftYear:
begin
prevTok := Elements[el].Token;
AIsTimeOnly := false;
s := IfThen(Elements[el].IntValue > 2, 'number:style="long" ', '');
Result := Result +
'<number:year ' + s + '/>';
end;
nftMonth:
begin
prevTok := Elements[el].Token;
AIsTimeOnly := false;
case Elements[el].IntValue of
1: s := '';
2: s := 'number:style="long" ';
3: s := 'number:textual="true" ';
4: s := 'number:style="long" number:textual="true" ';
end;
Result := result +
'<number:month ' + s + '/>';
end;
nftDay:
begin
prevTok := Elements[el].Token;
AIsTimeOnly := false;
case Elements[el].IntValue of
1: s := 'day ';
2: s := 'day number:style="long" ';
3: s := 'day-of-week ';
4: s := 'day-of-week number:style="long" ';
end;
Result := Result +
'<number:' + s + '/>';
end;
nftHour, nftMinute, nftSecond:
begin
prevTok := Elements[el].Token;
case Elements[el].Token of
nftHour : s := 'hours ';
nftMinute: s := 'minutes ';
nftSecond: s := 'seconds ';
end;
s := s + IfThen(abs(Elements[el].IntValue) = 1, '', 'number:style="long" ');
if Elements[el].IntValue < 0 then
AIsInterval := true;
Result := Result +
'<number:' + s + '/>';
end;
nftMilliseconds:
begin
// ???
end;
nftDateTimeSep, nftText, nftEscaped, nftSpace:
begin
if Elements[el].TextValue = ' ' then
s := '<![CDATA[ ]]>'
else
begin
s := Elements[el].TextValue;
if (s = '/') then
begin
if prevTok in [nftYear, nftMonth, nftDay] then
s := FWorkbook.FormatSettings.DateSeparator
else
s := FWorkbook.FormatSettings.TimeSeparator;
end;
end;
Result := Result +
'<number:text>' + s + '</number:text>';
end;
nftAMPM:
Result := Result +
'<number:am-pm />';
end;
inc(el);
end;
end;
end;
*)
function TsSpreadOpenDocNumFormatParser.BuildXMLAsString(AFormatName: String): String;
var
i: Integer;
@ -509,7 +318,6 @@ var
mask: String;
timeIntervalStr: String;
styleMapStr: String;
begin
Result := '';
@ -577,7 +385,7 @@ begin
Result := Result + ' number:decimal-places="' + IntToStr(n) + '"';
inc(el, 2);
end else
if (el = nel) or (Elements[el+1].Token <> nftDecSep) then
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
Result := Result + ' number:decimal-places="0"';
Result := Result + ' />';
end;
@ -645,7 +453,7 @@ begin
end
else
// Standard integer
if (el = nel) or (Elements[el+1].Token <> nftDecSep) then
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
begin
Result := Result + '<number:number number:decimal-places="0"';
n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
@ -741,144 +549,11 @@ begin
Result := Format(mask, [AFormatName, TimeIntervalStr, Result, StyleMapStr]);
end;
end;
(*
if IsTokenAt(nftColor, ASection, el) then
begin
clr := FWorkbook.GetPaletteColor(Elements[el].IntValue);
sColor := '<style:text-properties fo:color="' + ColorToHTMLColorStr(clr) + '" />' + LineEnding;
el := 1;
end;
// Find start of number format code
while (el < Length(Elements)) and not IsNumberAt(ASection, el, nf, decs, next) do
inc(el);
if IsNumberAt(ASection, el, nf, decs, next) then
begin
if nf = nfFixedTh then
sGrouping := 'number:grouping="true" ';
// nfFixed, nfFixedTh
if (next = Length(Elements)) then
begin
Result :=
'<number:number-style style:name="' + AFormatName + '">' +
sColor +
'<number:number ' +
'number:min-integer-digits="1" ' + sGrouping +
'number:decimal-places="' + IntToStr(decs) +
'" />' +
sStylemap +
'</number:number-style>';
exit;
end;
// nfPercentage
if (nfkPercent in Kind) then
begin
Result :=
'<number:percentage-style style:name="' + AFormatName + '">' +
sColor +
'<number:number ' +
'number:min-integer-digits="1" ' + sGrouping +
'number:decimal-places="' + IntToStr(decs) + '" />' +
'<number:text>%</number:text>' +
sStyleMap +
'</number:percentage-style>';
exit;
end;
// nfExp
if (nf = nfFixed) and IsTokenAt(nftExpChar, ASection, next) then
begin
if (next + 2 < Length(Elements)) and
IsTokenAt(nftExpSign, ASection, next+1) and
IsTokenAt(nftExpDigits, ASection, next+2)
then
expdig := Elements[next+2].IntValue
else
if (next + 1 < Length(Elements)) and
IsTokenAt(nftExpDigits, ASection, next+1)
then
expdig := Elements[next+1].IntValue
else
exit;
Result :=
'<number:number-style style:name="' + AFormatName + '">' +
sColor +
'<number:scientific-number number:decimal-places="' + IntToStr(decs) +'" '+
'number:min-integer-digits="1" '+
'number:min-exponent-digits="' + IntToStr(expdig) +'" />' +
sStylemap +
'</number:number-style>';
exit;
end;
// nfFraction
if (nf in [nfFixed, nfFraction]) and (nfkFraction in Kind) and (decs = 0) then
begin
if IsTokenAt(nftIntOptDigit, ASection, el) then
Result :=
'<number:number-style style:name="' + AFormatName + '">' +
sColor +
'<number:fraction ' +
'number:min-integer-digits="' + IntToStr(FracInt) + '" ' +
'number:min-numerator-digits="' + IntToStr(FracNumerator) + '" ' +
'number:min-denominator-digits="' + IntToStr(FracDenominator) + '" ' +
'/>' +
'</number:number-style>'
else
Result :=
'<number:number-style style:name="' + AFormatName + '">' +
sColor +
'<number:fraction ' +
'number:min-numerator-digits="' + IntToStr(FracNumerator) + '" ' +
'number:min-denominator-digits="' + IntToStr(FracDenominator) + '" ' +
'/>' +
'</number:number-style>';
exit;
end;
// nfCurrency
if (nfkCurrency in Kind) then
begin
Result :=
'<number:currency-style style:name="' + AFormatName + '">' +
BuildCurrencyXMLAsString(ASection) +
sStyleMap +
'</number:currency-style>';
exit;
end;
end;
// If the program gets here the format can only be date/time.
if (Kind * [nfkDate, nfkTime] <> []) then
begin
s := BuildDateTimeXMLAsString(ASection, isTimeOnly, isInterval);
if isTimeOnly then
begin
Result := Result +
'<number:time-style ' +
'style:name="' + AFormatName + '"' +
IfThen(isInterval, ' number:truncate-on-overflow="false"') + '>' +
s +
sStylemap +
'</number:time-style>';
end else
Result := Result +
'<number:date-style style:name="' + AFormatName + '">' +
s +
sStylemap +
'</number:date-style>';
exit;
end;
end;
end;
*)
{ TsSpreadOpenDocReader }
{******************************************************************************}
{ TsSpreadOpenDocReader }
{******************************************************************************}
constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook);
begin

View File

@ -910,6 +910,8 @@ procedure CopyCellFormat(AFromCell, AToCell: PCell);
var
sourceSheet, destSheet: TsWorksheet;
fmt: TsCellFormat;
numFmtParams: TsNumFormatParams;
nfs: String;
font: TsFont;
clr: TsColorvalue;
cb: TsCellBorder;
@ -923,7 +925,7 @@ begin
else
begin
fmt := sourceSheet.ReadCellFormat(AFromCell);
destSheet.WriteCellFormat(AToCell, fmt);
//destSheet.WriteCellFormat(AToCell, fmt);
if (uffBackground in fmt.UsedFormattingFields) then
begin
clr := sourceSheet.Workbook.GetPaletteColor(fmt.Background.BgColor);
@ -936,7 +938,9 @@ begin
font := sourceSheet.ReadCellFont(AFromCell);
clr := sourceSheet.Workbook.GetPaletteColor(font.Color);
font.Color := destSheet.Workbook.AddColorToPalette(clr);
fmt.FontIndex := destSheet.WriteFont(AToCell, font.FontName, font.Size, font.Style, font.Color);
fmt.FontIndex := destSheet.Workbook.FindFont(font.FontName, font.Size, font.Style, font.Color);
if fmt.FontIndex = -1 then
fmt.FontIndex := destSheet.Workbook.AddFont(font.FontName, font.Size, font.Style, font.Color);
end;
if (uffBorder in fmt.UsedFormattingFields) then
for cb in fmt.Border do
@ -944,6 +948,16 @@ begin
clr := sourceSheet.Workbook.GetPaletteColor(fmt.BorderStyles[cb].Color);
fmt.BorderStyles[cb].Color := destSheet.Workbook.AddColorToPalette(clr);
end;
if (uffNumberformat in fmt.UsedFormattingFields) then
begin
numFmtParams := sourceSheet.Workbook.GetNumberFormat(fmt.NumberFormatIndex);
if numFmtParams <> nil then
begin
nfs := numFmtParams.NumFormatStr[nfdExcel];
fmt.NumberFormatIndex := destSheet.Workbook.AddNumberFormat(nfs);
end;
end;
destSheet.WriteCellFormat(AToCell, fmt);
end;
end;