fpspreadsheet: Support defined names in ods files. No formula support so far.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9398 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-07-24 18:08:13 +00:00
parent 19e94158df
commit 7735590b99
2 changed files with 78 additions and 2 deletions

View File

@ -231,6 +231,7 @@ type
public
procedure CopyFrom(AItem: TsDefinedName);
function RangeAsString: String;
function RangeAsString_ODS: String;
property Name: String read FName;
property Range: TsCellRange read FRange write FRange;
property SheetName1: String read FSheet1 write FSheet1;
@ -1850,11 +1851,19 @@ begin
end;
end;
// Test!$C$3
function TsDefinedName.RangeAsString: String;
begin
Result := GetCellRangeString(FSheet1, FSheet2, FRange.Row1, FRange.Col1, FRange.Row2, FRange.Col2, [], true);
end;
// $Test.$C$3
function TsDefinedName.RangeAsString_ODS: String;
begin
Result := Format('$%s.%s', [FSheet1, GetCellString(FRange.Row1, FRange.Col1, [])]);
if (FSheet1 <> FSheet2) or (FRange.Row1 <> FRange.Row2) or (FRange.Col1 <> FRange.Col2) then
Result := Format('%s:$%s.%s', [Result, FSheet2, GetCellString(FRange.Row2, FRange.Col2, [])]);
end;
{==============================================================================}
{ TsDefinedNames }

View File

@ -42,7 +42,7 @@ uses
laz2_xmlread, laz2_DOM,
avglvltree, math, dateutils, contnrs,
{$IFDEF FPS_PATCHED_ZIPPER} fpszipper, {$ELSE} zipper, {$ENDIF}
fpstypes, fpsReaderWriter, fpsUtils, fpsHeaderFooterParser,
fpsTypes, fpsReaderWriter, fpsUtils, fpsClasses, fpsHeaderFooterParser,
fpsNumFormat, fpsXMLCommon,
{$IFDEF FPS_CHARTS} fpsChart, {$ENDIF}
fpsPagelayout;
@ -160,6 +160,7 @@ type
procedure ReadColumnStyle(AStyleNode: TDOMNode);
procedure ReadConditionalFormats(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
procedure ReadDateMode(SpreadSheetNode: TDOMNode);
procedure ReadDefinedNames(ANode: TDOMNode);
procedure ReadDocumentProtection(ANode: TDOMNode);
procedure ReadFont(ANode: TDOMNode; var AFontName: String;
var AFontSize: Single; var AFontStyle: TsFontStyles; var AFontColor: TsColor;
@ -290,6 +291,7 @@ type
function WriteConditionalStyleXMLAsString(ACFIndex: Integer): String;
function WriteDefaultFontXMLAsString: String;
function WriteDefaultGraphicStyleXMLAsString: String; overload;
function WriteDefinedNameXMLAsString(ADefinedName: TsDefinedName): String;
function WriteDocumentProtectionXMLAsString: String;
function WriteFontStyleXMLAsString(const AFormat: TsCellFormat): String; overload;
function WriteHeaderFooterFontXMLAsString(AFont: TsHeaderFooterFont): String;
@ -334,6 +336,7 @@ type
{ Routines to write those files }
procedure WriteContent;
procedure WriteDefinedNames(AStream: TStream);
procedure WriteMetaInfManifest;
procedure WriteMeta;
procedure WriteMimetype;
@ -380,7 +383,7 @@ implementation
uses
StrUtils, Variants, LazFileUtils, URIParser, LazUTF8,
{%H-}fpsPatches,
fpsStrings, fpsStreams, fpsCrypto, fpsClasses, fpSpreadsheet,
fpsStrings, fpsStreams, fpsCrypto, fpSpreadsheet,
fpsExprParser, fpsImages,
{$IFDEF FPS_CHARTS}
fpsOpenDocumentChart,
@ -2628,6 +2631,39 @@ begin
raise EFPSpreadsheetReader.CreateFmt('Spreadsheet file corrupt: cannot handle null-date format %s', [NullDateSetting]);
end;
procedure TsSpreadOpenDocReader.ReadDefinedNames(ANode: TDOMNode);
var
book: TsWorkbook;
nodeName: String;
defName: String;
defAddr: String;
r1, c1, r2, c2: Cardinal;
sheet1, sheet2: String;
flags: TsRelFlags;
begin
if ANode = nil then
exit;
ANode := ANode.FindNode('table:named-expressions');
if ANode = nil then
exit;
book := TsWorkbook(FWorkbook);
ANode := ANode.FirstChild;
while ANode <> nil do
begin
nodeName := ANode.NodeName;
if nodeName = 'table:named-range' then
begin
defName := GetAttrValue(ANode, 'table:name');
defAddr := GetAttrValue(ANode, 'table:cell-range-address');
if TryStrToCellRange_ODS(defAddr, sheet1, sheet2, r1, c1, r2, c2, flags) then
book.DefinedNames.Add(defName, sheet1, sheet2, r1, c1, r2, c2);
end;
ANode := ANode.NextSibling;
end;
end;
procedure TsSpreadOpenDocReader.ReadDocumentProtection(ANode: TDOMNode);
var
cinfo: TsCryptoInfo;
@ -3154,6 +3190,7 @@ begin
TableNode := TableNode.NextSibling;
end; //while Assigned(TableNode)
ReadDefinedNames(SpreadSheetNode);
FreeAndNil(Doc);
end;
@ -6659,6 +6696,8 @@ begin
for i := 0 to (Workbook as TsWorkbook).GetWorksheetCount - 1 do
WriteWorksheet(FSContent, i);
WriteDefinedNames(FSContent);
AppendToStream(FSContent,
'</office:spreadsheet>' +
'</office:body>' +
@ -6666,6 +6705,23 @@ begin
);
end;
procedure TsSpreadOpenDocWriter.WriteDefinedNames(AStream: TStream);
var
book: TsWorkbook;
i: Integer;
begin
book := TsWorkbook(FWorkbook);
if book.DefinedNames.Count = 0 then
exit;
AppendToStream(AStream, '<table:named-expressions>');
for i := 0 to book.DefinedNames.Count-1 do
AppendToStream(AStream, WriteDefinedNameXMLAsString(book.DefinedNames[i]));
AppendToStream(AStream, '</table:named-expressions>');
end;
procedure TsSpreadOpenDocWriter.WriteWorksheet(AStream: TStream;
ASheetIndex: Integer);
begin
@ -8691,6 +8747,17 @@ begin
Result := '';
end;
function TsSpreadOpenDocWriter.WriteDefinedNameXMLAsString(ADefinedName: TsDefinedName): String;
begin
Result := Format(
'<table:named-range ' +
'table:name="%s" ' +
'table:base-cell-address="$%s.$A$1" ' +
'table:cell-range-address="%s" />',
[ ADefinedName.Name, ADefinedName.SheetName1, ADefinedName.RangeAsString_ODS ]
);
end;
procedure TsSpreadOpenDocWriter.WriteError(AStream: TStream;
const ARow, ACol: Cardinal; const AValue: TsErrorValue; ACell: PCell);
var