fpspreadsheet: Add writing of text-related conditional formatting conditions to xlsx writer.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7498 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-06-26 10:59:12 +00:00
parent 5578d181a8
commit 8a30aacadb
3 changed files with 62 additions and 19 deletions

View File

@ -16,7 +16,7 @@ begin
try try
sh := wb.AddWorksheet('test'); sh := wb.AddWorksheet('test');
{ ------ 1st conditional format ------------------------------------------ } { ------ 1st conditional format : cfcEqual ------------------------------- }
sh.WriteNumber(0, 0, 1.0); sh.WriteNumber(0, 0, 1.0);
sh.WriteNumber(1, 0, 2.0); sh.WriteNumber(1, 0, 2.0);
sh.WriteNumber(2, 0, 3.0); sh.WriteNumber(2, 0, 3.0);
@ -37,12 +37,11 @@ begin
fmt.SetFont(wb.AddFont(font)); fmt.SetFont(wb.AddFont(font));
// Add format record to format list // Add format record to format list
fmtIdx := wb.AddCellFormat(fmt); fmtIdx := wb.AddCellFormat(fmt);
// Use the format as conditional format of A1:A6 when cells are equal to 3. // Use the format as conditional format of A1:A6 when cells are equal to 3.
sh.WriteConditionalCellFormat(Range(0, 0, 5, 0), cfcEqual, 3.0, fmtIdx); sh.WriteConditionalCellFormat(Range(0, 0, 5, 0), cfcEqual, 3.0, fmtIdx);
{ ------- 2nd conditional format ----------------------------------------- } { ------- 2nd conditional format : cfcBelowEqualAverage ------------------ }
sh.WriteNumber(0, 2, 10.0); sh.WriteNumber(0, 2, 10.0);
sh.WriteNumber(1, 2, 20.0); sh.WriteNumber(1, 2, 20.0);
sh.WriteNumber(2, 2, 15.0); sh.WriteNumber(2, 2, 15.0);
@ -52,9 +51,25 @@ begin
InitFormatRecord(fmt); InitFormatRecord(fmt);
fmt.SetBackgroundColor(scRed); fmt.SetBackgroundColor(scRed);
fmtIdx := wb.AddCellFormat(fmt); fmtIdx := wb.AddCellFormat(fmt);
sh.WriteConditionalCellFormat(Range(0, 2, 4, 2), cfcBelowEqualAverage, fmtIdx); sh.WriteConditionalCellFormat(Range(0, 2, 4, 2), cfcBelowEqualAverage, fmtIdx);
{ ------- 3rd and 4th conditional formats : beginWith, containsText ------ }
sh.WriteText(0, 4, 'abc');
sh.WriteText(1, 4, 'def');
sh.WriteText(2, 4, 'bac');
sh.WriteText(3, 4, 'dbc');
sh.WriteText(4, 4, 'acb');
sh.WriteText(5, 4, 'aca');
InitFormatRecord(fmt);
fmt.SetBackgroundColor($DEF1F4);
fmtIdx := wb.AddCellFormat(fmt);
sh.WriteConditionalCellFormat(Range(0, 4, 5, 4), cfcBeginsWith, 'a', fmtIdx);
fmt.SetBackgroundColor($D08330);
fmtIdx := wb.AddCellFormat(fmt);
sh.WriteConditionalCellFormat(Range(0, 4, 5, 4), cfcContainsText, 'bc', fmtIdx);
{ ------ Save workbook to file-------------------------------------------- } { ------ Save workbook to file-------------------------------------------- }
wb.WriteToFile('test.xlsx', true); wb.WriteToFile('test.xlsx', true);
finally finally

View File

@ -19,9 +19,9 @@ type
cfcGreaterThan, cfcLessThan, cfcGreaterEqual, cfcLessEqual, cfcGreaterThan, cfcLessThan, cfcGreaterEqual, cfcLessEqual,
cfcBetween, cfcNotBetween, cfcBetween, cfcNotBetween,
cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage, cfcAboveAverage, cfcBelowAverage, cfcAboveEqualAverage, cfcBelowEqualAverage,
cfcBeginsWidth, cfcEndsWith,
cfcDuplicate, cfcUnique, cfcDuplicate, cfcUnique,
cfcContainsText, cfcNotContaisText, cfcBeginsWith, cfcEndsWith,
cfcContainsText, cfcNotContainsText,
cfcContainsErrors, cfcNotContainsErrors cfcContainsErrors, cfcNotContainsErrors
); );

View File

@ -145,8 +145,10 @@ type
procedure WriteCols(AStream: TStream; AWorksheet: TsBasicWorksheet); procedure WriteCols(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteComments(AWorksheet: TsBasicWorksheet); procedure WriteComments(AWorksheet: TsBasicWorksheet);
procedure WriteConditionalFormat(AStream: TStream; AFormat: TsConditionalFormat; var APriority: Integer); procedure WriteConditionalFormat(AStream: TStream; AFormat: TsConditionalFormat; var APriority: Integer);
procedure WriteConditionalFormatCellRule(AStream: TStream; ARule: TsCFCellRule; APriority: Integer); procedure WriteConditionalFormatCellRule(AStream: TStream; ARule: TsCFCellRule;
procedure WriteConditionalFormatRule(AStream: TStream; ARule: TsCFRule; var APriority: Integer); ARange: TsCellRange; APriority: Integer);
procedure WriteConditionalFormatRule(AStream: TStream; ARule: TsCFRule;
const ARange: TsCellRange; var APriority: Integer);
procedure WriteConditionalFormats(AStream: TStream; AWorksheet: TsBasicWorksheet); procedure WriteConditionalFormats(AStream: TStream; AWorksheet: TsBasicWorksheet);
procedure WriteDefinedNames(AStream: TStream); procedure WriteDefinedNames(AStream: TStream);
procedure WriteDifferentialFormat(AStream: TStream; AFormat: PsCellFormat); procedure WriteDifferentialFormat(AStream: TStream; AFormat: PsCellFormat);
@ -3332,29 +3334,38 @@ begin
for i := 0 to AFormat.RulesCount-1 do for i := 0 to AFormat.RulesCount-1 do
begin begin
rule := AFormat.Rules[i]; rule := AFormat.Rules[i];
WriteConditionalFormatRule(AStream, rule, APriority); WriteConditionalFormatRule(AStream, rule, AFormat.CellRange, APriority);
end; end;
AppendToStream(AStream, AppendToStream(AStream,
'</conditionalFormatting>'); '</conditionalFormatting>');
end; end;
procedure TsSpreadOOXMLWriter.WriteConditionalFormatCellRule(AStream: TStream; procedure TsSpreadOOXMLWriter.WriteConditionalFormatCellRule(AStream: TStream;
ARule: TsCFCellRule; APriority: Integer); ARule: TsCFCellRule; ARange: TsCellRange; APriority: Integer);
const const
OPERATOR_NAMES_1: array[cfcEqual..cfcLessEqual] of String = OPERATOR_NAMES_1: array[cfcEqual..cfcLessEqual] of String =
('equal', 'notEqual', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual'); ('equal', 'notEqual', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual');
OPERATOR_NAMES_2: array[cfcBetween..cfcNotBetween] of String = OPERATOR_NAMES_2: array[cfcBetween..cfcNotBetween] of String =
('between', 'notBetween'); ('between', 'notBetween');
OPERATOR_NAMES_Text: array[cfcBeginsWith..cfcNotContainsText] of String =
('beginsWith', 'endsWith', 'containsText', 'notContainsText');
FORMULA: array[cfcBeginsWith..cfcNotContainsText] of String = (
'LEFT(%0:s,LEN("%1:s"))="%1:s"', // cfcBeginsWith
'RIGHT(%0:s,Len("%1:s"))="%1:s"', // cfcEndsWidth
'NOT(ISERROR(SEARCH("%1:s",%0:s)))', // cfcContainsText
'ISERROR(SEARCH("%1:s",%0:s))' // cfcNotContainsText
);
var var
i: Integer; i: Integer;
fmtID: Integer; dxfID: Integer;
aveStr, stdDevStr, eqAveStr: String; aveStr, stdDevStr, eqAveStr, opStr: String;
firstCellOfRange: String;
begin begin
fmtID := -1; dxfID := -1;
for i := 0 to High(FDifferentialFormatIndexList) do for i := 0 to High(FDifferentialFormatIndexList) do
if FDifferentialFormatIndexList[i] = ARule.FormatIndex then if FDifferentialFormatIndexList[i] = ARule.FormatIndex then
begin begin
fmtID := i; dxfID := i;
break; break;
end; end;
@ -3364,7 +3375,7 @@ begin
'<cfRule type="cellIs" dxfId="%d" priority="%d" operator="%s">' + '<cfRule type="cellIs" dxfId="%d" priority="%d" operator="%s">' +
'<formula>%s</formula>'+ '<formula>%s</formula>'+
'</cfRule>', [ '</cfRule>', [
fmtID, APriority, OPERATOR_NAMES_1[ARule.Condition], ARule.Operand1 dxfID, APriority, OPERATOR_NAMES_1[ARule.Condition], ARule.Operand1
])); ]));
cfcBetween, cfcNotBetween: cfcBetween, cfcNotBetween:
@ -3373,7 +3384,7 @@ begin
'<formula>%s</formula>'+ '<formula>%s</formula>'+
'<formula>%s</formula>'+ '<formula>%s</formula>'+
'</cfRule>', [ '</cfRule>', [
fmtId, APriority, OPERATOR_NAMES_1[ARule.Condition], ARule.Operand1, ARule.Operand2 dxfId, APriority, OPERATOR_NAMES_1[ARule.Condition], ARule.Operand1, ARule.Operand2
])); ]));
cfcAboveAverage..cfcBelowEqualAverage: cfcAboveAverage..cfcBelowEqualAverage:
@ -3392,7 +3403,24 @@ begin
stdDevStr := Format(' stdDev="%d"', [ARule.Operand1]); stdDevStr := Format(' stdDev="%d"', [ARule.Operand1]);
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<cfRule type="aboveAverage" dxfId="%d" priority="%d"%s%s%s />', '<cfRule type="aboveAverage" dxfId="%d" priority="%d"%s%s%s />',
[fmtId, APriority, aveStr, stdDevStr, eqAveStr])); [dxfId, APriority, aveStr, stdDevStr, eqAveStr]));
end;
cfcBeginsWith..cfcNotContainsText:
begin
firstCellOfRange := GetCellString(ARange.Row1, ARange.Col1);
if ARule.Condition = cfcNotContainsText then opStr := ' operator="notContains"' else opStr := '';
AppendToStream(AStream, Format(
'<cfRule type="%2:s" dxfId="%3:d" priority="%4:d"%5:s text="%1:s">'+
'<formula>' + FORMULA[ARule.Condition] + '</formula>' +
'</cfRule>', [
firstCellOfRange, // must be 1st ...
ARule.Operand1, // ... and 2nd parameters (see FORMULA[])
OPERATOR_NAMES_TEXT[ARule.Condition],
dxfId,
APriority,
opStr
]));
end; end;
else else
FWorkbook.AddErrorMsg('ConditionalFormat operator not supported.'); FWorkbook.AddErrorMsg('ConditionalFormat operator not supported.');
@ -3400,10 +3428,10 @@ begin
end; end;
procedure TsSpreadOOXMLWriter.WriteConditionalFormatRule(AStream: TStream; procedure TsSpreadOOXMLWriter.WriteConditionalFormatRule(AStream: TStream;
ARule: TsCFRule; var APriority: Integer); ARule: TsCFRule; const ARange: TsCellRange; var APriority: Integer);
begin begin
if ARule is TsCFCellRule then begin if ARule is TsCFCellRule then begin
WriteConditionalFormatCellRule(AStream, TsCFCellRule(ARule), APriority); WriteConditionalFormatCellRule(AStream, TsCFCellRule(ARule), ARange, APriority);
dec(APriority); dec(APriority);
end; end;
end; end;