You've already forked lazarus-ccr
fpspreadsheet: Add writing support for cell, sheet and workbook protection in xls files (biff2, biff5, biff8), opendocument and Excel XML files. Not complete, yet.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5795 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -10,13 +10,13 @@ type
|
|||||||
|
|
||||||
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
|
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
|
||||||
function StrToAlgorithm(const AName: String): TsCryptoAlgorithm;
|
function StrToAlgorithm(const AName: String): TsCryptoAlgorithm;
|
||||||
|
(*
|
||||||
function ExcelPasswordHash(const APassword: String): String;
|
function PasswordHash(const APassword: String; Algorithm: TsAlgorithm): String;
|
||||||
|
*)
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
LazUTF8;
|
sha1, LazUTF8;
|
||||||
|
|
||||||
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
|
function AlgorithmToStr(Algorithm: TsCryptoAlgorithm; AUsage: TsAlgorithmUsage): String;
|
||||||
begin
|
begin
|
||||||
@@ -100,5 +100,22 @@ begin
|
|||||||
|
|
||||||
Result := IntToHex(PassHash, 4);
|
Result := IntToHex(PassHash, 4);
|
||||||
end;
|
end;
|
||||||
|
(*
|
||||||
|
function SHA1Hash(const AText: String): String;
|
||||||
|
var
|
||||||
|
sha1: TSHA1Digest;
|
||||||
|
begin
|
||||||
|
sha1 := SHA1String(AText);
|
||||||
|
Result := PChar(sha1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CalcPasswordHash(const APassword: String; Algorithm: TsAlgorithm): String;
|
||||||
|
begin
|
||||||
|
case Algorithm of
|
||||||
|
caExcel: Result := ExcelPasswordHash(APassword);
|
||||||
|
caSHA1 : Result := SHA1Hash(APassword);
|
||||||
|
else raise Exception.Create('Hashing algorithm not implemented.');
|
||||||
|
end;
|
||||||
|
end; *)
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@@ -207,6 +207,7 @@ type
|
|||||||
function WriteCommentXMLAsString(AComment: String): String;
|
function WriteCommentXMLAsString(AComment: String): String;
|
||||||
function WriteDefaultFontXMLAsString: String;
|
function WriteDefaultFontXMLAsString: String;
|
||||||
function WriteDefaultGraphicStyleXMLAsString: String; overload;
|
function WriteDefaultGraphicStyleXMLAsString: String; overload;
|
||||||
|
function WriteDocumentProtectionXMLAsString: String;
|
||||||
function WriteFontStyleXMLAsString(const AFormat: TsCellFormat): String; overload;
|
function WriteFontStyleXMLAsString(const AFormat: TsCellFormat): String; overload;
|
||||||
function WriteFontStyleXMLAsString(AFont: TsFont): String; overload;
|
function WriteFontStyleXMLAsString(AFont: TsFont): String; overload;
|
||||||
function WriteHeaderFooterFontXMLAsString(AFont: TsHeaderFooterFont): String;
|
function WriteHeaderFooterFontXMLAsString(AFont: TsHeaderFooterFont): String;
|
||||||
@@ -4996,6 +4997,7 @@ end;
|
|||||||
procedure TsSpreadOpenDocWriter.WriteContent;
|
procedure TsSpreadOpenDocWriter.WriteContent;
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
s: String;
|
||||||
begin
|
begin
|
||||||
AppendToStream(FSContent,
|
AppendToStream(FSContent,
|
||||||
XML_HEADER);
|
XML_HEADER);
|
||||||
@@ -5089,7 +5091,7 @@ begin
|
|||||||
// Body
|
// Body
|
||||||
AppendToStream(FSContent,
|
AppendToStream(FSContent,
|
||||||
'<office:body>' +
|
'<office:body>' +
|
||||||
'<office:spreadsheet>');
|
'<office:spreadsheet' + WriteDocumentProtectionXMLAsString + '>');
|
||||||
|
|
||||||
// Write all worksheets
|
// Write all worksheets
|
||||||
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
for i := 0 to Workbook.GetWorksheetCount - 1 do
|
||||||
@@ -6589,6 +6591,29 @@ begin
|
|||||||
'style:language-complex="hi" style:country-complex="IN" />';
|
'style:language-complex="hi" style:country-complex="IN" />';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsSpreadOpenDocWriter.WriteDocumentProtectionXMLAsString: String;
|
||||||
|
var
|
||||||
|
cinfo: TsCryptoInfo;
|
||||||
|
pwd, algo: String;
|
||||||
|
begin
|
||||||
|
if bpLockStructure in Workbook.Protection then
|
||||||
|
begin
|
||||||
|
Result := ' table:structure-protected="true"';
|
||||||
|
cinfo := Workbook.CryptoInfo;
|
||||||
|
if cinfo.PasswordHash <> '' then
|
||||||
|
pwd := Format(' table:protection-key="%s"', [cinfo.PasswordHash])
|
||||||
|
else
|
||||||
|
pwd := '';
|
||||||
|
if cinfo.Algorithm <> caUnknown then
|
||||||
|
algo := Format(' table:protection-key-digest-algorithm="%s"',
|
||||||
|
[AlgorithmToStr(cinfo.Algorithm, auOpenDocument)])
|
||||||
|
else
|
||||||
|
algo := '';
|
||||||
|
Result := Result + pwd + algo;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := '';
|
||||||
|
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
|
||||||
|
@@ -6763,6 +6763,15 @@ begin
|
|||||||
ChangedCell(ACell^.Row, ACell^.Col);
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Defines how the cell at the specified row and column is protected: lock
|
||||||
|
cell modification and/or hide formulas. Note that this is activated only after
|
||||||
|
enabling worksheet protection (worksheet.Protect(true)).
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
FPSpreadsheet does not enforce these actions. They are only written
|
||||||
|
to the file for the Office application.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.WriteCellProtection(ARow, ACol: Cardinal;
|
function TsWorksheet.WriteCellProtection(ARow, ACol: Cardinal;
|
||||||
AValue: TsCellProtections): PCell;
|
AValue: TsCellProtections): PCell;
|
||||||
begin
|
begin
|
||||||
|
@@ -663,9 +663,9 @@ type
|
|||||||
spFormatCells, spFormatColumns, spFormatRows,
|
spFormatCells, spFormatColumns, spFormatRows,
|
||||||
spDeleteColumns, spDeleteRows,
|
spDeleteColumns, spDeleteRows,
|
||||||
spInsertColumns, spInsertRows, spInsertHyperlinks,
|
spInsertColumns, spInsertRows, spInsertHyperlinks,
|
||||||
spCells, spSort,
|
spCells, spSort, spObjects,
|
||||||
spSelectLockedCells, spSelectUnlockedCells
|
spSelectLockedCells, spSelectUnlockedCells
|
||||||
{spObjects, spPivotTables, spScenarios }
|
{spPivotTables, spScenarios }
|
||||||
);
|
);
|
||||||
TsWorksheetProtections = set of TsWorksheetProtection;
|
TsWorksheetProtections = set of TsWorksheetProtection;
|
||||||
|
|
||||||
@@ -676,8 +676,8 @@ type
|
|||||||
const
|
const
|
||||||
ALL_SHEET_PROTECTIONS = [spFormatCells, spFormatColumns, spFormatRows,
|
ALL_SHEET_PROTECTIONS = [spFormatCells, spFormatColumns, spFormatRows,
|
||||||
spDeleteColumns, spDeleteRows, spInsertColumns, spInsertRows, spInsertHyperlinks,
|
spDeleteColumns, spDeleteRows, spInsertColumns, spInsertRows, spInsertHyperlinks,
|
||||||
spCells, spSort, spSelectLockedCells, spSelectUnlockedCells
|
spCells, spSort, spObjects, spSelectLockedCells, spSelectUnlockedCells
|
||||||
{, spObjects, spPivotTables, spScenarios} ];
|
{spPivotTables, spScenarios} ];
|
||||||
|
|
||||||
DEFAULT_SHEET_PROTECTION = ALL_SHEET_PROTECTIONS - [spSelectLockedCells, spSelectUnlockedcells];
|
DEFAULT_SHEET_PROTECTION = ALL_SHEET_PROTECTIONS - [spSelectLockedCells, spSelectUnlockedcells];
|
||||||
|
|
||||||
|
@@ -63,6 +63,7 @@ type
|
|||||||
procedure ReadIXFE(AStream: TStream);
|
procedure ReadIXFE(AStream: TStream);
|
||||||
procedure ReadLabel(AStream: TStream); override;
|
procedure ReadLabel(AStream: TStream); override;
|
||||||
procedure ReadNumber(AStream: TStream); override;
|
procedure ReadNumber(AStream: TStream); override;
|
||||||
|
procedure ReadPROTECT(AStream: TStream);
|
||||||
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override;
|
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override;
|
||||||
procedure ReadRowInfo(AStream: TStream); override;
|
procedure ReadRowInfo(AStream: TStream); override;
|
||||||
function ReadRPNAttr(AStream: TStream; AIdentifier: Byte): Boolean; override;
|
function ReadRPNAttr(AStream: TStream; AIdentifier: Byte): Boolean; override;
|
||||||
@@ -616,10 +617,11 @@ begin
|
|||||||
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
||||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||||
|
INT_EXCEL_ID_OBJECTPROTECT : ReadObjectProtect(AStream);
|
||||||
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
||||||
INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream);
|
INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream);
|
||||||
INT_EXCEL_ID_PRINTHEADERS : ReadPrintHeaders(AStream);
|
INT_EXCEL_ID_PRINTHEADERS : ReadPrintHeaders(AStream);
|
||||||
INT_EXCEL_ID_PROTECT : ReadPROTECT(AStream, FWorksheet);
|
INT_EXCEL_ID_PROTECT : ReadPROTECT(AStream);
|
||||||
INT_EXCEL_ID_RIGHTMARGIN : ReadMargin(AStream, 1);
|
INT_EXCEL_ID_RIGHTMARGIN : ReadMargin(AStream, 1);
|
||||||
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
|
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
|
||||||
INT_EXCEL_ID_SELECTION : ReadSELECTION(AStream);
|
INT_EXCEL_ID_SELECTION : ReadSELECTION(AStream);
|
||||||
@@ -866,6 +868,12 @@ begin
|
|||||||
FPendingXFIndex := WordLEToN(AStream.ReadWord);
|
FPendingXFIndex := WordLEToN(AStream.ReadWord);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFF2Reader.ReadPROTECT(AStream: TStream);
|
||||||
|
begin
|
||||||
|
inherited ReadPROTECT(AStream);
|
||||||
|
FWorksheet.Protect(Workbook.IsProtected);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Reads the row, column and xf index from the stream
|
Reads the row, column and xf index from the stream
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@@ -1194,8 +1202,8 @@ var
|
|||||||
begin
|
begin
|
||||||
fmt := Workbook.GetPointerToCellFormat(AFormatIndex);
|
fmt := Workbook.GetPointerToCellFormat(AFormatIndex);
|
||||||
|
|
||||||
if fmt^.UsedFormattingFields = [] then begin
|
if (fmt^.UsedFormattingFields = []) and (fmt^.Protection = [cpLockCell]) then begin
|
||||||
Attrib1 := 15;
|
Attrib1 := 15 + $40;
|
||||||
Attrib2 := 0;
|
Attrib2 := 0;
|
||||||
Attrib3 := 0;
|
Attrib3 := 0;
|
||||||
exit;
|
exit;
|
||||||
@@ -1206,6 +1214,8 @@ begin
|
|||||||
// Mask $40: 1 = Cell is locked
|
// Mask $40: 1 = Cell is locked
|
||||||
// Mask $80: 1 = Formula is hidden
|
// Mask $80: 1 = Formula is hidden
|
||||||
Attrib1 := Min(XFIndex, $3F) and $3F;
|
Attrib1 := Min(XFIndex, $3F) and $3F;
|
||||||
|
if cpLockCell in fmt^.Protection then Attrib1 := Attrib1 or $40;
|
||||||
|
if cpHideFormulas in fmt^.Protection then Attrib1 := Attrib1 or $80;
|
||||||
|
|
||||||
// 2nd byte:
|
// 2nd byte:
|
||||||
// Mask $3F: Index to FORMAT record ("FORMAT" = number format!)
|
// Mask $3F: Index to FORMAT record ("FORMAT" = number format!)
|
||||||
@@ -1346,13 +1356,17 @@ begin
|
|||||||
rec.XFIndex_Locked_Hidden := 0; // to silence the compiler...
|
rec.XFIndex_Locked_Hidden := 0; // to silence the compiler...
|
||||||
FillChar(rec, SizeOf(rec), 0);
|
FillChar(rec, SizeOf(rec), 0);
|
||||||
|
|
||||||
if fmt^.UsedFormattingFields <> [] then
|
if (fmt^.UsedFormattingFields <> []) or (fmt^.Protection <> [cpLockCell]) then
|
||||||
begin
|
begin
|
||||||
// 1st byte:
|
// 1st byte:
|
||||||
// Mask $3F: Index to XF record
|
// Mask $3F: Index to XF record
|
||||||
// Mask $40: 1 = Cell is locked
|
// Mask $40: 1 = Cell is locked
|
||||||
// Mask $80: 1 = Formula is hidden
|
// Mask $80: 1 = Formula is hidden
|
||||||
rec.XFIndex_Locked_Hidden := Min(XFIndex, $3F) and $3F;
|
rec.XFIndex_Locked_Hidden := Min(XFIndex, $3F) and $3F;
|
||||||
|
if cpLockCell in fmt^.Protection then
|
||||||
|
rec.XFIndex_Locked_Hidden := rec.XFIndex_Locked_Hidden or $40;
|
||||||
|
if cpHideFormulas in fmt^.Protection then
|
||||||
|
rec.XFIndex_Locked_Hidden := rec.XFIndex_Locked_Hidden or $80;
|
||||||
|
|
||||||
// 2nd byte:
|
// 2nd byte:
|
||||||
// Mask $3F: Index to FORMAT record
|
// Mask $3F: Index to FORMAT record
|
||||||
@@ -1601,6 +1615,11 @@ begin
|
|||||||
|
|
||||||
WriteFormatCount(AStream);
|
WriteFormatCount(AStream);
|
||||||
WriteNumFormats(AStream);
|
WriteNumFormats(AStream);
|
||||||
|
if (bpLockStructure in Workbook.Protection) or FWorksheet.IsProtected then
|
||||||
|
WritePROTECT(AStream, true);
|
||||||
|
WriteWindowProtect(AStream, bpLockWindows in Workbook.Protection);
|
||||||
|
WriteObjectProtect(AStream, FWorksheet);
|
||||||
|
|
||||||
WriteXFRecords(AStream);
|
WriteXFRecords(AStream);
|
||||||
WriteDefaultColWidth(AStream, FWorksheet);
|
WriteDefaultColWidth(AStream, FWorksheet);
|
||||||
WriteColWidths(AStream);
|
WriteColWidths(AStream);
|
||||||
@@ -1700,6 +1719,7 @@ var
|
|||||||
rec: TBIFF2_XFRecord;
|
rec: TBIFF2_XFRecord;
|
||||||
b: Byte;
|
b: Byte;
|
||||||
formatIdx, fontIdx: Integer;
|
formatIdx, fontIdx: Integer;
|
||||||
|
fmtProt: byte;
|
||||||
begin
|
begin
|
||||||
Unused(XFType_Prot);
|
Unused(XFType_Prot);
|
||||||
GetFormatAndFontIndex(AFormatRecord, formatIdx, fontIdx);
|
GetFormatAndFontIndex(AFormatRecord, formatIdx, fontIdx);
|
||||||
@@ -1720,8 +1740,15 @@ begin
|
|||||||
5-0 $3F Index to (number) FORMAT record
|
5-0 $3F Index to (number) FORMAT record
|
||||||
6 $40 1 = Cell is locked
|
6 $40 1 = Cell is locked
|
||||||
7 $80 1 = Formula is hidden }
|
7 $80 1 = Formula is hidden }
|
||||||
rec.NumFormat_Prot := WordToLE(formatIdx);
|
fmtProt := formatIdx + $40;
|
||||||
// Cell flags not used, so far...
|
if AFormatRecord <> nil then
|
||||||
|
begin
|
||||||
|
if not (cpLockCell in AFormatRecord^.Protection) then
|
||||||
|
fmtProt := fmtProt and not $40;
|
||||||
|
if (cpHideFormulas in AFormatRecord^.Protection) then
|
||||||
|
fmtProt := fmtProt or $80;
|
||||||
|
end;
|
||||||
|
rec.NumFormat_Prot := WordToLE(fmtProt);
|
||||||
|
|
||||||
{Horizontal alignment, border style, and background
|
{Horizontal alignment, border style, and background
|
||||||
Bit Mask Contents
|
Bit Mask Contents
|
||||||
|
@@ -534,6 +534,7 @@ begin
|
|||||||
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
|
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
|
||||||
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
INT_EXCEL_ID_NOTE : ReadComment(AStream);
|
||||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||||
|
INT_EXCEL_ID_OBJECTPROTECT : ReadObjectProtect(AStream, FWorksheet);
|
||||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||||
INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
|
INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
|
||||||
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
||||||
@@ -1135,6 +1136,8 @@ begin
|
|||||||
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
||||||
|
|
||||||
WriteCODEPAGE(AStream, FCodePage);
|
WriteCODEPAGE(AStream, FCodePage);
|
||||||
|
WriteWindowProtect(AStream, bpLockWindows in Workbook.Protection);
|
||||||
|
WritePROTECT(AStream, bpLockStructure in Workbook.Protection);
|
||||||
WriteEXTERNCOUNT(AStream);
|
WriteEXTERNCOUNT(AStream);
|
||||||
WriteEXTERNSHEET(AStream);
|
WriteEXTERNSHEET(AStream);
|
||||||
WriteDefinedNames(AStream);
|
WriteDefinedNames(AStream);
|
||||||
@@ -1182,7 +1185,11 @@ begin
|
|||||||
WriteMargin(AStream, 2); // 2 = top margin
|
WriteMargin(AStream, 2); // 2 = top margin
|
||||||
WriteMargin(AStream, 3); // 3 = bottom margin
|
WriteMargin(AStream, 3); // 3 = bottom margin
|
||||||
WritePageSetup(AStream);
|
WritePageSetup(AStream);
|
||||||
|
if FWorksheet.IsProtected then begin
|
||||||
|
WritePROTECT(AStream, true);
|
||||||
|
// WriteScenarioProtect(AStream);
|
||||||
|
WriteObjectProtect(AStream, FWorksheet);
|
||||||
|
end;
|
||||||
WriteDefaultColWidth(AStream, FWorksheet);
|
WriteDefaultColWidth(AStream, FWorksheet);
|
||||||
WriteColInfos(AStream, FWorksheet);
|
WriteColInfos(AStream, FWorksheet);
|
||||||
WriteDimensions(AStream, FWorksheet);
|
WriteDimensions(AStream, FWorksheet);
|
||||||
@@ -1920,9 +1927,20 @@ begin
|
|||||||
rec.NumFormatIndex := WordToLE(j);
|
rec.NumFormatIndex := WordToLE(j);
|
||||||
|
|
||||||
{ XF type, cell protection and parent style XF }
|
{ XF type, cell protection and parent style XF }
|
||||||
rec.XFType_Prot_ParentXF := XFType_Prot and MASK_XF_TYPE_PROT;
|
if AFormatRecord = nil then
|
||||||
if XFType_Prot and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
begin
|
||||||
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_PARENT;
|
rec.XFType_Prot_ParentXF := XFType_Prot and MASK_XF_TYPE_PROT;
|
||||||
|
if XFType_Prot and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_PARENT;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
rec.XFType_Prot_ParentXF := 0;
|
||||||
|
if cpLockCell in AFormatRecord^.Protection then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_LOCKED;
|
||||||
|
if cpHideFormulas in AFormatRecord^.Protection then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_FORMULA_HIDDEN;
|
||||||
|
end;
|
||||||
|
rec.XFType_Prot_ParentXF := WordToLE(rec.XFType_Prot_ParentXF);
|
||||||
|
|
||||||
{ Text alignment and text break }
|
{ Text alignment and text break }
|
||||||
if AFormatRecord = nil then
|
if AFormatRecord = nil then
|
||||||
|
@@ -875,6 +875,7 @@ begin
|
|||||||
INT_EXCEL_ID_NOTE : ReadNOTE(AStream);
|
INT_EXCEL_ID_NOTE : ReadNOTE(AStream);
|
||||||
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
|
||||||
INT_EXCEL_ID_OBJ : ReadOBJ(AStream);
|
INT_EXCEL_ID_OBJ : ReadOBJ(AStream);
|
||||||
|
INT_EXCEL_ID_OBJECTPROTECT : ReadObjectProtect(AStream, FWorksheet);
|
||||||
INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
|
INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
|
||||||
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
INT_EXCEL_ID_PANE : ReadPane(AStream);
|
||||||
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
INT_EXCEL_ID_PASSWORD : ReadPASSWORD(AStream, FWorksheet);
|
||||||
@@ -2127,7 +2128,9 @@ begin
|
|||||||
{ Write workbook globals }
|
{ Write workbook globals }
|
||||||
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
|
||||||
WriteCodePage(AStream, 'ucs2le'); // = utf-16
|
WriteCodePage(AStream, 'ucs2le'); // = utf-16
|
||||||
WriteWindow1(AStream);
|
WriteWindowProtect(AStream, bpLockWindows in Workbook.Protection);
|
||||||
|
WritePROTECT(AStream, bpLockStructure in Workbook.Protection);
|
||||||
|
WriteWINDOW1(AStream);
|
||||||
WriteFonts(AStream);
|
WriteFonts(AStream);
|
||||||
WriteNumFormats(AStream);
|
WriteNumFormats(AStream);
|
||||||
WritePalette(AStream);
|
WritePalette(AStream);
|
||||||
@@ -2174,7 +2177,11 @@ begin
|
|||||||
WriteMargin(AStream, 2); // 2 = top margin
|
WriteMargin(AStream, 2); // 2 = top margin
|
||||||
WriteMargin(AStream, 3); // 3 = bottom margin
|
WriteMargin(AStream, 3); // 3 = bottom margin
|
||||||
WritePageSetup(AStream);
|
WritePageSetup(AStream);
|
||||||
|
if FWorksheet.IsProtected then begin
|
||||||
|
WritePROTECT(AStream, true);
|
||||||
|
// WriteScenarioProtect(AStream);
|
||||||
|
WriteObjectProtect(AStream, FWorksheet);
|
||||||
|
end;
|
||||||
WriteDefaultColWidth(AStream, FWorksheet);
|
WriteDefaultColWidth(AStream, FWorksheet);
|
||||||
WriteColInfos(AStream, FWorksheet);
|
WriteColInfos(AStream, FWorksheet);
|
||||||
WriteDimensions(AStream, FWorksheet);
|
WriteDimensions(AStream, FWorksheet);
|
||||||
@@ -3657,9 +3664,19 @@ begin
|
|||||||
rec.NumFormatIndex := WordToLE(j);
|
rec.NumFormatIndex := WordToLE(j);
|
||||||
|
|
||||||
{ XF type, cell protection and parent style XF }
|
{ XF type, cell protection and parent style XF }
|
||||||
rec.XFType_Prot_ParentXF := XFType_Prot and MASK_XF_TYPE_PROT;
|
if AFormatRecord = nil then begin
|
||||||
if XFType_Prot and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
rec.XFType_Prot_ParentXF := XFType_Prot and MASK_XF_TYPE_PROT;
|
||||||
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_PARENT;
|
if XFType_Prot and MASK_XF_TYPE_PROT_STYLE_XF <> 0 then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_PARENT;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
rec.XFType_Prot_ParentXF := 0;
|
||||||
|
if cpLockCell in AFormatRecord^.Protection then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_LOCKED;
|
||||||
|
if cpHideFormulas in AFormatRecord^.Protection then
|
||||||
|
rec.XFType_Prot_ParentXF := rec.XFType_Prot_ParentXF or MASK_XF_TYPE_PROT_FORMULA_HIDDEN;
|
||||||
|
end;
|
||||||
|
rec.XFType_Prot_ParentXF := WordToLE(rec.XFType_Prot_ParentXF);
|
||||||
|
|
||||||
{ Text alignment and text break }
|
{ Text alignment and text break }
|
||||||
if AFormatRecord = nil then
|
if AFormatRecord = nil then
|
||||||
@@ -3708,12 +3725,12 @@ begin
|
|||||||
|
|
||||||
{ Used attributes }
|
{ Used attributes }
|
||||||
rec.UsedAttrib :=
|
rec.UsedAttrib :=
|
||||||
MASK_XF_USED_ATTRIB_NUMBER_FORMAT or
|
MASK_XF_USED_ATTRIB_NUMBER_FORMAT or
|
||||||
MASK_XF_USED_ATTRIB_FONT or
|
MASK_XF_USED_ATTRIB_FONT or
|
||||||
MASK_XF_USED_ATTRIB_TEXT or
|
MASK_XF_USED_ATTRIB_TEXT or
|
||||||
MASK_XF_USED_ATTRIB_BORDER_LINES or
|
MASK_XF_USED_ATTRIB_BORDER_LINES or
|
||||||
MASK_XF_USED_ATTRIB_BACKGROUND or
|
MASK_XF_USED_ATTRIB_BACKGROUND or
|
||||||
MASK_XF_USED_ATTRIB_CELL_PROTECTION;
|
MASK_XF_USED_ATTRIB_CELL_PROTECTION;
|
||||||
|
|
||||||
{ Cell border lines and background area }
|
{ Cell border lines and background area }
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ const
|
|||||||
INT_EXCEL_ID_PANE = $0041;
|
INT_EXCEL_ID_PANE = $0041;
|
||||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||||
INT_EXCEL_ID_DEFCOLWIDTH = $0055;
|
INT_EXCEL_ID_DEFCOLWIDTH = $0055;
|
||||||
|
INT_EXCEL_ID_OBJECTPROTECT = $0063;
|
||||||
|
|
||||||
{ RECORD IDs which did not changed across versions 2-5 }
|
{ RECORD IDs which did not changed across versions 2-5 }
|
||||||
INT_EXCEL_ID_EXTERNCOUNT = $0016; // does not exist in BIFF8
|
INT_EXCEL_ID_EXTERNCOUNT = $0016; // does not exist in BIFF8
|
||||||
@@ -133,7 +134,7 @@ const
|
|||||||
{ XF_TYPE_PROT - XF Type and Cell protection (3 Bits) - BIFF3-BIFF8 }
|
{ XF_TYPE_PROT - XF Type and Cell protection (3 Bits) - BIFF3-BIFF8 }
|
||||||
MASK_XF_TYPE_PROT_LOCKED = $0001;
|
MASK_XF_TYPE_PROT_LOCKED = $0001;
|
||||||
MASK_XF_TYPE_PROT_FORMULA_HIDDEN = $0002;
|
MASK_XF_TYPE_PROT_FORMULA_HIDDEN = $0002;
|
||||||
MASK_XF_TYPE_PROT_STYLE_XF = $0004; // 0 = CELL XF
|
MASK_XF_TYPE_PROT_STYLE_XF = $0005; // was: 4 (wp)
|
||||||
MASK_XF_TYPE_PROTECTION = $0007;
|
MASK_XF_TYPE_PROTECTION = $0007;
|
||||||
|
|
||||||
|
|
||||||
@@ -450,6 +451,8 @@ type
|
|||||||
procedure ReadMulRKValues(const AStream: TStream);
|
procedure ReadMulRKValues(const AStream: TStream);
|
||||||
// Read floating point number
|
// Read floating point number
|
||||||
procedure ReadNumber(AStream: TStream); override;
|
procedure ReadNumber(AStream: TStream); override;
|
||||||
|
// Read OBJECTPROTECT record
|
||||||
|
procedure ReadObjectProtect(AStream: TStream; AWorksheet: TsWorksheet = nil);
|
||||||
// Read palette
|
// Read palette
|
||||||
procedure ReadPalette(AStream: TStream);
|
procedure ReadPalette(AStream: TStream);
|
||||||
// Read page setup
|
// Read page setup
|
||||||
@@ -585,6 +588,8 @@ type
|
|||||||
// Writes out a floating point NUMBER record
|
// Writes out a floating point NUMBER record
|
||||||
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
const AValue: Double; ACell: PCell); override;
|
const AValue: Double; ACell: PCell); override;
|
||||||
|
// Writes an OBJECTPROTECT record
|
||||||
|
procedure WriteObjectProtect(AStream: TStream; ASheet: TsWorksheet);
|
||||||
procedure WritePageSetup(AStream: TStream);
|
procedure WritePageSetup(AStream: TStream);
|
||||||
// Writes out a PALETTE record containing all colors defined in the workbook
|
// Writes out a PALETTE record containing all colors defined in the workbook
|
||||||
procedure WritePalette(AStream: TStream);
|
procedure WritePalette(AStream: TStream);
|
||||||
@@ -594,6 +599,7 @@ type
|
|||||||
// Writes out whether grid lines are printed
|
// Writes out whether grid lines are printed
|
||||||
procedure WritePrintGridLines(AStream: TStream);
|
procedure WritePrintGridLines(AStream: TStream);
|
||||||
procedure WritePrintHeaders(AStream: TStream);
|
procedure WritePrintHeaders(AStream: TStream);
|
||||||
|
procedure WritePROTECT(AStream: TStream; AEnable: Boolean);
|
||||||
// Writes out a ROW record
|
// Writes out a ROW record
|
||||||
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
|
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
|
||||||
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual;
|
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual;
|
||||||
@@ -632,6 +638,7 @@ type
|
|||||||
procedure WriteVirtualCells(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteVirtualCells(AStream: TStream; ASheet: TsWorksheet);
|
||||||
// Writes out a WINDOW1 record
|
// Writes out a WINDOW1 record
|
||||||
procedure WriteWindow1(AStream: TStream); virtual;
|
procedure WriteWindow1(AStream: TStream); virtual;
|
||||||
|
procedure WriteWindowProtect(AStream: TStream; AEnable: Boolean);
|
||||||
// Writes an XF record
|
// Writes an XF record
|
||||||
procedure WriteXF(AStream: TStream; ACellFormat: PsCellFormat;
|
procedure WriteXF(AStream: TStream; ACellFormat: PsCellFormat;
|
||||||
XFType_Prot: Byte = 0); virtual;
|
XFType_Prot: Byte = 0); virtual;
|
||||||
@@ -1903,6 +1910,24 @@ begin
|
|||||||
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
|
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Reads the OBJECTPROTECT record. It determines whether the objects (drawings,
|
||||||
|
etc) of the current sheet are protected.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsSpreadBIFFReader.ReadObjectProtect(AStream: TStream;
|
||||||
|
AWorksheet: TsWorksheet = nil);
|
||||||
|
var
|
||||||
|
w: Word;
|
||||||
|
sp: TsWorksheetProtections;
|
||||||
|
begin
|
||||||
|
if AWorksheet = nil then
|
||||||
|
AWorksheet := FWorksheet;
|
||||||
|
w := WordLEToN(AStream.ReadWord);
|
||||||
|
sp := AWorksheet.Protection;
|
||||||
|
if w = 0 then Exclude(sp, spObjects) else Include(sp, spObjects);
|
||||||
|
AWorksheet.Protection := sp;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Reads the color palette
|
Reads the color palette
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@@ -2092,16 +2117,22 @@ var
|
|||||||
p: Word;
|
p: Word;
|
||||||
begin
|
begin
|
||||||
p := WordLEToN(AStream.ReadWord);
|
p := WordLEToN(AStream.ReadWord);
|
||||||
if p = 0 then // not protected
|
|
||||||
exit;
|
|
||||||
|
|
||||||
if AWorksheet = nil then
|
if AWorksheet = nil then
|
||||||
|
begin
|
||||||
// Workbook protection
|
// Workbook protection
|
||||||
FWorkbook.Protection := FWorkbook.Protection + [bpLockStructure]
|
if p = 1 then
|
||||||
else begin
|
FWorkbook.Protection := FWorkbook.Protection + [bpLockStructure]
|
||||||
|
else
|
||||||
|
FWorkbook.Protection := FWorkbook.Protection - [bpLockStructure];
|
||||||
|
end else
|
||||||
|
begin
|
||||||
// Worksheet protection
|
// Worksheet protection
|
||||||
AWorksheet.Protection := FWorksheet.Protection + [spCells];
|
if p = 1 then begin
|
||||||
AWorksheet.Protect(true);
|
AWorksheet.Protection := AWorksheet.Protection + [spCells];
|
||||||
|
AWorksheet.Protect(true);
|
||||||
|
end else
|
||||||
|
AWorksheet.Protect(false);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -3833,6 +3864,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Writes an OBJECTPROTECT record. It determines whether the objects (drawings,
|
||||||
|
etc.) of the current worksheet are protected. Omitted if object
|
||||||
|
protection is not active.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsSpreadBIFFWriter.WriteObjectProtect(AStream: TStream;
|
||||||
|
ASheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
w: Word;
|
||||||
|
begin
|
||||||
|
if not ASheet.IsProtected then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
WriteBIFFHeader(AStream, INT_EXCEL_ID_OBJECTPROTECT, 2);
|
||||||
|
w := IfThen(spObjects in ASheet.Protection, 1, 0);
|
||||||
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Writes a PAGESETUP record containing information on printing
|
Writes a PAGESETUP record containing information on printing
|
||||||
Valid for BIFF5-8
|
Valid for BIFF5-8
|
||||||
@@ -4019,6 +4068,125 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(w));
|
AStream.WriteWord(WordToLE(w));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Writes an Excel PROTECT record
|
||||||
|
Valid for BIFF2-BIFF8
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsSpreadBIFFWriter.WritePROTECT(AStream: TStream; AEnable: Boolean);
|
||||||
|
var
|
||||||
|
w: Word;
|
||||||
|
begin
|
||||||
|
{ BIFF Header }
|
||||||
|
WriteBiffHeader(AStream, INT_EXCEL_ID_PROTECT, 2);
|
||||||
|
|
||||||
|
w := IfThen(AEnable, 1, 0);
|
||||||
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Writes an Excel 3-8 ROW record
|
||||||
|
Valid for BIFF3-BIFF8
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsSpreadBIFFWriter.WriteRow(AStream: TStream; ASheet: TsWorksheet;
|
||||||
|
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow);
|
||||||
|
var
|
||||||
|
w: Word;
|
||||||
|
dw: DWord;
|
||||||
|
cell: PCell;
|
||||||
|
spaceabove, spacebelow: Boolean;
|
||||||
|
colindex: Cardinal;
|
||||||
|
rowheight: Word;
|
||||||
|
fmt: PsCellFormat;
|
||||||
|
begin
|
||||||
|
if (ARowIndex >= FLimitations.MaxRowCount) or
|
||||||
|
(AFirstColIndex >= FLimitations.MaxColCount) or
|
||||||
|
(ALastColIndex >= FLimitations.MaxColCount)
|
||||||
|
then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// Check for additional space above/below row
|
||||||
|
spaceabove := false;
|
||||||
|
spacebelow := false;
|
||||||
|
colindex := AFirstColIndex;
|
||||||
|
while colindex <= ALastColIndex do
|
||||||
|
begin
|
||||||
|
cell := ASheet.FindCell(ARowindex, colindex);
|
||||||
|
if (cell <> nil) then
|
||||||
|
begin
|
||||||
|
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
|
||||||
|
if (uffBorder in fmt^.UsedFormattingFields) then
|
||||||
|
begin
|
||||||
|
if (cbNorth in fmt^.Border) and (fmt^.BorderStyles[cbNorth].LineStyle = lsThick)
|
||||||
|
then spaceabove := true;
|
||||||
|
if (cbSouth in fmt^.Border) and (fmt^.BorderStyles[cbSouth].LineStyle = lsThick)
|
||||||
|
then spacebelow := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if spaceabove and spacebelow then break;
|
||||||
|
inc(colindex);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ BIFF record header }
|
||||||
|
WriteBIFFHeader(AStream, INT_EXCEL_ID_ROW, 16);;
|
||||||
|
|
||||||
|
{ Index of row }
|
||||||
|
AStream.WriteWord(WordToLE(Word(ARowIndex)));
|
||||||
|
|
||||||
|
{ Index to column of the first cell which is described by a cell record }
|
||||||
|
AStream.WriteWord(WordToLE(Word(AFirstColIndex)));
|
||||||
|
|
||||||
|
{ Index to column of the last cell which is described by a cell record, increased by 1 }
|
||||||
|
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
||||||
|
|
||||||
|
{ Row height (in twips, 1/20 point) and info on custom row height }
|
||||||
|
if (ARow = nil) or (ARow^.RowHeightType = rhtDefault) then
|
||||||
|
rowheight := PtsToTwips(ASheet.ReadDefaultRowHeight(suPoints))
|
||||||
|
else
|
||||||
|
rowheight := PtsToTwips(FWorkbook.ConvertUnits(ARow^.Height, FWorkbook.Units, suPoints));
|
||||||
|
w := rowheight and $7FFF;
|
||||||
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
|
||||||
|
{ 2 words not used }
|
||||||
|
AStream.WriteDWord(0);
|
||||||
|
|
||||||
|
{ Option flags }
|
||||||
|
dw := $00000100; // bit 8 is always 1
|
||||||
|
if spaceabove then dw := dw or $10000000;
|
||||||
|
if spacebelow then dw := dw or $20000000;
|
||||||
|
if (ARow <> nil) and (ARow^.RowHeightType = rhtCustom) then // Custom row height
|
||||||
|
dw := dw or $00000040; // Row height and font height do not match
|
||||||
|
if ARow^.FormatIndex > 0 then begin
|
||||||
|
dw := dw or $00000080; // Row has custom format
|
||||||
|
dw := dw or DWord(FindXFIndex(ARow^.FormatIndex) shl 16); // xf index
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Write out }
|
||||||
|
AStream.WriteDWord(DWordToLE(dw));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Writes all ROW records for the given sheet.
|
||||||
|
Note that the OpenOffice documentation says that rows must be written in
|
||||||
|
groups of 32, followed by the cells on these rows, etc. THIS IS NOT NECESSARY!
|
||||||
|
Valid for BIFF2-BIFF8.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure TsSpreadBIFFWriter.WriteRows(AStream: TStream; ASheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
row: PRow;
|
||||||
|
i: Integer;
|
||||||
|
cell1, cell2: PCell;
|
||||||
|
begin
|
||||||
|
for i := 0 to ASheet.Rows.Count-1 do begin
|
||||||
|
row := ASheet.Rows[i];
|
||||||
|
cell1 := ASheet.Cells.GetFirstCellOfRow(row^.Row);
|
||||||
|
if cell1 <> nil then begin
|
||||||
|
cell2 := ASheet.Cells.GetLastCellOfRow(row^.Row);
|
||||||
|
WriteRow(AStream, ASheet, row^.Row, cell1^.Col, cell2^.Col, row);
|
||||||
|
end else
|
||||||
|
WriteRow(AStream, ASheet, row^.Row, 0, 0, row);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Writes the address of a cell as used in an RPN formula and returns the
|
Writes the address of a cell as used in an RPN formula and returns the
|
||||||
count of bytes written.
|
count of bytes written.
|
||||||
@@ -4421,110 +4589,6 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(ASize));
|
AStream.WriteWord(WordToLE(ASize));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Writes an Excel 3-8 ROW record
|
|
||||||
Valid for BIFF3-BIFF8
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsSpreadBIFFWriter.WriteRow(AStream: TStream; ASheet: TsWorksheet;
|
|
||||||
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow);
|
|
||||||
var
|
|
||||||
w: Word;
|
|
||||||
dw: DWord;
|
|
||||||
cell: PCell;
|
|
||||||
spaceabove, spacebelow: Boolean;
|
|
||||||
colindex: Cardinal;
|
|
||||||
rowheight: Word;
|
|
||||||
fmt: PsCellFormat;
|
|
||||||
begin
|
|
||||||
if (ARowIndex >= FLimitations.MaxRowCount) or
|
|
||||||
(AFirstColIndex >= FLimitations.MaxColCount) or
|
|
||||||
(ALastColIndex >= FLimitations.MaxColCount)
|
|
||||||
then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
// Check for additional space above/below row
|
|
||||||
spaceabove := false;
|
|
||||||
spacebelow := false;
|
|
||||||
colindex := AFirstColIndex;
|
|
||||||
while colindex <= ALastColIndex do
|
|
||||||
begin
|
|
||||||
cell := ASheet.FindCell(ARowindex, colindex);
|
|
||||||
if (cell <> nil) then
|
|
||||||
begin
|
|
||||||
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
|
|
||||||
if (uffBorder in fmt^.UsedFormattingFields) then
|
|
||||||
begin
|
|
||||||
if (cbNorth in fmt^.Border) and (fmt^.BorderStyles[cbNorth].LineStyle = lsThick)
|
|
||||||
then spaceabove := true;
|
|
||||||
if (cbSouth in fmt^.Border) and (fmt^.BorderStyles[cbSouth].LineStyle = lsThick)
|
|
||||||
then spacebelow := true;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if spaceabove and spacebelow then break;
|
|
||||||
inc(colindex);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ BIFF record header }
|
|
||||||
WriteBIFFHeader(AStream, INT_EXCEL_ID_ROW, 16);;
|
|
||||||
|
|
||||||
{ Index of row }
|
|
||||||
AStream.WriteWord(WordToLE(Word(ARowIndex)));
|
|
||||||
|
|
||||||
{ Index to column of the first cell which is described by a cell record }
|
|
||||||
AStream.WriteWord(WordToLE(Word(AFirstColIndex)));
|
|
||||||
|
|
||||||
{ Index to column of the last cell which is described by a cell record, increased by 1 }
|
|
||||||
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
|
||||||
|
|
||||||
{ Row height (in twips, 1/20 point) and info on custom row height }
|
|
||||||
if (ARow = nil) or (ARow^.RowHeightType = rhtDefault) then
|
|
||||||
rowheight := PtsToTwips(ASheet.ReadDefaultRowHeight(suPoints))
|
|
||||||
else
|
|
||||||
rowheight := PtsToTwips(FWorkbook.ConvertUnits(ARow^.Height, FWorkbook.Units, suPoints));
|
|
||||||
w := rowheight and $7FFF;
|
|
||||||
AStream.WriteWord(WordToLE(w));
|
|
||||||
|
|
||||||
{ 2 words not used }
|
|
||||||
AStream.WriteDWord(0);
|
|
||||||
|
|
||||||
{ Option flags }
|
|
||||||
dw := $00000100; // bit 8 is always 1
|
|
||||||
if spaceabove then dw := dw or $10000000;
|
|
||||||
if spacebelow then dw := dw or $20000000;
|
|
||||||
if (ARow <> nil) and (ARow^.RowHeightType = rhtCustom) then // Custom row height
|
|
||||||
dw := dw or $00000040; // Row height and font height do not match
|
|
||||||
if ARow^.FormatIndex > 0 then begin
|
|
||||||
dw := dw or $00000080; // Row has custom format
|
|
||||||
dw := dw or DWord(FindXFIndex(ARow^.FormatIndex) shl 16); // xf index
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Write out }
|
|
||||||
AStream.WriteDWord(DWordToLE(dw));
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
|
||||||
Writes all ROW records for the given sheet.
|
|
||||||
Note that the OpenOffice documentation says that rows must be written in
|
|
||||||
groups of 32, followed by the cells on these rows, etc. THIS IS NOT NECESSARY!
|
|
||||||
Valid for BIFF2-BIFF8.
|
|
||||||
-------------------------------------------------------------------------------}
|
|
||||||
procedure TsSpreadBIFFWriter.WriteRows(AStream: TStream; ASheet: TsWorksheet);
|
|
||||||
var
|
|
||||||
row: PRow;
|
|
||||||
i: Integer;
|
|
||||||
cell1, cell2: PCell;
|
|
||||||
begin
|
|
||||||
for i := 0 to ASheet.Rows.Count-1 do begin
|
|
||||||
row := ASheet.Rows[i];
|
|
||||||
cell1 := ASheet.Cells.GetFirstCellOfRow(row^.Row);
|
|
||||||
if cell1 <> nil then begin
|
|
||||||
cell2 := ASheet.Cells.GetLastCellOfRow(row^.Row);
|
|
||||||
WriteRow(AStream, ASheet, row^.Row, cell1^.Col, cell2^.Col, row);
|
|
||||||
end else
|
|
||||||
WriteRow(AStream, ASheet, row^.Row, 0, 0, row);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Writes the SCL record - this is the current magnification factor of the sheet
|
Writes the SCL record - this is the current magnification factor of the sheet
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
@@ -4898,6 +4962,18 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(600));
|
AStream.WriteWord(WordToLE(600));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadBIFFWriter.WriteWindowProtect(AStream: TStream;
|
||||||
|
AEnable: Boolean);
|
||||||
|
var
|
||||||
|
w: Word;
|
||||||
|
begin
|
||||||
|
{ BIFF Header }
|
||||||
|
WriteBiffHeader(AStream, INT_EXCEL_ID_WINDOWPROTECT, 2);
|
||||||
|
|
||||||
|
w := IfThen(AEnable, 1, 0);
|
||||||
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Writes an XF record needed for cell formatting.
|
Writes an XF record needed for cell formatting.
|
||||||
Is called from WriteXFRecords.
|
Is called from WriteXFRecords.
|
||||||
@@ -4949,7 +5025,7 @@ begin
|
|||||||
// XF14
|
// XF14
|
||||||
WriteXF(AStream, nil, MASK_XF_TYPE_PROT_STYLE_XF);
|
WriteXF(AStream, nil, MASK_XF_TYPE_PROT_STYLE_XF);
|
||||||
// XF15 - Default, no formatting
|
// XF15 - Default, no formatting
|
||||||
WriteXF(AStream, nil, 0);
|
WriteXF(AStream, nil, MASK_XF_TYPE_PROT_LOCKED);
|
||||||
|
|
||||||
// Add all further non-standard format records
|
// Add all further non-standard format records
|
||||||
// The first style was already added --> begin loop with 1
|
// The first style was already added --> begin loop with 1
|
||||||
|
@@ -143,6 +143,8 @@ const
|
|||||||
2
|
2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
FALSE_TRUE: array[boolean] of string = ('False', 'True');
|
||||||
|
|
||||||
function GetCellContentTypeStr(ACell: PCell): String;
|
function GetCellContentTypeStr(ACell: PCell): String;
|
||||||
begin
|
begin
|
||||||
case ACell^.ContentType of
|
case ACell^.ContentType of
|
||||||
@@ -428,16 +430,23 @@ end;
|
|||||||
procedure TsSpreadExcelXMLWriter.WriteExcelWorkbook(AStream: TStream);
|
procedure TsSpreadExcelXMLWriter.WriteExcelWorkbook(AStream: TStream);
|
||||||
var
|
var
|
||||||
datemodeStr: String;
|
datemodeStr: String;
|
||||||
|
protectStr: String;
|
||||||
begin
|
begin
|
||||||
if FDateMode = dm1904 then
|
if FDateMode = dm1904 then
|
||||||
datemodeStr := INDENT2 + '<Date1904/>' + LF else
|
datemodeStr := INDENT2 + '<Date1904/>' + LF else
|
||||||
datemodeStr := '';
|
datemodeStr := '';
|
||||||
|
|
||||||
|
protectStr := Format(
|
||||||
|
'<ProtectStructure>%s</ProtectStructure>' + LF + INDENT2 +
|
||||||
|
'<ProtectWindows>%s</ProtectWindows>' + LF, [
|
||||||
|
FALSE_TRUE[bpLockStructure in Workbook.Protection],
|
||||||
|
FALSE_TRUE[bpLockWindows in Workbook.Protection]
|
||||||
|
]);
|
||||||
|
|
||||||
AppendToStream(AStream, INDENT1 +
|
AppendToStream(AStream, INDENT1 +
|
||||||
'<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">' + LF +
|
'<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">' + LF +
|
||||||
datemodeStr + INDENT2 +
|
datemodeStr + INDENT2 +
|
||||||
'<ProtectStructure>False</ProtectStructure>' + LF + INDENT2 +
|
protectStr + INDENT1 +
|
||||||
'<ProtectWindows>False</ProtectWindows>' + LF + INDENT1 +
|
|
||||||
'</ExcelWorkbook>' + LF);
|
'</ExcelWorkbook>' + LF);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -653,6 +662,18 @@ begin
|
|||||||
'</Borders>' + LF);
|
'</Borders>' + LF);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
s := '';
|
||||||
|
if FWorkbook.IsProtected then begin
|
||||||
|
if not (cpLockCell in fmt^.Protection) then
|
||||||
|
s := s + 'ss:Protected="0" ';
|
||||||
|
if cpHideFormulas in fmt^.Protection then
|
||||||
|
s := s + 'x:HideFormula="1" ';
|
||||||
|
end;
|
||||||
|
if s <> '' then
|
||||||
|
AppendToStream(AStream, INDENT3 +
|
||||||
|
'<Protection ' + s + '/>' + LF);
|
||||||
|
|
||||||
AppendToStream(AStream, INDENT2 +
|
AppendToStream(AStream, INDENT2 +
|
||||||
'</Style>' + LF);
|
'</Style>' + LF);
|
||||||
end;
|
end;
|
||||||
@@ -784,10 +805,20 @@ end;
|
|||||||
|
|
||||||
procedure TsSpreadExcelXMLWriter.WriteWorksheet(AStream: TStream;
|
procedure TsSpreadExcelXMLWriter.WriteWorksheet(AStream: TStream;
|
||||||
AWorksheet: TsWorksheet);
|
AWorksheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
protectedStr: String;
|
||||||
begin
|
begin
|
||||||
FWorksheet := AWorksheet;
|
FWorksheet := AWorksheet;
|
||||||
|
|
||||||
|
if FWorksheet.IsProtected then
|
||||||
|
protectedStr := ' ss:Protected="1"' else
|
||||||
|
protectedStr := '';
|
||||||
|
|
||||||
AppendToStream(AStream, Format(
|
AppendToStream(AStream, Format(
|
||||||
' <Worksheet ss:Name="%s">' + LF, [UTF8TextToXMLText(AWorksheet.Name)]) );
|
' <Worksheet ss:Name="%s"%s>' + LF, [
|
||||||
|
UTF8TextToXMLText(AWorksheet.Name),
|
||||||
|
protectedStr
|
||||||
|
]) );
|
||||||
WriteTable(AStream, AWorksheet);
|
WriteTable(AStream, AWorksheet);
|
||||||
WriteWorksheetOptions(AStream, AWorksheet);
|
WriteWorksheetOptions(AStream, AWorksheet);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
@@ -805,6 +836,7 @@ var
|
|||||||
layoutStr: String;
|
layoutStr: String;
|
||||||
marginStr: String;
|
marginStr: String;
|
||||||
selectedStr: String;
|
selectedStr: String;
|
||||||
|
protectStr: String;
|
||||||
begin
|
begin
|
||||||
// Orientation, some PageLayout.Options
|
// Orientation, some PageLayout.Options
|
||||||
layoutStr := GetLayoutStr(AWorksheet);
|
layoutStr := GetLayoutStr(AWorksheet);
|
||||||
@@ -839,6 +871,13 @@ begin
|
|||||||
// Frozen panes
|
// Frozen panes
|
||||||
frozenStr := GetFrozenPanesStr(AWorksheet, INDENT3);
|
frozenStr := GetFrozenPanesStr(AWorksheet, INDENT3);
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
protectStr := Format(INDENT3 + '<ProtectObjects>%s</ProtectObjects>' + LF +
|
||||||
|
INDENT3 + '<ProtectScenarios>%s</ProtectScenarios>' + LF, [
|
||||||
|
AWorksheet.IsProtected and (spObjects in AWorksheet.Protection),
|
||||||
|
AWorksheet.IsProtected {and [spScenarios in AWorksheet.Protection])}
|
||||||
|
]);
|
||||||
|
|
||||||
// Put it all together...
|
// Put it all together...
|
||||||
AppendToStream(AStream, INDENT2 +
|
AppendToStream(AStream, INDENT2 +
|
||||||
'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">' + LF + INDENT3 +
|
'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">' + LF + INDENT3 +
|
||||||
@@ -849,6 +888,7 @@ begin
|
|||||||
marginStr + INDENT3 +
|
marginStr + INDENT3 +
|
||||||
'</PageSetup>' + LF +
|
'</PageSetup>' + LF +
|
||||||
selectedStr +
|
selectedStr +
|
||||||
|
protectStr +
|
||||||
frozenStr +
|
frozenStr +
|
||||||
hideGridStr +
|
hideGridStr +
|
||||||
hideHeadersStr + INDENT2 +
|
hideHeadersStr + INDENT2 +
|
||||||
|
@@ -2051,12 +2051,12 @@ begin
|
|||||||
if (s = '1') then Include(shp, spSelectUnlockedCells) else
|
if (s = '1') then Include(shp, spSelectUnlockedCells) else
|
||||||
if (s = '') or (s = '0') then Exclude(shp, spSelectUnlockedCells);
|
if (s = '') or (s = '0') then Exclude(shp, spSelectUnlockedCells);
|
||||||
|
|
||||||
// these options are currently not supported by fpspreadsheet
|
|
||||||
{
|
|
||||||
s := GetAttrValue(ANode, 'objects');
|
s := GetAttrValue(ANode, 'objects');
|
||||||
if (s = '1') then Include(shp, spObjects) else
|
if (s = '1') then Include(shp, spObjects) else
|
||||||
if (s = '') or (s = '0') then Exclude(shp, spObjects);
|
if (s = '') or (s = '0') then Exclude(shp, spObjects);
|
||||||
|
|
||||||
|
// these options are currently not supported by fpspreadsheet
|
||||||
|
{
|
||||||
s := GetAttrValue(ANode, 'scenarios');
|
s := GetAttrValue(ANode, 'scenarios');
|
||||||
if (s = '1') then Include(shp, spScenarios) else
|
if (s = '1') then Include(shp, spScenarios) else
|
||||||
if (s = '') or (s = '0') then Exclude(shp, spScenarios);
|
if (s = '') or (s = '0') then Exclude(shp, spScenarios);
|
||||||
@@ -3423,7 +3423,7 @@ begin
|
|||||||
|
|
||||||
// No attribute -> attr="0"
|
// No attribute -> attr="0"
|
||||||
if AWorksheet.IsProtected then
|
if AWorksheet.IsProtected then
|
||||||
s := ' sheet="1" objects="1" scenarios="1"'
|
s := ' sheet="1" scenarios="1"'
|
||||||
else
|
else
|
||||||
Exit; //exit if sheet not protected
|
Exit; //exit if sheet not protected
|
||||||
|
|
||||||
@@ -3445,11 +3445,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{
|
if spObjects in AWorksheet.Protection then
|
||||||
if spObjects in AWorksheet.Protection then // to do: Remove from default above
|
|
||||||
s := s + ' objects="1"';
|
s := s + ' objects="1"';
|
||||||
|
|
||||||
if spScenarios in AWorksheet.Protection then
|
{
|
||||||
|
if spScenarios in AWorksheet.Protection then // to do: Remove from default above
|
||||||
s := s + ' scenarios="1"';
|
s := s + ' scenarios="1"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,29 +32,71 @@ type
|
|||||||
published
|
published
|
||||||
// Writes out protection & reads back.
|
// Writes out protection & reads back.
|
||||||
|
|
||||||
|
{ BIFF2 protection tests }
|
||||||
|
procedure TestWriteRead_BIFF2_WorkbookProtection_None;
|
||||||
|
procedure TestWriteRead_BIFF2_WorkbookProtection_Struct;
|
||||||
|
procedure TestWriteRead_BIFF2_WorkbookProtection_Win;
|
||||||
|
procedure TestWriteRead_BIFF2_WorkbookProtection_StructWin;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF2_WorksheetProtection_Default;
|
||||||
|
procedure TestWriteRead_BIFF2_WorksheetProtection_Objects;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF2_CellProtection;
|
||||||
|
|
||||||
|
{ BIFF5 protection tests }
|
||||||
|
procedure TestWriteRead_BIFF5_WorkbookProtection_None;
|
||||||
|
procedure TestWriteRead_BIFF5_WorkbookProtection_Struct;
|
||||||
|
procedure TestWriteRead_BIFF5_WorkbookProtection_Win;
|
||||||
|
procedure TestWriteRead_BIFF5_WorkbookProtection_StructWin;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF5_WorksheetProtection_Default;
|
||||||
|
procedure TestWriteRead_BIFF5_WorksheetProtection_SelectLockedCells;
|
||||||
|
procedure TestWriteRead_BIFF5_WorksheetProtection_SelectUnlockedCells;
|
||||||
|
procedure TestWriteRead_BIFF5_WorksheetProtection_Objects;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF5_CellProtection;
|
||||||
|
|
||||||
|
{ BIFF8 protection tests }
|
||||||
|
procedure TestWriteRead_BIFF8_WorkbookProtection_None;
|
||||||
|
procedure TestWriteRead_BIFF8_WorkbookProtection_Struct;
|
||||||
|
procedure TestWriteRead_BIFF8_WorkbookProtection_Win;
|
||||||
|
procedure TestWriteRead_BIFF8_WorkbookProtection_StructWin;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF8_WorksheetProtection_Default;
|
||||||
|
procedure TestWriteRead_BIFF8_WorksheetProtection_SelectLockedCells;
|
||||||
|
procedure TestWriteRead_BIFF8_WorksheetProtection_SelectUnlockedCells;
|
||||||
|
procedure TestWriteRead_BIFF8_WorksheetProtection_Objects;
|
||||||
|
|
||||||
|
procedure TestWriteRead_BIFF8_CellProtection;
|
||||||
|
|
||||||
{ OOXML protection tests }
|
{ OOXML protection tests }
|
||||||
procedure TestWriteRead_OOXML_WorkbookProtection_None;
|
procedure TestWriteRead_OOXML_WorkbookProtection_None;
|
||||||
procedure TestWriteRead_OOXML_WorkbookProtection_Struct;
|
procedure TestWriteRead_OOXML_WorkbookProtection_Struct;
|
||||||
procedure TestWriteRead_OOXML_WorkbookProtection_Win;
|
procedure TestWriteRead_OOXML_WorkbookProtection_Win;
|
||||||
procedure TestWriteRead_OOXML_WorkbookProtection_StructWin;
|
procedure TestWriteRead_OOXML_WorkbookProtection_StructWin;
|
||||||
|
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_None;
|
procedure TestWriteRead_OOXML_WorksheetProtection_Default;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_FormatCells;
|
procedure TestWriteRead_OOXML_WorksheetProtection_FormatCells;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_FormatColumns;
|
procedure TestWriteRead_OOXML_WorksheetProtection_FormatColumns;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_FormatRows;
|
procedure TestWriteRead_OOXML_WorksheetProtection_FormatRows;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_DeleteColumns;
|
procedure TestWriteRead_OOXML_WorksheetProtection_DeleteColumns;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_DeleteRows;
|
procedure TestWriteRead_OOXML_WorksheetProtection_DeleteRows;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_InsertColumns;
|
procedure TestWriteRead_OOXML_WorksheetProtection_InsertColumns;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_InsertRows;
|
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_InsertHyperlinks;
|
procedure TestWriteRead_OOXML_WorksheetProtection_InsertHyperlinks;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_Sheet;
|
procedure TestWriteRead_OOXML_WorksheetProtection_InsertRows;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_Sort;
|
procedure TestWriteRead_OOXML_WorksheetProtection_Sort;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_SelectLockedCells;
|
procedure TestWriteRead_OOXML_WorksheetProtection_SelectLockedCells;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_SelectUnlockedCells;
|
procedure TestWriteRead_OOXML_WorksheetProtection_SelectUnlockedCells;
|
||||||
procedure TestWriteRead_OOXML_WorksheetProtection_All;
|
procedure TestWriteRead_OOXML_WorksheetProtection_Objects;
|
||||||
|
|
||||||
procedure TestWriteRead_OOXML_CellProtection;
|
procedure TestWriteRead_OOXML_CellProtection;
|
||||||
|
|
||||||
|
{ ODS protection tests }
|
||||||
|
procedure TestWriteRead_ODS_WorkbookProtection_None;
|
||||||
|
procedure TestWriteRead_ODS_WorkbookProtection_Struct;
|
||||||
|
//procedure TestWriteRead_ODS_WorkbookProtection_Win;
|
||||||
|
//procedure TestWriteRead_ODS_WorkbookProtection_StructWin;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -126,8 +168,8 @@ const
|
|||||||
ALL_SHEET_PROTECTIONS = [
|
ALL_SHEET_PROTECTIONS = [
|
||||||
spFormatCells, spFormatColumns, spFormatRows,
|
spFormatCells, spFormatColumns, spFormatRows,
|
||||||
spDeleteColumns, spDeleteRows, spInsertColumns, spInsertRows,
|
spDeleteColumns, spDeleteRows, spInsertColumns, spInsertRows,
|
||||||
spInsertHyperlinks, spSort, spSelectLockedCells,
|
spInsertHyperlinks, spSort, spObjects,
|
||||||
spSelectUnlockedCells
|
spSelectLockedCells, spSelectUnlockedCells
|
||||||
]; // NOTE: spCells is handled separately
|
]; // NOTE: spCells is handled separately
|
||||||
var
|
var
|
||||||
MyWorkbook: TsWorkbook;
|
MyWorkbook: TsWorkbook;
|
||||||
@@ -141,6 +183,23 @@ begin
|
|||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
MyWorksheet := MyWorkBook.AddWorksheet(ProtectionSheet);
|
MyWorksheet := MyWorkBook.AddWorksheet(ProtectionSheet);
|
||||||
|
expected := DEFAULT_SHEET_PROTECTION;
|
||||||
|
case ACondition of
|
||||||
|
0: ;
|
||||||
|
1: Exclude(expected, spFormatCells);
|
||||||
|
2: Exclude(expected, spFormatColumns);
|
||||||
|
3: Exclude(expected, spFormatRows);
|
||||||
|
4: Exclude(expected, spDeleteColumns);
|
||||||
|
5: Exclude(expected, spDeleteRows);
|
||||||
|
6: Exclude(expected, spInsertColumns);
|
||||||
|
7: Exclude(expected, spInsertHyperlinks);
|
||||||
|
8: Exclude(expected, spInsertRows);
|
||||||
|
9: Exclude(expected, spSort);
|
||||||
|
10: Exclude(expected, spSelectLockedCells);
|
||||||
|
11: Exclude(expected, spSelectUnlockedCells);
|
||||||
|
12: Exclude(expected, spObjects);
|
||||||
|
end;
|
||||||
|
{
|
||||||
case ACondition of
|
case ACondition of
|
||||||
0: expected := [];
|
0: expected := [];
|
||||||
1: expected := [spFormatCells];
|
1: expected := [spFormatCells];
|
||||||
@@ -154,8 +213,10 @@ begin
|
|||||||
9: expected := [spSort];
|
9: expected := [spSort];
|
||||||
10: expected := [spSelectLockedCells];
|
10: expected := [spSelectLockedCells];
|
||||||
11: expected := [spSelectUnlockedCells];
|
11: expected := [spSelectUnlockedCells];
|
||||||
12: expected := ALL_SHEET_PROTECTIONS;
|
12: expected := [spObjects];
|
||||||
|
13: expected := ALL_SHEET_PROTECTIONS;
|
||||||
end;
|
end;
|
||||||
|
}
|
||||||
MyWorksheet.Protection := expected;
|
MyWorksheet.Protection := expected;
|
||||||
MyWorksheet.Protect(true);
|
MyWorksheet.Protect(true);
|
||||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
@@ -172,11 +233,11 @@ begin
|
|||||||
fail(msg + 'Sheet protection not active');
|
fail(msg + 'Sheet protection not active');
|
||||||
|
|
||||||
actual := MyWorksheet.Protection;
|
actual := MyWorksheet.Protection;
|
||||||
if actual <> [] then actual := actual - [spCells];
|
// if actual <> [] then actual := actual - [spCells];
|
||||||
msg := 'Test saved worksheet protection mismatch: ';
|
msg := 'Test saved worksheet protection mismatch: ';
|
||||||
if actual <> expected then
|
if actual <> expected then
|
||||||
case ACondition of
|
case ACondition of
|
||||||
0: fail(msg + 'no protection');
|
0: fail(msg + 'default protection');
|
||||||
1: fail(msg + 'spFormatCells');
|
1: fail(msg + 'spFormatCells');
|
||||||
2: fail(msg + 'spFormatColumns');
|
2: fail(msg + 'spFormatColumns');
|
||||||
3: fail(msg + 'spFormatRows');
|
3: fail(msg + 'spFormatRows');
|
||||||
@@ -188,7 +249,7 @@ begin
|
|||||||
9: fail(msg + 'spSort');
|
9: fail(msg + 'spSort');
|
||||||
10: fail(msg + 'spSelectLockedCells');
|
10: fail(msg + 'spSelectLockedCells');
|
||||||
11: fail(msg + 'spSelectUnlockedCells');
|
11: fail(msg + 'spSelectUnlockedCells');
|
||||||
12: fail(msg + 'all options');
|
12: fail(msg + 'spObjects');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@@ -212,17 +273,19 @@ begin
|
|||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
MyWorksheet := MyWorkBook.AddWorksheet(ProtectionSheet);
|
MyWorksheet := MyWorkBook.AddWorksheet(ProtectionSheet);
|
||||||
|
// A1 --> lock cell
|
||||||
cell := Myworksheet.WriteText(0, 0, 'Protected');
|
cell := Myworksheet.WriteText(0, 0, 'Protected');
|
||||||
MyWorksheet.WriteCellProtection(cell, [cpLockCell]);
|
MyWorksheet.WriteCellProtection(cell, [cpLockCell]);
|
||||||
|
// B1 --> not protected at all
|
||||||
cell := MyWorksheet.WriteText(1, 0, 'Not protected');
|
cell := MyWorksheet.WriteText(1, 0, 'Not protected');
|
||||||
MyWorksheet.WriteCellProtection(cell, []);
|
MyWorksheet.WriteCellProtection(cell, []);
|
||||||
|
// A2 --> lock cell & hide formulas
|
||||||
cell := Myworksheet.WriteFormula(0, 1, '=A1');
|
cell := Myworksheet.WriteFormula(0, 1, '=A1');
|
||||||
MyWorksheet.WriteCellProtection(cell, [cpLockCell, cpHideFormulas]);
|
MyWorksheet.WriteCellProtection(cell, [cpLockCell, cpHideFormulas]);
|
||||||
|
// B2 --> hide formula only
|
||||||
cell := MyWorksheet.WriteFormula(1, 1, '=A2');
|
cell := MyWorksheet.WriteFormula(1, 1, '=A2');
|
||||||
Myworksheet.WriteCellProtection(Cell, [cpHideFormulas]);
|
Myworksheet.WriteCellProtection(Cell, [cpHideFormulas]);
|
||||||
MyWorksheet.Protect(true);
|
MyWorksheet.Protect(true);
|
||||||
// NOTE: FPSpreadsheet does not enforce these actions. They are only written
|
|
||||||
// to the file for the Office application.
|
|
||||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
finally
|
finally
|
||||||
MyWorkbook.Free;
|
MyWorkbook.Free;
|
||||||
@@ -271,7 +334,153 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ Tests for OOXML file format }
|
{------------------------------------------------------------------------------}
|
||||||
|
{ Tests for BIFF2 file format }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorkbookProtection_None;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel2, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorkbookProtection_Struct;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel2, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorkbookProtection_Win;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel2, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorkbookProtection_StructWin;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel2, 3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorksheetProtection_Default;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel2, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_WorksheetProtection_Objects;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel2, 12);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF2_CellProtection;
|
||||||
|
begin
|
||||||
|
TestWriteRead_CellProtection(sfExcel2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ Tests for BIFF5 file format }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorkbookProtection_None;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel5, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorkbookProtection_Struct;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel5, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorkbookProtection_Win;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel5, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorkbookProtection_StructWin;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel5, 3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorksheetProtection_Default;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel5, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorksheetProtection_SelectLockedCells;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel5, 10);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorksheetProtection_SelectUnlockedCells;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel5, 11);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_WorksheetProtection_Objects;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel5, 12);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF5_CellProtection;
|
||||||
|
begin
|
||||||
|
TestWriteRead_CellProtection(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ Tests for BIFF8 file format }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorkbookProtection_None;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel8, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorkbookProtection_Struct;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel8, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorkbookProtection_Win;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel8, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorkbookProtection_StructWin;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfExcel8, 3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorksheetProtection_Default;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel8, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorksheetProtection_SelectLockedCells;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel8, 10);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorksheetProtection_SelectUnlockedCells;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel8, 11);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_WorksheetProtection_Objects;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorksheetProtection(sfExcel8, 12);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_BIFF8_CellProtection;
|
||||||
|
begin
|
||||||
|
TestWriteRead_CellProtection(sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ Tests for OOXML file format }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorkbookProtection_None;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorkbookProtection_None;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorkbookProtection(sfOOXML, 0);
|
TestWriteRead_WorkbookProtection(sfOOXML, 0);
|
||||||
@@ -292,7 +501,7 @@ begin
|
|||||||
TestWriteRead_WorkbookProtection(sfOOXML, 3);
|
TestWriteRead_WorkbookProtection(sfOOXML, 3);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_None;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_Default;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 0);
|
TestWriteRead_WorksheetProtection(sfOOXML, 0);
|
||||||
end;
|
end;
|
||||||
@@ -327,46 +536,67 @@ begin
|
|||||||
TestWriteRead_WorksheetProtection(sfOOXML, 6);
|
TestWriteRead_WorksheetProtection(sfOOXML, 6);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_InsertRows;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_InsertHyperlinks;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 7);
|
TestWriteRead_WorksheetProtection(sfOOXML, 7);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_InsertHyperlinks;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_InsertRows;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 8);
|
TestWriteRead_WorksheetProtection(sfOOXML, 8);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_Sheet;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_Sort;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 9);
|
TestWriteRead_WorksheetProtection(sfOOXML, 9);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_Sort;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_SelectLockedCells;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 10);
|
TestWriteRead_WorksheetProtection(sfOOXML, 10);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_SelectLockedCells;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_SelectUnlockedCells;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 11);
|
TestWriteRead_WorksheetProtection(sfOOXML, 11);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_SelectUnlockedCells;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_Objects;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 12);
|
TestWriteRead_WorksheetProtection(sfOOXML, 12);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_WorksheetProtection_All;
|
|
||||||
begin
|
|
||||||
TestWriteRead_WorksheetProtection(sfOOXML, 13);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_CellProtection;
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_OOXML_CellProtection;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_CellProtection(sfOOXML);
|
TestWriteRead_CellProtection(sfOOXML);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ Tests for OpenDocument file format }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorkbookProtection_None;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfOpenDocument, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorkbookProtection_Struct;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfOpenDocument, 1);
|
||||||
|
end;
|
||||||
|
{
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorkbookProtection_Win;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfOpenDocument, 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadProtectionTests.TestWriteRead_ODS_WorkbookProtection_StructWin;
|
||||||
|
begin
|
||||||
|
TestWriteRead_WorkbookProtection(sfOpenDocument, 3);
|
||||||
|
end;}
|
||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterTest(TSpreadWriteReadProtectionTests);
|
RegisterTest(TSpreadWriteReadProtectionTests);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user