From 52e4cccf802b0f0a39961e1204a46ccae2aee43e Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Thu, 16 Jul 2020 20:46:21 +0000 Subject: [PATCH] fpspreadsheet: XLSX reader supports expression conditional format. Add test case for it. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7546 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../read_write/ooxmldemo/ooxmlwrite.lpi | 3 - .../read_write/ooxmldemo/ooxmlwrite.lpr | 78 +------------------ .../fpspreadsheet/source/common/fpsutils.pas | 28 ++++--- .../fpspreadsheet/source/common/xlsxooxml.pas | 27 +++++++ .../tests/conditionalformattests.pas | 10 +++ 5 files changed, 57 insertions(+), 89 deletions(-) diff --git a/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpi b/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpi index 89f200930..9b6d15184 100644 --- a/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpi +++ b/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpi @@ -19,9 +19,6 @@ - - - diff --git a/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpr b/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpr index 0b9e7c70e..e44c699e5 100644 --- a/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpr +++ b/components/fpspreadsheet/examples/read_write/ooxmldemo/ooxmlwrite.lpr @@ -27,85 +27,9 @@ begin MyWorkbook := TsWorkbook.Create; MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet'); - // Write some number cells MyWorksheet.WriteNumber(0, 0, 1.0); - MyWorksheet.WriteNumber(0, 1, 2.0); - MyWorksheet.WriteNumber(0, 2, 3.0); - MyWorksheet.WriteNumber(0, 3, 4.0); - MyWorksheet.WriteUTF8Text(0, 4, '& " '' < >'); - MyWorksheet.WriteText(0, 26, 'AA'); // Test for column name - - MyWorksheet.WriteColWidth(0, 20, suChars); - MyWorksheet.WriteRowHeight(0, 4, suLines); - - // Write some formulas - Myworksheet.WriteFormula(0, 5, '=A1-B1'); - Myworksheet.WriteFormula(0, 6, '=SUM(A1:D1)'); - MyWorksheet.WriteFormula(0, 7, '=SIN(A1+B1)'); - -// Uncomment this to test large XLS files - for i := 2 to 2{20} do - begin - MyWorksheet.WriteText(i, 0, ParamStr(0)); - MyWorksheet.WriteText(i, 1, ParamStr(0)); - MyWorksheet.WriteText(i, 2, ParamStr(0)); - MyWorksheet.WriteText(i, 3, ParamStr(0)); - end; - - // Test for Bold - MyCell := MyWorksheet.GetCell(2, 0); - MyCell^.FontIndex := BOLD_FONTINDEX; - MyCell := MyWorksheet.GetCell(2, 1); - MyCell^.FontIndex := BOLD_FONTINDEX; - MyCell := MyWorksheet.GetCell(2, 2); - MyCell^.FontIndex := BOLD_FONTINDEX; - MyCell := MyWorksheet.GetCell(2, 3); - MyCell^.FontIndex := BOLD_FONTINDEX; - - // Background and text color - MyWorksheet.WriteText(4, 0, 'white on red'); - Myworksheet.WriteBackgroundColor(4, 0, scRed); - MyWorksheet.WriteFontColor(4, 0, scWhite); - - // Border - MyWorksheet.WriteText(4, 2, 'left/right'); - Myworksheet.WriteBorders(4, 2, [cbWest, cbEast]); - MyWorksheet.WriteHorAlignment(4, 2, haCenter); - - Myworksheet.WriteText(4, 4, 'top/bottom'); - Myworksheet.WriteBorders(4, 4, [cbNorth, cbSouth]); - MyWorksheet.WriteBorderStyle(4, 4, cbSouth, lsThick, scBlue); - Myworksheet.WriteHorAlignment(4, 4, haRight); - - // Wordwrap - MyWorksheet.WriteText(4, 6, 'This is a long, long, long, wrapped text.'); - MyWorksheet.WriteWordwrap(4, 6, true); - - // Creates a new worksheet - MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2'); - - // Write some string cells - MyWorksheet.WriteText(0, 0, 'First'); - MyWorksheet.WriteText(0, 1, 'Second'); - MyWorksheet.WriteText(0, 2, 'Third'); - MyWorksheet.WriteText(0, 3, 'Fourth'); - - // Write current date/time - MyWorksheet.WriteDateTime(0, 5, now, nfShortDate); - MyWorksheet.WriteDateTime(1, 5, now, nfShortTime); - MyWorksheet.WriteDateTime(2, 5, now, 'nn:ss.zzz'); - - // Write some numbers in various formats - MyWorksheet.WriteNumber(0, 6, 12345.6789, nfFixed, 0); - MyWorksheet.WriteNumber(1, 6, 12345.6789, nfFixed, 3); - MyWorksheet.WriteNumber(2, 6, 12345.6789, nfFixedTh, 0); - MyWorksheet.Writenumber(3, 6, 12345.6789, nfFixedTh, 3); - MyWorksheet.WriteNumber(4, 6, 12345.6789, nfExp, 2); - Myworksheet.Writenumber(5, 6, 12345.6789, nfExp, 4); - MyWorksheet.WriteCurrency(6, 6,-12345.6789, nfCurrency, 2); - MyWorksheet.WriteCurrency(7, 6,-12345.6789, nfCurrencyRed, 2); - MyWorksheet.WriteNumber(8, 6, 1.66666667, nfFraction, '# ?/?'); + MyWorksheet.WriteNumberFormat(0, 0, nfFixed, 2); // Save the spreadsheet to a file MyWorkbook.WriteToFile(MyDir + 'test.xlsx', sfOOXML, true); diff --git a/components/fpspreadsheet/source/common/fpsutils.pas b/components/fpspreadsheet/source/common/fpsutils.pas index 9236f25e5..2300435fa 100644 --- a/components/fpspreadsheet/source/common/fpsutils.pas +++ b/components/fpspreadsheet/source/common/fpsutils.pas @@ -488,21 +488,31 @@ var p: Integer; s: String; f: TsRelFlags; + singleCell: Boolean = false; begin Result := True; // First find the colon p := pos(':', AStr); - if p = 0 then exit(false); + if p = 0 then //exit(false); + begin + singleCell := true; + Result := ParseCellString(AStr, AFirstcellRow, AFirstCellCol, f); + if not Result then exit; + ALastCellRow := AFirstCellRow; + ALastCellCol := AFirstCellCol; + AFlags := f; + end else + begin + // Analyze part after the colon + s := copy(AStr, p+1, Length(AStr)); + Result := ParseCellString(s, ALastCellRow, ALastCellCol, f); + if not Result then exit; - // Analyze part after the colon - s := copy(AStr, p+1, Length(AStr)); - Result := ParseCellString(s, ALastCellRow, ALastCellCol, f); - if not Result then exit; - - // Analyze part before the colon - s := copy(AStr, 1, p-1); - Result := ParseCellString(s, AFirstCellRow, AFirstCellCol, AFlags); + // Analyze part before the colon + s := copy(AStr, 1, p-1); + Result := ParseCellString(s, AFirstCellRow, AFirstCellCol, AFlags); + end; // Add flags of 2nd part if rfRelRow in f then Include(AFlags, rfRelRow2); diff --git a/components/fpspreadsheet/source/common/xlsxooxml.pas b/components/fpspreadsheet/source/common/xlsxooxml.pas index 2e32c8e40..a3ec0f48c 100644 --- a/components/fpspreadsheet/source/common/xlsxooxml.pas +++ b/components/fpspreadsheet/source/common/xlsxooxml.pas @@ -81,6 +81,8 @@ type ARange: TsCellRange); procedure ReadCFDataBars(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; ARange: TsCellRange); + procedure ReadCFExpression(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; + ARange: TsCellRange; AFormatIndex: Integer); procedure ReadCFMisc(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; ARange: TsCellRange; AFormatIndex: Integer); procedure ReadCFTop10(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; @@ -1509,6 +1511,29 @@ begin sheet.WriteDataBars(ARange, clr, vk[0], v[0], vk[1], v[1]); end; +procedure TsSpreadOOXMLReader.ReadCFExpression(ANode: TDOMNode; + AWorksheet: TsBasicWorksheet; ARange: TsCellRange; AFormatIndex: Integer); +var + sheet: TsWorksheet; + nodeName: String; + s: String; +begin + sheet := TsWorksheet(AWorksheet); + + ANode := ANode.FirstChild; + while ANode <> nil do + begin + nodeName := ANode.NodeName; + if nodeName = 'formula' then + begin + s := GetNodeValue(ANode); + sheet.WriteConditionalCellFormat(ARange, cfcExpression, s, AFormatIndex); + exit; + end; + ANode := ANode.NextSibling; + end; +end; + procedure TsSpreadOOXMLReader.ReadCFMisc(ANode: TDOMNode; AWorksheet: TsBasicWorksheet; ARange: TsCellRange; AFormatIndex: Integer); var @@ -1857,6 +1882,8 @@ begin ReadCFMisc(childNode, AWorksheet, range, fmtIdx); 'containsText', 'notContainsText', 'beginsWith', 'endsWith': ReadCFMisc(childNode, AWorksheet, range, fmtIdx); + 'expression': + ReadCFExpression(childNode, AWorksheet, range, fmtIdx); 'colorScale': ReadCFColorRange(childNode, AWorksheet, range); 'dataBar': diff --git a/components/fpspreadsheet/tests/conditionalformattests.pas b/components/fpspreadsheet/tests/conditionalformattests.pas index 68d9c55f3..ab125e8be 100644 --- a/components/fpspreadsheet/tests/conditionalformattests.pas +++ b/components/fpspreadsheet/tests/conditionalformattests.pas @@ -67,6 +67,7 @@ type procedure TestWriteRead_CF_CellFmt_XLSX_Duplicate; procedure TestWriteRead_CF_CellFmt_XLSX_ContainsErrors; procedure TestWriteRead_CF_CellFmt_XLSX_NotContainsErrors; + procedure TestWriteRead_CF_CellFmt_XLSX_Expression; procedure TestWriteRead_CF_CellFmt_XLSX_Background; procedure TestWriteRead_CF_CellFmt_XLSX_Border; @@ -564,6 +565,15 @@ begin TestWriteRead_CF_CellFmt(sfOOXML, cfcNotContainsErrors, fmt); end; +procedure TSpreadWriteReadCFTests.TestWriteRead_CF_CellFmt_XLSX_Expression; +var + fmt: TsCellFormat; +begin + InitFormatRecord(fmt); + fmt.SetBackgroundColor(scRed); + TestWriteRead_CF_CellFmt(sfOOXML, cfcExpression, 'ISNUMBER(A1)', fmt); +end; + procedure TSpreadWriteReadCFTests.TestWriteRead_CF_CellFmt_XLSX_Background; var fmt: TsCellFormat;