fpspreadsheet: Complete ods writer for cell/sheet/document protection -- but ods has a so-far unsupported option to hide cell content, not just formulas ("hidden-and-protected")...

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5797 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2017-03-07 10:13:18 +00:00
parent dfc01330c2
commit d81738d19c
2 changed files with 106 additions and 21 deletions

View File

@ -204,6 +204,7 @@ type
function WriteBackgroundColorStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteBackgroundColorStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteBiDiModeStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteBiDiModeStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteBorderStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteBorderStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteCellProtectionStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteCommentXMLAsString(AComment: String): String; function WriteCommentXMLAsString(AComment: String): String;
function WriteDefaultFontXMLAsString: String; function WriteDefaultFontXMLAsString: String;
function WriteDefaultGraphicStyleXMLAsString: String; overload; function WriteDefaultGraphicStyleXMLAsString: String; overload;
@ -212,8 +213,10 @@ type
function WriteFontStyleXMLAsString(AFont: TsFont): String; overload; function WriteFontStyleXMLAsString(AFont: TsFont): String; overload;
function WriteHeaderFooterFontXMLAsString(AFont: TsHeaderFooterFont): String; function WriteHeaderFooterFontXMLAsString(AFont: TsHeaderFooterFont): String;
function WriteHorAlignmentStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteHorAlignmentStyleXMLAsString(const AFormat: TsCellFormat): String;
function WritePageLayoutAsXMLString(AStyleName: String; const APageLayout: TsPageLayout): String; function WritePageLayoutXMLAsString(AStyleName: String; const APageLayout: TsPageLayout): String;
function WritePrintRangesAsXMLString(ASheet: TsWorksheet): String; function WritePrintRangesXMLAsString(ASheet: TsWorksheet): String;
function WriteSheetProtectionXMLAsString(ASheet: TsWorksheet): String;
function WriteSheetProtectionDetailsXMLAsString(ASheet: TsWorksheet): String;
function WriteTextRotationStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteTextRotationStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteVertAlignmentStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteVertAlignmentStyleXMLAsString(const AFormat: TsCellFormat): String;
function WriteWordwrapStyleXMLAsString(const AFormat: TsCellFormat): String; function WriteWordwrapStyleXMLAsString(const AFormat: TsCellFormat): String;
@ -3934,7 +3937,9 @@ begin
s := GetAttrValue(childnode, 'loext:select-unprotected-cells'); s := GetAttrValue(childnode, 'loext:select-unprotected-cells');
if s='true' then Exclude(sp, spSelectUnlockedCells) if s='true' then Exclude(sp, spSelectUnlockedCells)
else Include(sp, spSelectUnlockedCells); else Include(sp, spSelectUnlockedCells);
if s='false' then Exclude(sp, spSelectLockedCells)
s := GetAttrValue(childnode, 'loext:select-protected-cells');
if s='true' then Exclude(sp, spSelectLockedCells)
else Include(sp, spSelectLockedCells); else Include(sp, spSelectLockedCells);
end; end;
childNode := childNode.NextSibling; childNode := childNode.NextSibling;
@ -4796,7 +4801,7 @@ begin
for i:=0 to FWorkbook.GetWorksheetCount-1 do begin for i:=0 to FWorkbook.GetWorksheetCount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i); sheet := FWorkbook.GetWorksheetByIndex(i);
AppendToStream(AStream, AppendToStream(AStream,
WritePageLayoutAsXMLString('Mpm' + IntToStr(3+i), sheet.PageLayout)); WritePageLayoutXMLAsString('Mpm' + IntToStr(3+i), sheet.PageLayout));
end; end;
for i:=0 to FHeaderFooterFontList.Count-1 do for i:=0 to FHeaderFooterFontList.Count-1 do
@ -5116,8 +5121,12 @@ begin
// Header // Header
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<table:table table:name="%s" table:style-name="ta%d" %s>', [ '<table:table table:name="%s" table:style-name="ta%d"%s%s>%s', [
UTF8TextToXMLText(FWorkSheet.Name), ASheetIndex+1, WritePrintRangesAsXMLString(FWorksheet) UTF8TextToXMLText(FWorkSheet.Name),
ASheetIndex+1,
WriteSheetProtectionXMLAsString(FWorksheet),
WritePrintRangesXMLAsString(FWorksheet),
WriteSheetProtectionDetailsXMLAsString(FWorksheet)
])); ]));
// shapes // shapes
@ -5196,7 +5205,8 @@ begin
WriteBackgroundColorStyleXMLAsString(fmt) + WriteBackgroundColorStyleXMLAsString(fmt) +
WriteWordwrapStyleXMLAsString(fmt) + WriteWordwrapStyleXMLAsString(fmt) +
WriteTextRotationStyleXMLAsString(fmt) + WriteTextRotationStyleXMLAsString(fmt) +
WriteVertAlignmentStyleXMLAsString(fmt); WriteVertAlignmentStyleXMLAsString(fmt) +
WriteCellProtectionStyleXMLAsString(fmt);
if s <> '' then if s <> '' then
AppendToStream(AStream, AppendToStream(AStream,
'<style:table-cell-properties ' + s + '/>'); '<style:table-cell-properties ' + s + '/>');
@ -5336,6 +5346,21 @@ begin
end; end;
end; end;
function TsSpreadOpenDocWriter.WriteCellProtectionStyleXMLAsString(
const AFormat: TsCellFormat): String;
// style:cell-protect="protected formula-hidden"
begin
if AFormat.Protection * [cpLockCell, cpHideFormulas] = [] then
Result := 'none'
else if (AFormat.Protection * [cpLockCell, cpHideFormulas] = [cpLockCell]) then
Result := 'protected'
else if (AFormat.Protection *[cpLockCell, cpHideFormulas] = [cpHideFormulas]) then
Result := 'formula-hidden'
else
Result := 'hidden-and-protected'; // or: 'protected formula-hidden'
Result := ' style:cell-protect="' + Result + '"';
end;
function TsSpreadOpenDocWriter.WriteCommentXMLAsString(AComment: String): String; function TsSpreadOpenDocWriter.WriteCommentXMLAsString(AComment: String): String;
var var
L: TStringList; L: TStringList;
@ -6340,7 +6365,7 @@ begin
spannedStr := ''; spannedStr := '';
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<table:table-cell table:style-name="ce%d"%s>', [ACell^.FormatIndex, spannedStr]), '<table:table-cell table:style-name="ce%d"%s>', [ACell^.FormatIndex, spannedStr]),
comment, comment,
@ -6373,7 +6398,7 @@ begin
valType := 'boolean'; valType := 'boolean';
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" ' lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" '
else else
lStyle := ''; lStyle := '';
@ -6598,7 +6623,6 @@ var
begin begin
if bpLockStructure in Workbook.Protection then if bpLockStructure in Workbook.Protection then
begin begin
Result := ' table:structure-protected="true"';
cinfo := Workbook.CryptoInfo; cinfo := Workbook.CryptoInfo;
if cinfo.PasswordHash <> '' then if cinfo.PasswordHash <> '' then
pwd := Format(' table:protection-key="%s"', [cinfo.PasswordHash]) pwd := Format(' table:protection-key="%s"', [cinfo.PasswordHash])
@ -6609,11 +6633,12 @@ begin
[AlgorithmToStr(cinfo.Algorithm, auOpenDocument)]) [AlgorithmToStr(cinfo.Algorithm, auOpenDocument)])
else else
algo := ''; algo := '';
Result := Result + pwd + algo; Result := ' table:structure-protected="true"' + pwd + algo;
end end
else else
Result := ''; Result := '';
end; end;
procedure TsSpreadOpenDocWriter.WriteError(AStream: TStream; procedure TsSpreadOpenDocWriter.WriteError(AStream: TStream;
const ARow, ACol: Cardinal; const AValue: TsErrorValue; ACell: PCell); const ARow, ACol: Cardinal; const AValue: TsErrorValue; ACell: PCell);
var var
@ -6628,7 +6653,7 @@ begin
Unused(ARow, ACol, AValue); Unused(ARow, ACol, AValue);
fmt := FWorkbook.GetPointerToCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetPointerToCellFormat(ACell^.FormatIndex);
if fmt^.UsedFormattingFields <> [] then if (fmt^.UsedFormattingFields <> []) or (fmt^.Protection <> [cpLockCell]) then
lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" ' lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" '
else else
lStyle := ''; lStyle := '';
@ -6787,7 +6812,7 @@ begin
end; end;
end; end;
function TsSpreadOpenDocWriter.WritePageLayoutAsXMLString(AStyleName: String; function TsSpreadOpenDocWriter.WritePageLayoutXMLAsString(AStyleName: String;
const APageLayout: TsPageLayout): String; const APageLayout: TsPageLayout): String;
function CalcPageLayoutPropStr: String; function CalcPageLayoutPropStr: String;
@ -6902,12 +6927,13 @@ begin
'</style:page-layout>'; '</style:page-layout>';
end; end;
function TsSpreadOpenDocWriter.WritePrintRangesAsXMLString(ASheet: TsWorksheet): String; function TsSpreadOpenDocWriter.WritePrintRangesXMLAsString(ASheet: TsWorksheet): String;
var var
i: Integer; i: Integer;
rng: TsCellRange; rng: TsCellRange;
sheetName: String; sheetName: String;
begin begin
Result := '';
if ASheet.PageLayout.NumPrintRanges > 0 then if ASheet.PageLayout.NumPrintRanges > 0 then
begin begin
for i := 0 to ASheet.PageLayout.NumPrintRanges - 1 do for i := 0 to ASheet.PageLayout.NumPrintRanges - 1 do
@ -6924,10 +6950,44 @@ begin
if Result <> '' then if Result <> '' then
begin begin
Delete(Result, 1, 1); Delete(Result, 1, 1);
Result := 'table:print-ranges="' + Result + '"'; Result := ' table:print-ranges="' + Result + '"';
end; end;
end else end;
Result := ''; end;
function TsSpreadOpenDocWriter.WriteSheetProtectionXMLAsString(
ASheet: TsWorksheet): String;
{table:protected="true" table:protection-key="h/jtkVcSX/xNqeBqe4ARrYClP+E=" table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha1"}
var
pwd: String;
algo: String;
begin
Result := '';
if ASheet.IsProtected then
begin
if ASheet.CryptoInfo.PasswordHash <> '' then
pwd := ' table:protection-key="' + ASheet.CryptoInfo.PasswordHash + '"' else
pwd := '';
algo := AlgorithmToStr(ASheet.CryptoInfo.Algorithm, auOpenDocument);
if algo <> '' then
algo := ' table:protection-key-digest-algorithm="%s"';
Result := ' table:protected="true"' + pwd + algo;
end;
end;
function TsSpreadOpenDocWriter.WriteSheetProtectionDetailsXMLAsString(
ASheet: TsWorksheet): String;
// <loext:table-protection loext:select-unprotected-cells="true" />
begin
Result := '';
if ASheet.IsProtected then
begin
if not (spSelectUnlockedCells in ASheet.Protection) then
Result := Result + ' loext:select-unprotected-cells="true"';
if not (spSelectLockedCells in ASheet.Protection) then
Result := Result + ' loext:select-protected-cells="true"';
Result := '<loext:table-protection' + Result + '/>';
end;
end; end;
procedure TsSpreadOpenDocWriter.WriteShapes(AStream: TStream; procedure TsSpreadOpenDocWriter.WriteShapes(AStream: TStream;
@ -7357,7 +7417,7 @@ begin
// Style // Style
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" ' lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" '
else else
lStyle := ''; lStyle := '';
@ -7527,7 +7587,7 @@ begin
// Style // Style
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '"' lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '"'
else else
lStyle := ''; lStyle := '';
@ -7683,7 +7743,7 @@ begin
valType := 'float'; valType := 'float';
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
begin begin
numFmt := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex); numFmt := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex);
if (numFmt <> nil) then begin if (numFmt <> nil) then begin
@ -7778,7 +7838,7 @@ begin
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
numFmtParams := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex); numFmtParams := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex);
if fmt.UsedFormattingFields <> [] then if (fmt.UsedFormattingFields <> []) or (fmt.Protection <> [cpLockCell]) then
lStyle := Format(' table:style-name="ce%d"', [ACell^.FormatIndex]) lStyle := Format(' table:style-name="ce%d"', [ACell^.FormatIndex])
else else
lStyle := ''; lStyle := '';

View File

@ -97,6 +97,12 @@ type
//procedure TestWriteRead_ODS_WorkbookProtection_Win; //procedure TestWriteRead_ODS_WorkbookProtection_Win;
//procedure TestWriteRead_ODS_WorkbookProtection_StructWin; //procedure TestWriteRead_ODS_WorkbookProtection_StructWin;
procedure TestWriteRead_ODS_WorksheetProtection_Default;
procedure TestWriteRead_ODS_WorksheetProtection_SelectLockedCells;
procedure TestWriteRead_ODS_WorksheetProtection_SelectUnlockedCells;
procedure TestWriteRead_ODS_CellProtection;
end; end;
implementation implementation
@ -596,6 +602,25 @@ begin
TestWriteRead_WorkbookProtection(sfOpenDocument, 3); TestWriteRead_WorkbookProtection(sfOpenDocument, 3);
end;} end;}
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorksheetProtection_Default;
begin
TestWriteRead_WorksheetProtection(sfOpenDocument, 0);
end;
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorksheetProtection_SelectLockedCells;
begin
TestWriteRead_WorksheetProtection(sfOpenDocument, 10);
end;
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorksheetProtection_SelectUnlockedCells;
begin
TestWriteRead_WorksheetProtection(sfOpenDocument, 11);
end;
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_CellProtection;
begin
TestWriteRead_CellProtection(sfOpenDocument);
end;
initialization initialization
RegisterTest(TSpreadWriteReadProtectionTests); RegisterTest(TSpreadWriteReadProtectionTests);