You've already forked lazarus-ccr
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:
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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}
|
||||||
|
@ -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 := '';
|
||||||
|
Reference in New Issue
Block a user