diff --git a/components/fpspreadsheet/examples/other/conditional_formatting/demo_conditional_formatting.pas b/components/fpspreadsheet/examples/other/conditional_formatting/demo_conditional_formatting.pas index 47c7da8db..bfea8f1d9 100644 --- a/components/fpspreadsheet/examples/other/conditional_formatting/demo_conditional_formatting.pas +++ b/components/fpspreadsheet/examples/other/conditional_formatting/demo_conditional_formatting.pas @@ -38,7 +38,7 @@ begin sh.WriteNumber(i, 8, 7.0); sh.WriteNumber(i, 9, 8.0); sh.WriteNumber(i, 10, 9.0); - sh.WriteNumber(i, 11, 10.0); + //sh.WriteNumber(i, 11, 10.0); sh.WriteText(i, 12, 'abc'); sh.WriteText(i, 13, 'abc'); sh.WriteBlank(i, 14); @@ -60,7 +60,7 @@ begin fmtIdx := wb.AddCellFormat(fmt); // Write conditional format sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcEqual, 5, fmtIdx); - (* + // conditional format #2: equal to text constant inc(row); sh.WriteText(row, 0, 'equal to text "abc"'); @@ -123,7 +123,7 @@ begin InitFormatRecord(fmt); fmt.SetBackground(fsThinStripeDiagUp, scRed, scYellow); fmtIdx := wb.AddCellFormat(fmt); - sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcAboveAverage, fmtIdx); + sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveAverage, fmtIdx); // only 1..9 -> ave = 5 // conditional format #6: below average inc(row); @@ -132,7 +132,7 @@ begin InitFormatRecord(fmt); fmt.SetBackground(fsGray25, scRed, scYellow); fmtIdx := wb.AddCellFormat(fmt); - sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBelowAverage, fmtIdx); + sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowAverage, fmtIdx); // only 1..9 -> ave = 5 // conditional format #6: above or equal to average inc(row); @@ -141,7 +141,7 @@ begin InitFormatRecord(fmt); fmt.SetBackground(fsThinStripeHor, scRed, scYellow); fmtIdx := wb.AddCellFormat(fmt); - sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcAboveEqualAverage, fmtIdx); + sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcAboveEqualAverage, fmtIdx); // only 1..9 -> ave = 5 // conditional format #6: below or equal to average inc(row); @@ -150,7 +150,7 @@ begin InitFormatRecord(fmt); fmt.SetBackground(fsThinStripeVert, scRed, scYellow); fmtIdx := wb.AddCellFormat(fmt); - sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBelowEqualAverage, fmtIdx); + sh.WriteConditionalCellFormat(Range(row, 2, row, 10), cfcBelowEqualAverage, fmtIdx); // only 1..9 -> ave = 5 // conditional format #6: top 3 values inc(row); @@ -183,7 +183,7 @@ begin fmt.SetBackgroundColor($FFC0C0); fmtIdx := wb.AddCellFormat(fmt); sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcBottomPercent, 10, fmtIdx); - + (* // conditional format #6: duplicates inc(row); sh.WriteText(row, 0, 'duplicate values'); @@ -199,7 +199,7 @@ begin fmt.SetBackgroundColor($D0D0FF); fmtIdx := wb.AddCellFormat(fmt); sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcUnique, fmtIdx); - + *) // conditional format #6: contains any text inc(row); sh.WriteText(row, 0, 'contains any text'); @@ -247,7 +247,7 @@ begin fmt.SetBackgroundColor(scRed); fmtIdx := wb.AddCellFormat(fmt); sh.WriteConditionalCellFormat(Range(row, 2, row, lastCol), cfcNotContainsText, 'ef', fmtIdx); - + (* // conditional format #6: contains error inc(row); sh.WriteText(row, 0, 'contains error'); diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk index 021dd0292..c5743599a 100644 --- a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk +++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk @@ -46,8 +46,8 @@ It provides graphical components like a grid and chart."/> - - + + diff --git a/components/fpspreadsheet/source/common/fpsopendocument.pas b/components/fpspreadsheet/source/common/fpsopendocument.pas index e3e9c72fd..fd263ffe4 100644 --- a/components/fpspreadsheet/source/common/fpsopendocument.pas +++ b/components/fpspreadsheet/source/common/fpsopendocument.pas @@ -383,9 +383,11 @@ const COLWIDTH_EPS = 1e-3; ROWHEIGHT_EPS = 1e-3; - CF_OPERATORS: array[TsCFCondition] of string = ( - '=', '!=', '>', '<', '>=', '<=', - '', '', // cfcBetween, cfcNotBetween, + CF_STYLE_OP: array[TsCFCondition] of string = ( + 'cell-content()=%s', 'cell-content()!=%s', // cfcEqual, cfcNotEqual + '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, @@ -393,6 +395,22 @@ const '', '' // cfcContainsErrors, cfcNotContainsErrors ); + 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, + 'above-equal-average', 'below-equal-average', // cfcAboveEqualAverage, cfcBelowEqualAverage + 'top-elements(%s)', 'bottom-elements(%s)', // cfcTop, cfcBottom, + 'top-percent(%s)', 'bottom-percent(%s)', // cfcTopPercent, cfcBottomPercent, + '', '', // cfcDuplicate, cfcUnique, + 'begins-with(%s)', 'ends-with(%s)', // cfcBeginsWith, cfcEndsWith, + 'contains-text(%s)', 'not-contains-text(%s)', // cfcContainsText, cfcNotContainsText, + '', '' // cfcContainsErrors, cfcNotContainsErrors + ); + + type { Table style items stored in TableStyleList of the reader } @@ -5899,6 +5917,12 @@ begin begin cf_cellRule := TsCFCellRule(cf.Rules[k]); cf_styleName := Format('conditional_%d', [cf_CellRule.FormatIndex]); + value1Str := VarToStr(cf_cellRule.Operand1); + if VarIsStr(cf_cellRule.Operand1) then value1Str := UTF8TextToXMLText(SafeQuoteStr(value1Str)); + value2Str := VarToStr(cf_cellRule.Operand2); + if VarIsStr(cf_cellRule.Operand1) then value2Str := UTF8TextToXMLText(SafeQuoteStr(value2Str)); + opStr := Format(CF_CALCEXT_OP[cf_cellRule.Condition], [value1Str, value2str]); + (* case cf_cellRule.Condition of cfcEqual..cfcLessEqual: begin @@ -5926,10 +5950,12 @@ begin else Continue; end; - AppendToStream(AStream, Format( - '', - [cf_stylename, opStr, firstCellStr] - )); + *) + if opStr <> '' then + AppendToStream(AStream, Format( + '', + [cf_stylename, opStr, firstCellStr] + )); end; end; @@ -7365,12 +7391,18 @@ begin cf_sheet := cf.Worksheet as TsWorksheet; firstCellOfRange := cf_sheet.Name + '.' + GetCellString(cf.CellRange.Row1, cf.CellRange.Col1); - // Every rule has a style:map node + // Some rules have a style:map node for k := 0 to cf.RulesCount-1 do begin if cf.Rules[k] is TsCFCellRule then begin cf_cellRule := TsCFCellRule(cf.Rules[k]); cf_styleName := Format('conditional_%d', [cf_cellRule.FormatIndex]); + operand1Str := VarToStr(cf_cellrule.Operand1); + if VarIsStr(cf_cellRule.Operand1) then operand1Str := UTF8TextToXMLText(SafeQuoteStr(operand1Str)); + operand2Str := VarToStr(cf_cellrule.Operand2); + if VarIsStr(cf_cellRule.Operand2) then operand2Str := UTF8TextToXMLText(SafeQuoteStr(operand2Str)); + cf_condition := Format(CF_STYLE_OP[cf_cellRule.Condition], [operand1Str, operand2Str]); + (* case cf_cellRule.Condition of cfcEqual..cfcLessEqual: begin @@ -7399,6 +7431,7 @@ begin else cf_Condition := ''; end; + *) if cf_Condition <> '' then Result := Result + diff --git a/components/fpspreadsheet/source/visual/fpspreadsheetctrls.pas b/components/fpspreadsheet/source/visual/fpspreadsheetctrls.pas index 75452296c..287ee587d 100644 --- a/components/fpspreadsheet/source/visual/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/source/visual/fpspreadsheetctrls.pas @@ -640,8 +640,9 @@ type imRow, imCol); {@@ Inspector expanded nodes } - TsInspectorExpandedNode = (ienFormatSettings, ienPageLayout, ienFonts, ienFormats, - ienEmbeddedObj, ienImages, ienCryptoInfo); + TsInspectorExpandedNode = (ienFormatSettings, ienConditionalFormats, + ienPageLayout, ienFonts, ienFormats, ienEmbeddedObj, ienImages, + ienCryptoInfo); TsInspectorExpandedNodes = set of TsInspectorExpandedNode; {@@ TsSpreadsheetInspector displays all properties of a workbook, worksheet, @@ -691,8 +692,8 @@ type {@@ Displays subproperties } property ExpandedNodes: TsInspectorExpandedNodes read FExpanded write SetExpanded - default [ienFormatSettings, ienPageLayout, ienFonts, ienFormats, - ienEmbeddedObj, ienImages, ienCryptoInfo]; + default [ienFormatSettings, ienConditionalFormats, ienPageLayout, + ienFonts, ienFormats, ienEmbeddedObj, ienImages, ienCryptoInfo]; {@@ inherited from TValueListEditor. Turns of the fixed column by default} property FixedCols default 0; {@@ inherited from TStringGrid, but not published in TValueListEditor. } @@ -708,7 +709,7 @@ uses Types, Math, StrUtils, TypInfo, LCLType, LCLIntf, LCLProc, Dialogs, Forms, Clipbrd, fpsStrings, fpsCrypto, fpsReaderWriter, fpsUtils, fpsNumFormat, fpsImages, - fpsHTMLUtils, fpsCSV, fpsExprParser; + fpsHTMLUtils, fpsCSV, fpsExprParser, fpsConditionalFormat; var cfBiff8Format: Integer = 0; @@ -3529,8 +3530,8 @@ begin inherited Create(AOwner); DisplayOptions := DisplayOptions - [doKeyColFixed]; FixedCols := 0; - FExpanded := [ienFormatSettings, ienPageLayout, ienFonts, ienFormats, - ienEmbeddedObj, ienImages, ienCryptoInfo]; + FExpanded := [ienFormatSettings, ienConditionalFormats, ienPageLayout, + ienFonts, ienFormats, ienEmbeddedObj, ienImages, ienCryptoInfo]; with (TitleCaptions as TStringList) do begin OnChange := nil; // This fixes an issue with Laz 1.0 Clear; @@ -3566,6 +3567,12 @@ begin then Exclude(expNodes, ienFormatSettings) else Include(expNodes, ienFormatSettings); end else + if (pos('Conditional formats', s) > 0) or (pos('ConditionalFormats', s) > 0) then + begin + if (ienConditionalFormats in expNodes) + then Exclude(expNodes, ienConditionalFormats) + else Include(expNodes, ienConditionalFormats); + end else if (pos('Page layout', s) > 0) or (pos('PageLayout', s) > 0) then begin if (ienPageLayout in expNodes) @@ -4252,6 +4259,7 @@ var embObj: TsEmbeddedObj; so: TsSheetOption; sp: TsWorksheetProtection; + cf: TsConditionalFormat; begin if ASheet = nil then begin @@ -4270,6 +4278,7 @@ begin AStrings.Add('Options='); AStrings.Add('Protection='); AStrings.Add('TabColor='); + AStrings.Add('Conditional formats='); end else begin AStrings.Add(Format('Name=%s', [ASheet.Name])); @@ -4292,7 +4301,23 @@ begin AStrings.Add(Format('Hyperlinks=%d items', [ASheet.Hyperlinks.Count])); AStrings.Add(Format('MergedCells=%d items', [ASheet.MergedCells.Count])); AStrings.Add(Format('TabColor=$%.8x (%s)', [ASheet.TabColor, GetColorName(ASheet.TabColor)])); - + (* + if ienConditionalFormats in FExpanded then + begin + AStrings.Add('(-) Conditional formats='); + AStrings.Add(Format(' Count=%d', [ASheet.ConditionalFormatCount])); + for i := 0 to ASheet.ConditionalFormatCount-1 do + begin + cf := ASheet.ReadConditionalFormat(i); + AStrings.Add(' Item #' + IntToStr(i) + ':'); + with cf.CellRange do + AStrings.Add(Format(' CellRange=%s', [GetCellRangeString(Row1, Col1, Row2, Col2)])); + end; + end else + begin + AStrings.Add('(+) Conditional formats=(dblclick for more...)'); + end; + *) if ienPageLayout in FExpanded then begin AStrings.Add('(-) Page layout=');