diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index 17f6f6d69..cdd6eb593 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -118,6 +118,7 @@ type var AFontSize: Double; var AFontStyle: TsHeaderFooterFontStyles; var AFontColor: TsColor); function ReadHeaderFooterText(ANode: TDOMNode): String; + procedure ReadPrintRanges(ATableNode: TDOMNode; ASheet: TsWorksheet); procedure ReadRowsAndCells(ATableNode: TDOMNode); procedure ReadRowStyle(AStyleNode: TDOMNode); procedure ReadTableStyle(AStyleNode: TDOMNode); @@ -2199,6 +2200,8 @@ begin pageLayout := ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name')); if pageLayout <> nil then FWorksheet.PageLayout := pagelayout^; + // Read print ranges + ReadPrintRanges(TableNode, FWorksheet); // Apply table style ApplyTableStyle(FWorksheet, tablestylename); // Handle columns and rows @@ -2948,6 +2951,45 @@ begin end; end; +procedure TsSpreadOpenDocReader.ReadPrintRanges(ATableNode: TDOMNode; + ASheet: TsWorksheet); +var + L: TStringList; + s, sheetname: String; + i, p: Integer; + r1,c1,r2,c2: Cardinal; +begin + s := GetAttrValue(ATableNode, 'table:print-ranges'); + if s = '' then + exit; + L := TStringList.Create; + try + L.Delimiter := ' '; + L.StrictDelimiter := true; + L.DelimitedText := s; + for i:=0 to L.Count-1 do begin + p := pos(':', L[i]); + s := Copy(L[i], 1, p-1); + ParseSheetCellString(s, sheetname, r1, c1, '.'); + if (sheetname <> '') and (sheetname <> ASheet.Name) then + begin + FWorkbook.AddErrorMsg(rsDifferentSheetPrintRange, [L[i]]); + Continue; + end; + s := Copy(L[i], p+1, Length(L[i])); + ParseSheetCellString(s, sheetname, r2, c2, '.'); + if (sheetname <> '') and (sheetname <> ASheet.name) then + begin + FWorkbook.AddErrorMsg(rsDifferentSheetPrintRange, [L[i]]); + Continue; + end; + ASheet.AddPrintRange(r1, c1, r2, c2); + end; + finally + L.Free; + end; +end; + { Reads the cells in the given table. Loops through all rows, and then finds all cells of each row. } procedure TsSpreadOpenDocReader.ReadRowsAndCells(ATableNode: TDOMNode); diff --git a/components/fpspreadsheet/fpsstrings.pas b/components/fpspreadsheet/fpsstrings.pas index e10f1d48a..d2a446109 100644 --- a/components/fpspreadsheet/fpsstrings.pas +++ b/components/fpspreadsheet/fpsstrings.pas @@ -92,6 +92,8 @@ resourcestring rsCannotSortMerged = 'The cell range cannot be sorted because it contains merged cells.'; + rsDifferentSheetPrintRange = 'Print range "%s" requires a different worksheet.'; + // Colors rsAqua = 'aqua'; rsBeige = 'beige'; diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index 57aac16db..880947a63 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -70,8 +70,8 @@ function ParseCellString(const AStr: string; out ACellRow, ACellCol: Cardinal; out AFlags: TsRelFlags): Boolean; overload; function ParseCellString(const AStr: string; out ACellRow, ACellCol: Cardinal): Boolean; overload; -function ParseSheetCellString(const AStr: String; - out ASheetName: String; out ACellRow, ACellCol: Cardinal): Boolean; +function ParseSheetCellString(const AStr: String; out ASheetName: String; + out ACellRow, ACellCol: Cardinal; ASheetSeparator: Char = '!'): Boolean; function ParseCellRowString(const AStr: string; out AResult: Cardinal): Boolean; function ParseCellColString(const AStr: string; @@ -787,11 +787,11 @@ begin end; function ParseSheetCellString(const AStr: String; out ASheetName: String; - out ACellRow, ACellCol: Cardinal): Boolean; + out ACellRow, ACellCol: Cardinal; ASheetSeparator: Char = '!'): Boolean; var p: Integer; begin - p := UTF8Pos('!', AStr); + p := pos(ASheetSeparator, AStr); if p = 0 then begin Result := ParseCellString(AStr, ACellRow, ACellCol); ASheetName := ''; diff --git a/components/fpspreadsheet/tests/pagelayouttests.pas b/components/fpspreadsheet/tests/pagelayouttests.pas index 6cf37a9b4..a23cb0c58 100644 --- a/components/fpspreadsheet/tests/pagelayouttests.pas +++ b/components/fpspreadsheet/tests/pagelayouttests.pas @@ -26,6 +26,7 @@ type procedure TearDown; override; procedure TestWriteRead_PageLayout(AFormat: TsSpreadsheetFormat; ANumSheets, ATestMode: Integer); procedure TestWriteRead_PageMargins(AFormat: TsSpreadsheetFormat; ANumSheets, AHeaderFooterMode: Integer); + procedure TestWriteRead_PrintRanges(AFormat: TsSpreadsheetFormat; ANumSheets, ANumRanges: Integer); published { BIFF2 page layout tests } @@ -272,6 +273,12 @@ type procedure TestWriteRead_ODS_HeaderFooterFontColor_1sheet; procedure TestWriteRead_ODS_HeaderFooterFontColor_2sheets; procedure TestWriteRead_ODS_HeaderFooterFontColor_3sheets; + + procedure TestWriteRead_ODS_PrintRanges_1sheet_1Range; + procedure TestWriteRead_ODS_PrintRanges_1sheet_2Ranges; + procedure TestWriteRead_ODS_PrintRanges_2sheet_1Range; + procedure TestWriteRead_ODS_PrintRanges_2sheet_2Ranges; + end; implementation @@ -284,6 +291,12 @@ uses const PageLayoutSheet = 'PageLayout'; +const + SollRanges: Array[1..2] of TsCellRange = ( + (Row1: 0; Col1: 0; Row2:10; Col2:20), + (Row1:20; Col1:30; Row2:25; Col2:40) + ); + { TSpreadWriteReadPageLayoutTests } @@ -658,6 +671,56 @@ actual: '&LH&Y2&YO cm&X2 &C&"Times New Roman"&18This is big&RThis is &Bbold&B,'#13#10'&Iitalic&I,'#13#10'&Uunderlined&U,'#13#10'&Edouble underlined&E,striked-out,'#13#10'&Ooutlined&O,'#13#10'&Hshadow' } + +procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_PrintRanges( + AFormat: TsSpreadsheetFormat; ANumSheets, ANumRanges: Integer); +var + tempFile: String; + i, j: Integer; + MyWorkbook: TsWorkbook; + MyWorksheet: TsWorksheet; + rng: TsCellRange; +begin + TempFile := GetTempFileName; + + MyWorkbook := TsWorkbook.Create; + try + for i:= 1 to ANumSheets do + begin + MyWorksheet := MyWorkbook.AddWorksheet(PageLayoutSheet+IntToStr(i)); + for j:=1 to ANumRanges do + MyWorksheet.AddPrintRange(SollRanges[j]); + end; + MyWorkBook.WriteToFile(TempFile, AFormat, true); + finally + MyWorkbook.Free; + end; + + // Open the spreadsheet + MyWorkbook := TsWorkbook.Create; + try + MyWorkbook.ReadFromFile(TempFile, AFormat); + CheckEquals(ANumSheets, MyWorkbook.GetWorksheetCount, 'Worksheet count mismatch'); + for i := 1 to ANumSheets do + begin + MyWorksheet := MyWorkbook.GetWorksheetByIndex(i-1); + CheckEquals(ANumRanges, MyWorksheet.NumPrintRanges, 'Print range count mismatch'); + for j:=1 to ANumRanges do + begin + rng := MyWorksheet.GetPrintRange(j-1); + CheckEquals(SollRanges[j].Row1, rng.Row1, Format('Row1 mismatch at i=%d, j=%d', [i, j])); + CheckEquals(SollRanges[j].Row2, rng.Row2, Format('Row2 mismatch at i=%d, j=%d', [i, j])); + CheckEquals(SollRanges[j].Col1, rng.Col1, Format('Col1 mismatch at i=%d, j=%d', [i, j])); + CheckEquals(SollRanges[j].Col2, rng.Col2, Format('Col2 mismatch at i=%d, j=%d', [i, j])); + end; + end; + finally + MyWorkbook.Free; + DeleteFile(TempFile); + end; +end; + + { Tests for BIFF2 file format } procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_BIFF2_PageMargins_1sheet_0; @@ -1670,6 +1733,25 @@ begin TestWriteRead_PageLayout(sfOpenDocument, 3, 9); end; +procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_ODS_PrintRanges_1sheet_1Range; +begin + TestWriteRead_PrintRanges(sfOpenDocument, 1, 1); +end; + +procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_ODS_PrintRanges_1sheet_2Ranges; +begin + TestWriteRead_PrintRanges(sfOpenDocument, 1, 2); +end; + +procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_ODS_PrintRanges_2sheet_1Range; +begin + TestWriteRead_PrintRanges(sfOpenDocument, 2, 1); +end; + +procedure TSpreadWriteReadPageLayoutTests.TestWriteRead_ODS_PrintRanges_2sheet_2Ranges; +begin + TestWriteRead_PrintRanges(sfOpenDocument, 2, 2); +end; initialization RegisterTest(TSpreadWriteReadPageLayoutTests);