fpspreadsheet: Add reading of conditional formats for xlsx. Not complete, and still fragile.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7526 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-07-05 22:45:12 +00:00
parent 3189f58ee5
commit 9bc1afa59b
4 changed files with 454 additions and 89 deletions

View File

@ -11,8 +11,9 @@ spreadsheet documents in various formats:
- Comma-separated text files - Comma-separated text files
- html files - html files
- wikimedia wikitable formats - wikimedia wikitable formats
- there is also a demo file showing how to install user-defined readers/writers - the user can register his own readers/writers for other formats. An example
for other formats (.slk). is shown in the "spready" application for the .slk format.
("spready" is in the applications folder of CCR).
The library is written in a very flexible manner, capable of being extended to The library is written in a very flexible manner, capable of being extended to
support any number of formats easily. support any number of formats easily.

View File

@ -305,8 +305,8 @@ var
begin begin
rule := TsCFCellRule.Create; rule := TsCFCellRule.Create;
rule.Condition := ACondition; rule.Condition := ACondition;
rule.Operand1 := varNull; VarClear(rule.Operand1);
rule.Operand2 := varNull; VarClear(rule.Operand2);
rule.FormatIndex := ACellFormatIndex; rule.FormatIndex := ACellFormatIndex;
Result := AddRule(ASheet, ARange, rule); Result := AddRule(ASheet, ARange, rule);
end; end;
@ -320,7 +320,7 @@ begin
rule := TsCFCellRule.Create; rule := TsCFCellRule.Create;
rule.Condition := ACondition; rule.Condition := ACondition;
rule.Operand1 := AParam; rule.Operand1 := AParam;
rule.Operand2 := varNull; VarClear(rule.Operand2);
rule.FormatIndex := ACellFormatIndex; rule.FormatIndex := ACellFormatIndex;
Result := AddRule(ASheet, ARange, rule); Result := AddRule(ASheet, ARange, rule);
end; end;

View File

@ -83,6 +83,8 @@ type
protected protected
{@@ list of format records collected from the file } {@@ list of format records collected from the file }
FCellFormatList: TsCellFormatList; FCellFormatList: TsCellFormatList;
{@@ list for differential formats needed by conditional formatting}
FDifferentialFormatList: TFPList;
{@@ List of fonts collected from the file } {@@ List of fonts collected from the file }
FFontList: TFPList; FFontList: TFPList;
{@@ Temporary cell for virtual mode} {@@ Temporary cell for virtual mode}

View File

@ -59,6 +59,7 @@ type
FBorderList: TFPList; FBorderList: TFPList;
FHyperlinkList: TFPList; FHyperlinkList: TFPList;
FSharedFormulaBaseList: TFPList; FSharedFormulaBaseList: TFPList;
FDxfList: TFPList;
FPalette: TsPalette; FPalette: TsPalette;
FThemeColors: array of TsColor; FThemeColors: array of TsColor;
FLastRow, FLastCol: Cardinal; FLastRow, FLastCol: Cardinal;
@ -68,15 +69,20 @@ type
function FindCommentsFileName(ANode: TDOMNode): String; function FindCommentsFileName(ANode: TDOMNode): String;
procedure ReadActiveSheet(ANode: TDOMNode; out ActiveSheetIndex: Integer); procedure ReadActiveSheet(ANode: TDOMNode; out ActiveSheetIndex: Integer);
procedure ReadBorders(ANode: TDOMNode); procedure ReadBorders(ANode: TDOMNode);
function ReadBorderStyle(ANode: TDOMNode; out ABorderStyle: TsCellBorderStyle): Boolean;
procedure ReadCell(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; procedure ReadCell(ANode: TDOMNode; AWorksheet: TsBasicWorksheet;
ARowIndex: Cardinal; var AColIndex: Cardinal); ARowIndex: Cardinal; var AColIndex: Cardinal);
procedure ReadCellXfs(ANode: TDOMNode); procedure ReadCellXfs(ANode: TDOMNode);
procedure ReadCFRule(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; ARange: TsCellRange);
procedure ReadColRowBreaks(ANode: TDOMNode; AWorksheet: TsBasicWorksheet); procedure ReadColRowBreaks(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
function ReadColor(ANode: TDOMNode): TsColor; function ReadColor(ANode: TDOMNode): TsColor;
procedure ReadCols(ANode: TDOMNode; AWorksheet: TsBasicWorksheet); procedure ReadCols(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
procedure ReadComments(ANode: TDOMNode; AWorksheet: TsBasicWorksheet); procedure ReadComments(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
procedure ReadConditionalFormatting(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
procedure ReadDateMode(ANode: TDOMNode); procedure ReadDateMode(ANode: TDOMNode);
procedure ReadDefinedNames(ANode: TDOMNode); procedure ReadDefinedNames(ANode: TDOMNode);
procedure ReadDifferentialFormat(ANode: TDOMNode);
procedure ReadDifferentialFormats(ANode: TDOMNode);
procedure ReadDimension(ANode: TDOMNode; AWorksheet: TsBasicWorksheet); procedure ReadDimension(ANode: TDOMNode; AWorksheet: TsBasicWorksheet);
procedure ReadFileVersion(ANode: TDOMNode); procedure ReadFileVersion(ANode: TDOMNode);
procedure ReadFills(ANode: TDOMNode); procedure ReadFills(ANode: TDOMNode);
@ -330,6 +336,16 @@ type
end; end;
TDifferentialFormatData = class TDifferentialFormatData = class
CellFormatIndex: Integer;
UsedFormattingFields: TsUsedFormattingFields;
Borders: TsCellBorders;
BorderStyles: TsCellBorderStyles;
FillPatternType: TsFillStyle;
FillFgColor: TsColor;
FillBgColor: TsColor;
FontColor: TsColor;
FontStyles: TsFontStyles;
NumFormatStr: String;
end; end;
THyperlinkListData = class THyperlinkListData = class
@ -394,6 +410,66 @@ const
'slantDashDot' // lsSlantDashDot 'slantDashDot' // lsSlantDashDot
); );
CF_TYPE_NAMES: array[TsCFCondition] of String = (
'cellIs', 'cellIs', // cfcEqual, cfcNotEqual,
'cellIs', 'cellIs', 'cellIs', 'cellIs', // cfcGreaterThan, cfcLessThan, cfcGreaterEqual, cfcLessEqual,
'cellIs', 'cellIs', // cfcBetween, cfcNotBetween,
'aboveAverage', 'aboveAverage', 'aboveAverage', 'aboveAverage', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage,
'top10', 'top10', 'top10', 'top10', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'duplicateValues', 'uniqueValues', // cfcDuplicate, cfcUnique,
'beginsWith', 'endsWith', // cfcBeginsWith, cfcEndsWith,
'containsText', 'notContainsText', // cfcContainsText, cfcNotContainsText,
'containsErrors', 'notContainsErrors' // cfcContainsErrors, cfcNotContainsErrors
);
CF_OPERATOR_NAMES: array[TsCFCondition] of string = (
'equal', 'notEqual', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual',
'between', 'notBetween',
'', '', '', '', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage,
'', '', '', '', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'', '', // cfcDuplicate, cfcUnique,
'', '', '', 'notContains', //cfcBeginsWith, cfcEndsWith, cfcContainsText, cfcNotContainsText,
'', '' // cfcContainsErrors, cfcNotContainsErrors
);
function StrToFillStyle(s: String): TsFillStyle;
var
fs: TsFillStyle;
begin
if s = '' then
begin
Result := fsSolidFill;
exit;
end;
for fs in TsFillStyle do
if PATTERN_TYPES[fs] = s then
begin
Result := fs;
exit;
end;
Result := fsNoFill;
end;
function StrToLineStyle(s: String): TsLineStyle;
var
ls: TsLineStyle;
begin
if s = '' then
begin
Result := lsThin;
exit;
end;
for ls in TsLineStyle do
if LINESTYLE_TYPES[ls] = s then
begin
Result := ls;
exit;
end;
Result := lsThin;
end;
function CFOperandToStr(v: Variant): String; function CFOperandToStr(v: Variant): String;
const const
ERR = cardinal(-1); ERR = cardinal(-1);
@ -468,6 +544,7 @@ begin
FBorderList := TFPList.Create; FBorderList := TFPList.Create;
FHyperlinkList := TFPList.Create; FHyperlinkList := TFPList.Create;
FCellFormatList := TsCellFormatList.Create(true); FCellFormatList := TsCellFormatList.Create(true);
FDifferentialFormatList := TFPList.Create;
// Allow duplicates because xf indexes used in cell records cannot be found any more. // Allow duplicates because xf indexes used in cell records cannot be found any more.
FSharedFormulaBaseList := TFPList.Create; FSharedFormulaBaseList := TFPList.Create;
@ -495,6 +572,10 @@ begin
TObject(FHyperlinkList[j]).Free; TObject(FHyperlinkList[j]).Free;
FHyperlinkList.Free; FHyperlinkList.Free;
for j := FDifferentialFormatList.Count-1 downto 0 do
TObject(FDifferentialFormatList[j]).Free;
FDifferentialFormatList.Free;
for j := FSheetList.Count-1 downto 0 do for j := FSheetList.Count-1 downto 0 do
TObject(FSheetList[j]).Free; TObject(FSheetList[j]).Free;
FSheetList.Free; FSheetList.Free;
@ -613,59 +694,6 @@ begin
end; end;
procedure TsSpreadOOXMLReader.ReadBorders(ANode: TDOMNode); procedure TsSpreadOOXMLReader.ReadBorders(ANode: TDOMNode);
function ReadBorderStyle(ANode: TDOMNode;
out ABorderStyle: TsCellBorderStyle): Boolean;
var
s: String;
colorNode: TDOMNode;
nodeName: String;
begin
Result := false;
ABorderStyle.LineStyle := lsThin;
ABorderStyle.Color := scBlack;
s := GetAttrValue(ANode, 'style');
if (s = '') or (s = 'none') then
exit;
if s = 'thin' then
ABorderStyle.LineStyle := lsThin
else if s = 'medium'then
ABorderStyle.LineStyle := lsMedium
else if s = 'thick' then
ABorderStyle.LineStyle := lsThick
else if s = 'dotted' then
ABorderStyle.LineStyle := lsDotted
else if s = 'dashed' then
ABorderStyle.LineStyle := lsDashed
else if s = 'double' then
ABorderStyle.LineStyle := lsDouble
else if s = 'hair' then
ABorderStyle.LineStyle := lsHair
else if s = 'dashDot' then
ABorderStyle.LineStyle := lsDashDot
else if s = 'dashDotDot' then
ABorderStyle.LineStyle := lsDashDotDot
else if s = 'mediumDashed' then
ABorderStyle.LineStyle := lsMediumDash
else if s = 'mediumDashDot' then
ABorderStyle.LineSTyle := lsMediumDashDot
else if s = 'mediumDashDotDot' then
ABorderStyle.LineStyle := lsMediumDashDotDot
else if s = 'slantDashDot' then
ABorderStyle.LineStyle := lsSlantDashDot;
colorNode := ANode.FirstChild;
while Assigned(colorNode) do begin
nodeName := colorNode.NodeName;
if (nodeName = 'color') or (nodename = 'x:color') then
ABorderStyle.Color := ReadColor(colorNode);
colorNode := colorNode.NextSibling;
end;
Result := true;
end;
var var
borderNode: TDOMNode; borderNode: TDOMNode;
edgeNode: TDOMNode; edgeNode: TDOMNode;
@ -727,6 +755,61 @@ begin
end; end;
end; end;
function TsSpreadOOXMLReader.ReadBorderStyle(ANode: TDOMNode;
out ABorderStyle: TsCellBorderStyle): Boolean;
var
s: String;
colorNode: TDOMNode;
nodeName: String;
begin
Result := false;
ABorderStyle.LineStyle := lsThin;
ABorderStyle.Color := scBlack;
s := GetAttrValue(ANode, 'style');
if (s = '') or (s = 'none') then
exit;
ABorderStyle.LineStyle := StrToLineStyle(s);
{
if s = 'thin' then
ABorderStyle.LineStyle := lsThin
else if s = 'medium'then
ABorderStyle.LineStyle := lsMedium
else if s = 'thick' then
ABorderStyle.LineStyle := lsThick
else if s = 'dotted' then
ABorderStyle.LineStyle := lsDotted
else if s = 'dashed' then
ABorderStyle.LineStyle := lsDashed
else if s = 'double' then
ABorderStyle.LineStyle := lsDouble
else if s = 'hair' then
ABorderStyle.LineStyle := lsHair
else if s = 'dashDot' then
ABorderStyle.LineStyle := lsDashDot
else if s = 'dashDotDot' then
ABorderStyle.LineStyle := lsDashDotDot
else if s = 'mediumDashed' then
ABorderStyle.LineStyle := lsMediumDash
else if s = 'mediumDashDot' then
ABorderStyle.LineSTyle := lsMediumDashDot
else if s = 'mediumDashDotDot' then
ABorderStyle.LineStyle := lsMediumDashDotDot
else if s = 'slantDashDot' then
ABorderStyle.LineStyle := lsSlantDashDot;
}
colorNode := ANode.FirstChild;
while Assigned(colorNode) do begin
nodeName := colorNode.NodeName;
if (nodeName = 'color') or (nodename = 'x:color') then
ABorderStyle.Color := ReadColor(colorNode);
colorNode := colorNode.NextSibling;
end;
Result := true;
end;
procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode; procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode;
AWorksheet: TsBasicWorksheet; ARowIndex: Cardinal; var AColIndex: Cardinal); AWorksheet: TsBasicWorksheet; ARowIndex: Cardinal; var AColIndex: Cardinal);
var var
@ -1152,6 +1235,101 @@ begin
end; end;
end; end;
procedure TsSpreadOOXMLReader.ReadCFRule(ANode: TDOMNode; AWorksheet: TsBasicWorksheet;
ARange: TsCellRange);
var
nodeName: String;
s, sType, sOp: String;
sFormula: Array of String;
cf: TsCFCondition;
found: Boolean;
i: Integer;
n: Integer;
x: Double;
r, c: Cardinal;
dxf: TDifferentialFormatData;
dxfId: Integer;
condition: TsCFCondition;
values: array of Variant;
fmtIdx: Integer;
sheet: TsWorksheet;
begin
sheet := TsWorksheet(AWorksheet);
found := false;
sType := GetAttrValue(ANode, 'type');
sOp := GetAttrValue(ANode, 'operator');
if sType = 'cellIs' then
begin
for cf in TsCFCondition do
if sOp = CF_OPERATOR_NAMES[cf] then
begin
found := true;
condition := cf;
break;
end
end
else
for cf in TsCFCondition do
if sType = CF_TYPE_NAMES[cf] then
begin
found := true;
condition := cf;
break;
end;
if not found then
exit;
s := GetAttrValue(ANode, 'dxfId');
if not TryStrToInt(s, dxfId) then
exit;
dxf := TDifferentialFormatData(FDifferentialFormatList[dxfId]);
fmtIdx := dxf.CellFormatIndex;
SetLength(sFormula, 0);
ANode := ANode.FirstChild;
while (ANode <> nil) do
begin
nodeName := ANode.NodeName;
if nodeName = 'formula' then
begin
SetLength(sFormula, Length(sFormula) + 1);
sFormula[High(sFormula)] := GetNodeValue(ANode);
end;
ANode := ANode.NextSibling;
end;
if condition in [cfcEqual..cfcNotBetween] then begin
SetLength(values, Length(sFormula));
for i := 0 to High(sFormula) do begin
values[i] := sFormula[i];
if (sFormula[i] <> '') then begin
if TryStrToInt(sFormula[i], n) then
values[i] := n
else if TryStrToFloat(sFormula[i], x, FPointSeparatorSettings) then
values[i] := x
else if sFormula[i][1] = '"' then
values[i] := sFormula[i]
else if ParseCellString(sFormula[i], r, c) then
values[i] := sFormula[i]
else
values[i] := '=' + sFormula[i];
end;
end;
end else
exit;
case Length(values) of
0: sheet.WriteConditionalCellFormat(ARange, condition, fmtIdx);
1: sheet.WriteConditionalCellFormat(ARange, condition, values[0], fmtIdx);
2: sheet.WriteConditionalCellFormat(ARange, condition, values[0], values[1], fmtIdx);
end;
end;
procedure TsSpreadOOXMLReader.ReadColRowBreaks(ANode: TDOMNode; procedure TsSpreadOOXMLReader.ReadColRowBreaks(ANode: TDOMNode;
AWorksheet: TsBasicWorksheet); AWorksheet: TsBasicWorksheet);
var var
@ -1391,6 +1569,36 @@ begin
end; end;
end; end;
procedure TsSpreadOOXMLReader.ReadConditionalFormatting(ANode: TDOMNode;
AWorksheet: TsBasicWorksheet);
var
childNode: TDOMNode;
nodeName: string;
range: TsCellRange;
s: String;
begin
while ANode <> nil do
begin
nodeName := ANode.NodeName;
if (nodeName = 'conditionalFormatting') then
begin
s := GetAttrValue(ANode, 'sqref');
if ParseCellRangeString(s, range) then
begin
childNode := ANode.FirstChild;
while childNode <> nil do
begin
nodeName := childNode.NodeName;
if nodeName = 'cfRule' then
ReadCFRule(childNode, AWorksheet, range);
childNode := childNode.NextSibling;
end;
end;
end;
ANode := ANode.NextSibling;
end;
end;
procedure TsSpreadOOXMLReader.ReadDateMode(ANode: TDOMNode); procedure TsSpreadOOXMLReader.ReadDateMode(ANode: TDOMNode);
var var
s: String; s: String;
@ -1503,6 +1711,186 @@ begin
end; end;
end; end;
procedure TsSpreadOOXMLReader.ReadDifferentialFormat(ANode: TDOMNode);
var
nodeName: String;
childNode: TDOMNode;
pattNode: TDOMNode;
s: String;
fontStyles: TsFontStyles;
fontColor: TsColor;
bgColor: TsColor;
fgColor: TsColor;
fillPatt: String;
borders: TsCellBorders;
borderStyles: TsCellBorderStyles;
uff: TsUsedFormattingFields;
dxf: TDifferentialFormatData;
fmt: TsCellFormat;
numFmtStr: String;
begin
uff := [];
borders := [];
fontStyles := [];
fontColor := scNotDefined;
numFmtStr := '';
ANode := ANode.FirstChild;
while ANode <> nil do
begin
nodeName := ANode.NodeName;
if nodeName = 'font' then
begin
// read font
uff := uff + [uffFont];
childNode := ANode.FirstChild;
while childNode <> nil do
begin
nodeName := childNode.NodeName;
if (nodename = 'b') then
fontStyles := fontStyles + [fssBold]
else
if (nodename = 'i') then
fontStyles := fontStyles + [fssItalic]
else
if (nodeName = 'strike') then
fontStyles := fontStyles + [fssStrikeOut]
else
if (nodename = 'color') then
fontColor := ReadColor(childNode);
childNode := childNode.NextSibling;
end;
end else
if nodeName = 'border' then
begin
// read border
uff := uff + [uffBorder];
childNode := ANode.FirstChild;
while childNode <> nil do
begin
nodeName := childNode.NodeName;
if nodeName = 'left' then
begin
borders := borders + [cbWest];
ReadBorderStyle(childNode, borderStyles[cbWest]);
end else
if nodeName = 'top' then
begin
borders := borders + [cbNorth];
ReadBorderStyle(childNode, borderStyles[cbNorth]);
end else
if nodeName = 'right' then
begin
borders := borders + [cbEast];
ReadBorderStyle(childNode, borderStyles[cbEast]);
end else
if nodeName = 'bottom' then
begin
borders := borders + [cbSouth];
ReadBorderStyle(childNode, borderStyles[cbSouth]);
end;
childNode := childNode.NextSibling;
end;
end else
if nodeName = 'fill' then
begin
// read fill
uff := uff + [uffBackground];
pattNode := ANode.FirstChild;
while pattNode <> nil do begin
nodeName := pattNode.NodeName;
if nodeName = 'patternFill' then
begin
fillPatt := GetAttrValue(pattNode, 'patternType');
childNode := pattNode.FirstChild;
while childNode <> nil do
begin
nodeName := childNode.NodeName;
if nodeName = 'bgColor' then
bgColor := ReadColor(childNode)
else if nodeName = 'fgColor' then
fgColor := ReadColor(childNode);
childNode := childNode.NextSibling;
end;
end;
pattNode := pattNode.NextSibling;
end;
{
fillPatt := GetAttrValue(ANode, 'patternType');
childNode := ANode.FirstChild;
while childNode <> nil do begin
nodeName := childNode.NodeName;
if nodeName = 'bgColor' then
bgColor := ReadColor(childNode)
else
if nodeName ='fgColor' then
fgColor := ReadColor(childNode);
childNode := childNode.NextSibling;
end;
}
end else
if nodeName = 'numFmt' then
begin
// Nuzmber format
uff := uff + [uffNumberFormat];
numFmtStr := GetAttrValue(ANode, 'formatCode');
end;
ANode := ANode.NextSibling;
end;
InitFormatRecord(fmt);
if uff <> [] then
begin
dxf := TDifferentialFormatData.Create;
dxf.UsedFormattingFields := uff;
fmt.UsedFormattingFields := uff;
if (uffBackground in uff) then
begin
dxf.FillPatternType := StrToFillStyle(fillPatt);
dxf.FillBgColor := bgColor;
dxf.FillFgColor := fgColor;
fmt.SetBackground(dxf.FillPatternType, dxf.FillFgColor, dxf.FillBgColor);
end;
if (uffBorder in uff) then
begin
dxf.Borders := borders;
dxf.BorderStyles := borderStyles;
fmt.Border := borders;
fmt.BorderStyles := borderStyles;
end;
if (uffFont in uff) then
begin
dxf.FontColor := fontColor;
dxf.FontStyles := fontStyles;
fmt.FontIndex := TsWorkbook(FWorkbook).AddFont('', -1, fontStyles, fontColor);
end else
if (uffNumberFormat in uff) then
begin
dxf.NumFormatStr := numFmtStr;
fmt.NumberFormatStr := numFmtStr;
fmt.NumberFormatIndex := TsWorkbook(FWorkbook).AddNumberFormat(numFmtStr);
end;
dxf.CellFormatIndex := TsWorkbook(FWorkbook).AddCellFormat(fmt);
FDifferentialFormatList.Add(dxf);
end;
end;
procedure TsSpreadOOXMLReader.ReadDifferentialFormats(ANode: TDOMNode);
var
nodeName: String;
begin
if ANode = nil then
exit;
ANode := ANode.FirstChild;
while ANode <> nil do
begin
nodeName := ANode.NodeName;
if nodeName = 'dxf' then
ReadDifferentialFormat(ANode);
ANode := ANode.NextSibling;
end;
end;
procedure TsSpreadOOXMLReader.ReadDimension(ANode: TDOMNode; procedure TsSpreadOOXMLReader.ReadDimension(ANode: TDOMNode;
AWorksheet: TsBasicWorksheet); AWorksheet: TsBasicWorksheet);
var var
@ -2790,6 +3178,7 @@ begin
ReadBorders(Doc_FindNode('borders')); ReadBorders(Doc_FindNode('borders'));
ReadNumFormats(Doc_FindNode('numFmts')); ReadNumFormats(Doc_FindNode('numFmts'));
ReadCellXfs(Doc_FindNode('cellXfs')); ReadCellXfs(Doc_FindNode('cellXfs'));
ReadDifferentialFormats(DOC_FindNode('dxfs'));
FreeAndNil(Doc); FreeAndNil(Doc);
end; end;
finally finally
@ -2844,6 +3233,7 @@ begin
ReadSheetFormatPr(Doc_FindNode('sheetFormatPr'), FWorksheet); ReadSheetFormatPr(Doc_FindNode('sheetFormatPr'), FWorksheet);
ReadCols(Doc_FindNode('cols'), FWorksheet); ReadCols(Doc_FindNode('cols'), FWorksheet);
ReadWorksheet(Doc_FindNode('sheetData'), FWorksheet); ReadWorksheet(Doc_FindNode('sheetData'), FWorksheet);
ReadConditionalFormatting(Doc_FindNode('conditionalFormatting'), FWorksheet);
ReadSheetProtection(Doc_FindNode('sheetProtection'), FWorksheet); ReadSheetProtection(Doc_FindNode('sheetProtection'), FWorksheet);
ReadMergedCells(Doc_FindNode('mergeCells'), FWorksheet); ReadMergedCells(Doc_FindNode('mergeCells'), FWorksheet);
ReadHyperlinks(Doc_FindNode('hyperlinks'), FWorksheet); ReadHyperlinks(Doc_FindNode('hyperlinks'), FWorksheet);
@ -3382,34 +3772,6 @@ end;
procedure TsSpreadOOXMLWriter.WriteConditionalFormatCellRule(AStream: TStream; procedure TsSpreadOOXMLWriter.WriteConditionalFormatCellRule(AStream: TStream;
ARule: TsCFCellRule; ARange: TsCellRange; APriority: Integer); ARule: TsCFCellRule; ARange: TsCellRange; APriority: Integer);
const const
TYPE_NAMES: array[TsCFCondition] of String = (
'cellIs', 'cellIs', // cfcEqual, cfcNotEqual,
'cellIs', 'cellIs', 'cellIs', 'cellIs', // cfcGreaterThan, cfcLessThan, cfcGreaterEqual, cfcLessEqual,
'cellIs', 'cellIs', // cfcBetween, cfcNotBetween,
'aboveAverage', 'aboveAverage', 'aboveAverage', 'aboveAverage', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage,
'top10', 'top10', 'top10', 'top10', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'duplicateValues', 'uniqueValues', // cfcDuplicate, cfcUnique,
'beginsWith', 'endsWith', // cfcBeginsWith, cfcEndsWith,
'containsText', 'notContainsText', // cfcContainsText, cfcNotContainsText,
'containsErrors', 'notContainsErrors' // cfcContainsErrors, cfcNotContainsErrors
);
OPERATOR_NAMES: array[TsCFCondition] of string = (
'equal', 'notEqual', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual',
'between', 'notBetween',
'', '', '', '', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage,
'', '', '', '', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'', '', // cfcDuplicate, cfcUnique,
'', '', '', 'notContains', //cfcBeginsWith, cfcEndsWith, cfcContainsText, cfcNotContainsText,
'', '' // cfcContainsErrors, cfcNotContainsErrors
);
{
OPERATOR_NAMES_1: array[cfcEqual..cfcLessEqual] of String =
('equal', 'notEqual', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual');
OPERATOR_NAMES_2: array[cfcBetween..cfcNotBetween] of String =
('between', 'notBetween');
TYPE_NAMES: array[cfcBeginsWith..cfcNotContainsErrors] of String =
('beginsWith', 'endsWith', 'containsText', 'notContainsText', 'containsErrors', 'notContainsErrors');
}
FORMULA: array[cfcBeginsWith..cfcNotContainsErrors] of String = ( FORMULA: array[cfcBeginsWith..cfcNotContainsErrors] of String = (
'LEFT(%0:s,LEN("%1:s"))="%1:s"', // cfcBeginsWith 'LEFT(%0:s,LEN("%1:s"))="%1:s"', // cfcBeginsWith
'RIGHT(%0:s,Len("%1:s"))="%1:s"', // cfcEndsWidth 'RIGHT(%0:s,Len("%1:s"))="%1:s"', // cfcEndsWidth
@ -3433,11 +3795,11 @@ begin
break; break;
end; end;
typeStr := TYPE_NAMES[ARule.Condition]; typeStr := CF_TYPE_NAMES[ARule.Condition];
if OPERATOR_NAMES[ARule.Condition] = '' then if CF_OPERATOR_NAMES[ARule.Condition] = '' then
opStr := '' opStr := ''
else else
opStr := ' operator="' + OPERATOR_NAMES[ARule.Condition] + '"'; opStr := ' operator="' + CF_OPERATOR_NAMES[ARule.Condition] + '"';
formula1Str := ''; formula1Str := '';
formula2Str := ''; formula2Str := '';
param1Str := ''; param1Str := '';