fpspreadsheet: Support expression conditional cell formatting by XLSX, Excel-XML and ODS writers.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7541 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-07-15 16:39:05 +00:00
parent 4a9dced270
commit 269c684533
5 changed files with 65 additions and 20 deletions

View File

@ -265,6 +265,15 @@ begin
fmtIdx := wb.AddCellFormat(fmt);
sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsErrors, fmtIdx);
// conditional format: expression
inc(row);
sh.WriteText(row, 0, 'expression: ISNUMBER($E$5)');
sh.WriteText(row, 1, 'background blue');
InitFormatRecord(fmt);
fmt.SetBackgroundColor(scBlue);
fmtIdx := wb.AddCellFormat(fmt);
sh.WriteConditionalCellFormat(Range(row, 2, row, 2), cfcExpression, '=ISNUMBER($E$5)', fmtIdx);
// Two rules in the same conditional format
inc(row);
sh.WriteText(row, 0, 'Two rules: #1: equal to 5, #2: equal to 3');

View File

@ -23,7 +23,8 @@ type
cfcDuplicate, cfcUnique,
cfcBeginsWith, cfcEndsWith,
cfcContainsText, cfcNotContainsText,
cfcContainsErrors, cfcNotContainsErrors
cfcContainsErrors, cfcNotContainsErrors,
cfcExpression
);
TsCFCellRule = class(TsCFRule)

View File

@ -388,26 +388,28 @@ const
'cell-content()>%s', 'cell-content()<%s', //cfcGreaterThan, cfcLessThan
'cell-content()>=%s', 'cell-content<=%s', // cfcGreaterEqual, cfdLessEqual
'cell-is-between(%s,%s)', 'cell-is-not-between(%s,%s)', // cfcBetween, cfcNotBetween,
'', '', '', '', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage
'', '', '', '', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'', '', // cfcDuplicate, cfcUnique,
'', '', '', '', // cfcBeginsWith, cfcEndsWith, cfcContainsText, cfcNotContainsText,
'', '' // cfcContainsErrors, cfcNotContainsErrors
'', '', '', '', // cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage
'', '', '', '', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'', '', // cfcDuplicate, cfcUnique,
'', '', '', '', // cfcBeginsWith, cfcEndsWith, cfcContainsText, cfcNotContainsText,
'', '', // cfcContainsErrors, cfcNotContainsErrors
'is-true-formula(%s)' // cfcExpression
);
CF_CALCEXT_OP: array[TsCFCondition] of string = (
'=%s', '!=%s', // cfcEqual, cfcNotEqual
'>%s', '<%s', //cfcGreaterThan, cfcLessThan
'>=%s', '<=%s', // cfcGreaterEqual, cfdLessEqual
'between(%s,%s)', 'not-between(%s,%s)', // cfcBetween, cfcNotBetween,
'above-average', 'below-average', // cfcAboveAverage, cfcBelowAverage,
'=%s', '!=%s', // cfcEqual, cfcNotEqual
'>%s', '<%s', //cfcGreaterThan, cfcLessThan
'>=%s', '<=%s', // cfcGreaterEqual, cfdLessEqual
'between(%s,%s)', 'not-between(%s,%s)', // cfcBetween, cfcNotBetween,
'above-average', 'below-average', // cfcAboveAverage, cfcBelowAverage,
'above-equal-average', 'below-equal-average', // cfcAboveEqualAverage, cfcBelowEqualAverage
'top-elements(%s)', 'bottom-elements(%s)', // cfcTop, cfcBottom,
'top-percent(%s)', 'bottom-percent(%s)', // cfcTopPercent, cfcBottomPercent,
'duplicate', 'unique', // cfcDuplicate, cfcUnique,
'begins-with(%s)', 'ends-with(%s)', // cfcBeginsWith, cfcEndsWith,
'contains-text(%s)', 'not-contains-text(%s)', // cfcContainsText, cfcNotContainsText,
'is-error', 'is-no-error' // cfcContainsErrors, cfcNotContainsErrors
'is-error', 'is-no-error', // cfcContainsErrors, cfcNotContainsErrors
'formula-is(%s)' // cfcExprssion
);
CF_VALUE_KIND: array[TsCFValueKind] of string = (
@ -7398,8 +7400,18 @@ begin
begin
cf_cellRule := TsCFCellRule(cf.Rules[k]);
cf_styleName := Format('conditional_%d', [cf_cellRule.FormatIndex]);
operand1Str := CFOperandToStr(cf_cellrule.Operand1, cf_sheet);
operand2Str := CFOperandToStr(cf_cellrule.Operand2, cf_sheet);
if cf_cellRule.Condition = cfcExpression then
begin
operand1Str := VarToStr(cf_cellRule.Operand1);
if (operand1Str <> '') and (operand1Str[1] <> '=') then
operand1Str := '=' + operand1Str;
operand1Str := CFOperandToStr(operand1Str, cf_sheet);
operand2Str := '';
end else
begin
operand1Str := CFOperandToStr(cf_cellrule.Operand1, cf_sheet);
operand2Str := CFOperandToStr(cf_cellrule.Operand2, cf_sheet);
end;
cf_condition := Format(CF_STYLE_OP[cf_cellRule.Condition], [operand1Str, operand2Str]);
if cf_Condition <> '' then begin

View File

@ -229,7 +229,8 @@ const
'@NOT(ISERROR(SEARCH(%0:s,RC)))', // cfcContainsText
'@ISERROR(SEARCH(%0:s,RC))', // cfcNotContainsText,
'@ISERROR(RC)', // cfcContainsErrors
'@NOT(ISERROR(RC))' // cfcNotContainsErrors
'@NOT(ISERROR(RC))', // cfcNotContainsErrors
'@' // cfcExpression
);
// The leading '@' indicates that the formula will be used in <Value1> node
@ -2134,14 +2135,26 @@ begin
Continue;
end;
value1Str := CFOperandToStr(cfRule.Operand1, sheet);
value2Str := CFOperandToStr(cfRule.Operand2, sheet);
if cfRule.Condition = cfcExpression then
begin
s := cfRule.Operand1;
if (s <> '') and (s[1] <> '=') then s := '=' + s;
value1Str := CFOperandToStr(s, sheet);
value2Str := '';
end else
begin
value1Str := CFOperandToStr(cfRule.Operand1, sheet);
value2Str := CFOperandToStr(cfRule.Operand2, sheet);
end;
s := CF_CONDITIONS[cfRule.Condition];
if s[1] = '@' then
begin
Delete(s, 1,1);
s := Format(s, [value1Str, value2Str, rangeStr]);
if s = '' then
s := value1Str
else
s := Format(s, [value1Str, value2Str, rangeStr]);
value1Str := s;
s := '';
end;
@ -2152,9 +2165,11 @@ begin
if s <> '' then
AppendToStream(AStream, LF + INDENT4 +
'<Qualifier>' + s + '</Qualifier>');
if value1Str <> '' then
AppendToStream(AStream, LF + INDENT4 +
'<Value1>' + value1Str + '</Value1>');
if (cfRule.Condition in [cfcBetween, cfcNotBetween]) and (value2Str <> '') then
AppendToStream(AStream, LF + INDENT4 +
'<Value2>' + value2Str + '</Value2>');

View File

@ -430,7 +430,8 @@ const
'duplicateValues', 'uniqueValues', // cfcDuplicate, cfcUnique,
'beginsWith', 'endsWith', // cfcBeginsWith, cfcEndsWith,
'containsText', 'notContainsText', // cfcContainsText, cfcNotContainsText,
'containsErrors', 'notContainsErrors' // cfcContainsErrors, cfcNotContainsErrors
'containsErrors', 'notContainsErrors', // cfcContainsErrors, cfcNotContainsErrors
'expression' // cfcExpression
);
CF_OPERATOR_NAMES: array[TsCFCondition] of string = (
@ -440,7 +441,8 @@ const
'', '', '', '', // cfcTop, cfcBottom, cfcTopPercent, cfcBottomPercent,
'', '', // cfcDuplicate, cfcUnique,
'', '', '', 'notContains', //cfcBeginsWith, cfcEndsWith, cfcContainsText, cfcNotContainsText,
'', '' // cfcContainsErrors, cfcNotContainsErrors
'', '', // cfcContainsErrors, cfcNotContainsErrors
'' // cfcExpression
);
function StrToFillStyle(s: String): TsFillStyle;
@ -4115,6 +4117,12 @@ begin
'</formula>';
param1Str := ' text="' + VarToStr(ARule.Operand1) + '"';
end;
cfcExpression:
begin
s := ARule.Operand1;
if (s <> '') and (s[1] = '=') then Delete(s, 1, 1);
formula1Str := '<formula>' + s + '</formula>';
end;
else
FWorkbook.AddErrorMsg('ConditionalFormat operator not supported.');
end;