diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index 90c7a4d7b..6ac3ef059 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -42,7 +42,7 @@ uses fpszipper, {$ENDIF} fpstypes, fpspreadsheet, fpsReaderWriter, fpsutils, fpsHeaderFooterParser, - fpsNumFormat, fpsNumFormatParser, fpsxmlcommon; + fpsNumFormat, fpsNumFormatParser, fpsxmlcommon, fpsPagelayout; type TDateModeODS=( @@ -131,7 +131,8 @@ type procedure ReadAutomaticStyles(AStylesNode: TDOMNode); procedure ReadMasterStyles(AStylesNode: TDOMNode); procedure ReadNumFormats(AStylesNode: TDOMNode); - function ReadPageLayout(AStylesNode: TDOMNode; ATableStyleName: String): PsPageLayout; + procedure ReadPageLayout(AStylesNode: TDOMNode; ATableStyleName: String; + APageLayout: TsPageLayout); procedure ReadSettings(AOfficeSettingsNode: TDOMNode); procedure ReadStyles(AStylesNode: TDOMNode); { Record writing methods } @@ -356,8 +357,23 @@ type public Name: String; PageLayout: TsPageLayout; + constructor Create; + destructor Destroy; override; end; + constructor TPageLayoutData.Create; + begin + inherited; + PageLayout := TsPageLayout.Create(nil); + end; + + destructor TPageLayoutData.destroy; + begin + PageLayout.Free; + inherited; + end; + +type { MasterPage items stored in MasterPageList } TMasterPageData = class public @@ -404,6 +420,7 @@ type StyleName: String; end; + {******************************************************************************} { TsSpreadOpenDocHeaderFooterParser } {******************************************************************************} @@ -1278,6 +1295,7 @@ var fntSize: Double; fntStyle: TsHeaderFooterFontStyles; fntColor: TsColor; + n: Integer; begin if not Assigned(AStylesNode) then exit; @@ -1309,7 +1327,6 @@ begin begin // Read page layout parameters data := TPageLayoutData.Create; - InitPageLayout(data.PageLayout); data.Name := GetAttrValue(layoutNode, 'style:name'); node := layoutNode.FirstChild; @@ -1355,51 +1372,52 @@ begin begin if s[Length(s)] = '%' then Delete(s, Length(s), 1); data.PageLayout.ScalingFactor := round(StrToFloat(s, FPointSeparatorSettings)); - Exclude(data.PageLayout.Options, poFitPages); + with data.PageLayout do Options := Options - [poFitPages]; end; s := GetAttrValue(node, 'style:scale-to-X'); if s <> '' then begin data.PageLayout.FitWidthToPages := StrToInt(s); - Include(data.PageLayout.Options, poFitPages); + with data.PageLayout do Options := Options + [poFitPages]; end; s := GetAttrValue(node, 'style:scale-to-Y'); if s <> '' then begin data.PageLayout.FitHeightToPages := StrToInt(s); - Include(data.PageLayout.Options, poFitPages); + with data.PageLayout do Options := Options + [poFitPages]; end; s := GetAttrValue(node, 'style:table-centering'); case s of 'both': - data.PageLayout.Options := data.PageLayout.Options + [poHorCentered, poVertCentered]; + with data.PageLayout do Options := Options + [poHorCentered, poVertCentered]; 'horizontal': - data.PageLayout.Options := data.PageLayout.Options + [poHorCentered] - [poVertCentered]; + with data.PageLayout do Options := Options + [poHorCentered] - [poVertCentered]; 'vertical': - data.PageLayout.Options := data.PageLayout.Options - [poHorCentered] + [poVertCentered]; + with data.PageLayout do Options := Options - [poHorCentered] + [poVertCentered]; end; s := GetAttrValue(node, 'style:print'); if pos('grid', s) > 0 then - Include(data.PageLayout.Options, poPrintGridLines); + with data.PageLayout do Options := Options + [poPrintGridLines]; if pos('headers', s) > 0 then - Include(data.PageLayout.Options, poPrintHeaders); + with data.PageLayout do Options := Options + [poPrintHeaders]; if pos('annotations', s) > 0 then - Include(data.PageLayout.Options, poPrintCellComments); + with data.PageLayout do Options := Options + [poPrintCellComments]; s := GetAttrValue(node, 'style:print-page-order'); if s = 'ltr' then // "left-to-right", the other option is "ttb = top-to-bottom" - Include(data.PageLayout.Options, poPrintPagesByRows); + with data.PageLayout do Options := Options + [poPrintPagesByRows]; s := GetAttrValue(node, 'style:first-page-number'); if s = 'continue' then - Exclude(data.PageLayout.Options, poUseStartPageNumber) + with Data.PageLayout do Options := Options - [poUseStartPageNumber] else - if TryStrToInt(s, data.PageLayout.StartPageNumber) then - Include(data.PageLayout.Options, poUseStartPageNumber); + if TryStrToInt(s, n) then + data.PageLayout.StartPageNumber := n; + // Sets poUseStartPageNumber automatically FPageLayoutList.Add(data); end else @@ -1459,7 +1477,7 @@ var nodeName: String; s: String; data: TMasterPageData; - pagelayout: PsPageLayout; + pagelayout: TsPageLayout; j: Integer; begin @@ -1478,13 +1496,13 @@ begin for j:=0 to FPageLayoutList.Count-1 do if TPageLayoutData(FPageLayoutList[j]).Name = s then begin - pageLayout := @TPageLayoutData(FPageLayoutList[j]).PageLayout; + pageLayout := TPageLayoutData(FPageLayoutList[j]).PageLayout; break; end; if pagelayout = nil then exit; - data := TMasterPageData.create; + data := TMasterPageData.Create; data.Name := GetAttrValue(masternode, 'style:name'); data.PageLayoutName := s; FMasterPageList.Add(data); @@ -1496,37 +1514,37 @@ begin begin s := ReadHeaderFooterText(styleNode); if s <> '' then - pageLayout^.Headers[HEADER_FOOTER_INDEX_ODD] := s; + pageLayout.Headers[HEADER_FOOTER_INDEX_ODD] := s; end else if nodeName = 'style:header-left' then begin s := ReadHeaderFooterText(styleNode); if s <> '' then begin - pageLayout^.Headers[HEADER_FOOTER_INDEX_EVEN] := s; - Include(pageLayout^.Options, poDifferentOddEven); + pageLayout.Headers[HEADER_FOOTER_INDEX_EVEN] := s; + with pageLayout do Options := Options + [poDifferentOddEven]; end; s := GetAttrValue(styleNode, 'style:display'); if s = 'false' then - Exclude(pagelayout^.Options, poDifferentOddEven); + with pageLayout do Options := Options - [poDifferentOddEven]; end else if nodeName = 'style:footer' then begin s := ReadHeaderFooterText(styleNode); if s <> '' then - pageLayout^.Footers[HEADER_FOOTER_INDEX_ODD] := s; + pageLayout.Footers[HEADER_FOOTER_INDEX_ODD] := s; end else if nodeName = 'style:footer-left' then begin s := ReadHeaderFooterText(styleNode); if s <> '' then begin - pageLayout^.Footers[HEADER_FOOTER_INDEX_EVEN] := s; - Include(pageLayout^.Options, poDifferentOddEven); + pageLayout.Footers[HEADER_FOOTER_INDEX_EVEN] := s; + with pageLayout do Options := Options + [poDifferentOddEven]; end; s := GetAttrValue(styleNode, 'style:display'); if s = 'false' then - Exclude(pagelayout^.Options, poDifferentOddEven); + with pagelayout do Options := Options - [poDifferentOddEven]; end; styleNode := styleNode.NextSibling; end; @@ -2142,7 +2160,6 @@ var StylesNode: TDOMNode; OfficeSettingsNode: TDOMNode; nodename: String; - pageLayout: PsPageLayout; XMLStream: TStream; sheet: TsWorksheet; tablestyleName: String; @@ -2225,14 +2242,10 @@ begin // Process each row inside the sheet and process each cell of the row ReadRowsAndCells(TableNode); // Read page layout - pageLayout := ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name')); - if pageLayout <> nil then - begin - FWorksheet.PageLayout := pagelayout^; - // Repeated cols/rows already have been determined. - FWorksheet.PageLayout.RepeatedRows := FRepeatedRows; - FWorksheet.PageLayout.RepeatedCols := FRepeatedCols; - end; + ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name'), FWorksheet.PageLayout); + // Repeated cols/rows already have been determined. + FWorksheet.PageLayout.SetRepeatedRows(FRepeatedRows.FirstIndex, FRepeatedRows.LastIndex); + FWorksheet.PageLayout.SetRepeatedCols(FRepeatedCols.FirstIndex, FRepeatedCols.LastIndex); // Read print ranges ReadPrintRanges(TableNode, FWorksheet); // Apply table style @@ -2925,8 +2938,8 @@ end; Then seeks the FMasterPageList for the entry with the determined master page name. This entry contains the name of the associated PageLayoutData stored in the PageLayoutList which, finally, contains the requested PageLayout record. } -function TsSpreadOpenDocReader.ReadPageLayout(AStylesNode: TDOMNode; - ATableStyleName: String): PsPageLayout; +procedure TsSpreadOpenDocReader.ReadPageLayout(AStylesNode: TDOMNode; + ATableStyleName: String; APageLayout: TsPageLayout); var nodeName, s: String; node: TDOMNode; @@ -2935,8 +2948,6 @@ var pageLayoutData: TPageLayoutData; i, j: Integer; begin - Result := nil; - if AStylesNode = nil then exit; @@ -2971,7 +2982,7 @@ begin if pageLayoutData.Name = masterPageData.PageLayoutName then begin { Found: Return a pointer to the PageLayout record stored in the list } - Result := @pageLayoutData.PageLayout; + APageLayout.Assign(pageLayoutData.PageLayout); exit; end; end; @@ -3057,7 +3068,7 @@ begin end; end; // Add found range to worksheet - ASheet.AddPrintRange(r1, c1, r2, c2); + ASheet.PageLayout.AddPrintRange(r1, c1, r2, c2); end; finally L.Free; @@ -4804,9 +4815,9 @@ begin // Cell block of print range srng := ''; - for j := 0 to ASheet.NumPrintRanges - 1 do + for j := 0 to ASheet.PageLayout.NumPrintRanges - 1 do begin - prng := ASheet.GetPrintRange(j); + prng := ASheet.PageLayout.PrintRange[j]; srng := srng + ';' + Format('[$%s.%s]', [ sheetname, GetCellRangeString(prng.Row1, prng.Col1, prng.Row2, prng.Col2, []) ]); @@ -5638,7 +5649,7 @@ var begin hasHeader := false; hasFooter := false; - for i:=0 to High(APageLayout.Headers) do + for i:=0 to 2 do begin if APageLayout.Headers[i] <> '' then hasHeader := true; if APageLayout.Footers[i] <> '' then hasFooter := true; @@ -5742,12 +5753,12 @@ var srng: String; sheetName: String; begin - if ASheet.NumPrintRanges > 0 then + if ASheet.PageLayout.NumPrintRanges > 0 then begin srng := ''; - for i := 0 to ASheet.NumPrintRanges - 1 do + for i := 0 to ASheet.PageLayout.NumPrintRanges - 1 do begin - rng := ASheet.GetPrintRange(i); + rng := ASheet.PageLayout.PrintRange[i]; if pos(' ', ASheet.Name) > 0 then sheetName := ''' + UTF8TextToXMLText(ASheet.Name) + ''' else sheetname := UTF8TextToXMLText(ASheet.Name); diff --git a/components/fpspreadsheet/fpspagelayout.pas b/components/fpspreadsheet/fpspagelayout.pas new file mode 100644 index 000000000..67c0b3340 --- /dev/null +++ b/components/fpspreadsheet/fpspagelayout.pas @@ -0,0 +1,453 @@ +unit fpsPageLayout; + +interface + +uses + SysUtils, fpsTypes; + +type + {@@ Class defining parameters for printing by the Office applications } + TsPageLayout = class + private + FWorksheet: pointer; + FOrientation: TsPageOrientation; + FPageWidth: Double; + FPageHeight: Double; + FLeftMargin: Double; + FRightMargin: Double; + FTopMargin: Double; + FBottomMargin: Double; + FHeaderMargin: Double; + FFooterMargin: Double; + FStartPageNumber: Integer; + FScalingFactor: Integer; + FFitWidthToPages: Integer; + FFitHeightToPages: Integer; + FCopies: Integer; + FOptions: TsPrintOptions; + FHeaders: array[0..2] of String; + FFooters: array[0..2] of String; + FHeaderImages: array[TsHeaderFooterSection] of TsHeaderFooterImage; + FFooterImages: array[TsHeaderFooterSection] of TsHeaderFooterImage; + FRepeatedCols: TsRowColRange; + FRepeatedRows: TsRowColRange; + FPrintRanges: TsCellRangeArray; + + function GetFooterImages(ASection: TsHeaderFooterSection): TsHeaderFooterImage; + function GetFooters(AIndex: Integer): String; + function GetHeaderImages(ASection: TsHeaderFooterSection): TsHeaderFooterImage; + function GetHeaders(AIndex: Integer): String; + procedure SetFitHeightToPages(AValue: Integer); + procedure SetFitWidthToPages(AValue: Integer); + procedure SetFooters(AIndex: Integer; const AValue: String); + procedure SetHeaders(AIndex: Integer; const AValue: String); + procedure SetScalingFactor(AValue: Integer); + procedure SetStartPageNumber(AValue: Integer); + + public + constructor Create(AWorksheet: pointer); + procedure Assign(ASource: TsPageLayout); + + { Images embedded in header and/or footer } + procedure AddHeaderImage(ASection: TsHeaderFooterSection; + const AFilename: String); + procedure AddFooterImage(ASection: TsHeaderFooterSection; + const AFilename: String); + + { Repeated rows and columns } + function HasRepeatedCols: Boolean; + function HasRepeatedRows: Boolean; + procedure SetRepeatedCols(AFirstCol, ALastCol: Cardinal); + procedure SetRepeatedRows(AFirstRow, ALastRow: Cardinal); + + { print ranges } + function AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload; + function AddPrintRange(const ARange: TsCellRange): Integer; overload; + function GetPrintRange(AIndex: Integer): TsCellRange; + function NumPrintRanges: Integer; + procedure RemovePrintRange(AIndex: Integer); + + {@@ Page orientation, portrait or landscape. Use spoPortrait or spoLandscape} + property Orientation: TsPageOrientation + read FOrientation write FOrientation; + {@@ Page width, in millimeters. + Defined for non-rotated orientation, mostly Portrait } + property PageWidth: Double + read FPageWidth write FPageWidth; + {@@ Page height, in millimeters. + Defined for non-rotated orientation, mostly Portrait } + property PageHeight: Double + read FPageHeight write FPageHeight; + {@@ Left page margin, in millimeters } + property LeftMargin: Double + read FLeftMargin write FLeftMargin; + {@@ Right page margin, in millimeters } + property RightMargin: Double + read FRightMargin write FRightMargin; + {@@ Top page margin, in millimeters } + property TopMargin: Double + read FTopMargin write FTopMargin; + {@@ Bottom page margin, in millimeters } + property BottomMargin: Double + read FBottomMargin write FBottomMargin; + {@@ Margin reserved for the header region, in millimeters } + property HeaderMargin: Double + read FHeaderMargin write FHeaderMargin; + {@@ Margin reserved for the footer region, in millimeters } + property FooterMargin: Double + read FFooterMargin write FFooterMargin; + {@@ Page number to be printed on the first page, default: 1 } + property StartPageNumber: Integer + read FStartPageNumber write SetStartPageNumber; + {@@ Scaling factor of the page, in percent. + PrintOptions must not contain poFitPages (is removed automatically) } + property ScalingFactor: Integer + read FScalingFactor write SetScalingFactor; + {@@ Count of pages scaled such they they fon on a single page height. + 0 means: use as many pages as needed. + Options must contain poFitPages (is set automatically) } + property FitHeightToPages: Integer + read FFitHeightToPages write SetFitHeightToPages; + {@@ Count of pages scaled such that they fit on one page width. + 0 means: use as many pages as needed. + Options must contain poFitPages (is set automatically) } + property FitWidthToPages: Integer + read FFitWidthToPages write SetFitWidthToPages; + {@@ Number of copies to be printed } + property Copies: Integer + read FCopies write FCopies; + + {@@ A variety of options controlling the output - see TsPrintOption } + property Options: TsPrintOptions + read FOptions write FOptions; + + {@@ Headers and footers are in Excel syntax: + - left/center/right sections begin with &L / &C / &R + - page number: &P + - page count: &N + - current date: &D + - current time: &T + - sheet name: &A + - file name without path: &F + - file path without file name: &Z + - image: &G (must be provided by "AddHeaderImage" or "AddFooterImage") + - bold/italic/underlining/double underlining/strike out/shadowed/ + outlined/superscript/subscript on/off: + &B / &I / &U / &E / &S / &H + &O / &X / &Y + There can be three headers/footers, for first ([0]) page and + odd ([1])/even ([2]) page numbers. + This is activated by Options poDifferentOddEven and poDifferentFirst. + Array index 1 contains the strings if these options are not used. } + property Headers[AIndex: Integer]: String + read GetHeaders write SetHeaders; + property Footers[AIndex: Integer]: String + read GetFooters write SetFooters; + + {@@ Count of worksheet columns repeated at the left of the printed page } + property RepeatedCols: TsRowColRange + read FRepeatedCols; + {@@ Count of worksheet rows repeated at the top of the printed page } + property RepeatedRows: TsRowColRange + read FRepeatedRows; + + {@@ TsCellRange record of the print range with the specified index. } + property PrintRange[AIndex: Integer]: TsCellRange + read GetPrintRange; + + {@@ Images inserted into footer } + property FooterImages[ASection: TsHeaderFooterSection]: TsHeaderFooterImage + read GetFooterImages; + {@@ Images inserted into header } + property HeaderImages[ASection: TsHeaderFooterSection]: TsHeaderFooterImage + read GetHeaderImages; + end; + + +implementation + +uses + Math, + fpsUtils, fpSpreadsheet; + +constructor TsPageLayout.Create(AWorksheet: Pointer); +var + hfs: TsHeaderFooterSection; + i: Integer; +begin + inherited Create; + FWorksheet := AWorksheet; + + FOrientation := spoPortrait; + FPageWidth := 210; + FPageHeight := 297; + FLeftMargin := InToMM(0.7); + FRightMargin := InToMM(0.7); + FTopMargin := InToMM(0.78740157499999996); + FBottomMargin := InToMM(0.78740157499999996); + FHeaderMargin := InToMM(0.3); + FFooterMargin := InToMM(0.3); + FStartPageNumber := 1; + FScalingFactor := 100; // Percent + FFitWidthToPages := 0; // use as many pages as needed + FFitHeightToPages := 0; + FCopies := 1; + + FOptions := []; + + for i:=0 to 2 do FHeaders[i] := ''; + for i:=0 to 2 do FFooters[i] := ''; + + for hfs in TsHeaderFooterSection do + begin + InitHeaderFooterImageRecord(FHeaderImages[hfs]); + InitHeaderFooterImageRecord(FFooterImages[hfs]); + end; + + FRepeatedRows.FirstIndex := UNASSIGNED_ROW_COL_INDEX; + FRepeatedRows.LastIndex := UNASSIGNED_ROW_COL_INDEX; + FRepeatedCols.FirstIndex := UNASSIGNED_ROW_COL_INDEX; + FRepeatedCols.LastIndex := UNASSIGNED_ROW_COL_INDEX; +end; + +{@@ Copies the data from the provided PageLayout ASource } +procedure TsPageLayout.Assign(ASource: TsPageLayout); +var + i: Integer; + hfs: TsHeaderFooterSection; +begin + FOrientation := ASource.Orientation; + FPageWidth := ASource.PageWidth; + FPageHeight := ASource.PageHeight; + FLeftMargin := ASource.LeftMargin; + FRightMargin := ASource.RightMargin; + FTopMargin := ASource.TopMargin; + FBottomMargin := ASource.BottomMargin; + FHeaderMargin := ASource.HeaderMargin; + FFooterMargin := ASource.FooterMargin; + FStartPageNumber := ASource.StartPageNumber; + FScalingFactor := ASource.ScalingFactor; + FFitWidthToPages := ASource.FitWidthToPages; + FFitHeightToPages := ASource.FitHeightToPages; + FCopies := ASource.Copies; + FOptions := ASource.Options; + for i:=0 to 2 do + begin + FHeaders[i] := ASource.Headers[i]; + FFooters[i] := ASource.Footers[i]; + end; + for hfs in TsHeaderFooterSection do + begin + FHeaderImages[hfs] := ASource.HeaderImages[hfs]; + FFooterImages[hfs] := ASource.FooterImages[hfs]; + end; + FRepeatedCols := ASource.RepeatedCols; + FRepeatedRows := ASource.RepeatedRows; + SetLength(FPrintRanges, Length(ASource.FPrintRanges)); + for i:=0 to High(FPrintRanges) do + FPrintranges[i] := ASource.FPrintRanges[i]; +end; + +procedure TsPageLayout.AddHeaderImage(ASection: TsHeaderFooterSection; + const AFilename: String); +var + book: TsWorkbook; + idx: Integer; +begin + book := TsWorksheet(FWorksheet).Workbook; + idx := book.FindEmbeddedStream(AFilename); + if idx = -1 then + idx := book.AddEmbeddedStream(AFilename); + FHeaderImages[ASection].Index := idx; +end; + +procedure TsPageLayout.AddFooterImage(ASection: TsHeaderFooterSection; + const AFileName: String); +var + book: TsWorkbook; + idx: Integer; +begin + book := TsWorksheet(FWorksheet).Workbook; + idx := book.FindEmbeddedStream(AFilename); + if idx = -1 then + idx := book.AddEmbeddedStream(AFilename); + FFooterImages[ASection].Index := idx; +end; + +{@@ ---------------------------------------------------------------------------- + Adds a print range defined by the row/column indexes of its corner cells. +-------------------------------------------------------------------------------} +function TsPageLayout.AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; +begin + Result := Length(FPrintRanges); + SetLength(FPrintRanges, Result + 1); + with FPrintRanges[Result] do + begin + if ARow1 < ARow2 then + begin + Row1 := ARow1; + Row2 := ARow2; + end else + begin + Row1 := ARow2; + Row2 := ARow1; + end; + if ACol1 < ACol2 then + begin + Col1 := ACol1; + Col2 := ACol2; + end else + begin + Col1 := ACol2; + Col2 := ACol1; + end; + end; +end; + +{@@ ---------------------------------------------------------------------------- + Adds a print range defined by a TsCellRange record +-------------------------------------------------------------------------------} +function TsPageLayout.AddPrintRange(const ARange: TsCellRange): Integer; +begin + Result := AddPrintRange(ARange.Row1, ARange.Col1, ARange.Row2, ARange.Col2); +end; + +function TsPageLayout.GetFooterImages( + ASection: TsHeaderFooterSection): TsHeaderFooterImage; +begin + Result := FFooterImages[ASection]; +end; + +function TsPageLayout.GetFooters(AIndex: Integer): String; +begin + if InRange(AIndex, 0, High(FFooters)) then + Result := FFooters[AIndex] + else + raise Exception.Create('[TsPageLayout.GetFooters] Illegal index.'); +end; + +function TsPageLayout.GetHeaderImages( + ASection: TsHeaderFooterSection): TsHeaderFooterImage; +begin + Result := FHeaderImages[ASection]; +end; + +function TsPageLayout.GetHeaders(AIndex: Integer): String; +begin + if InRange(AIndex, 0, High(FHeaders)) then + Result := FHeaders[AIndex] + else + raise Exception.Create('[TsPageLayout.GetHeaders] Illegal index.'); +end; + +{@@ ---------------------------------------------------------------------------- + Returns the TsCellRange record of the print range with the specified index. +-------------------------------------------------------------------------------} +function TsPageLayout.GetPrintRange(AIndex: Integer): TsCellRange; +begin + if InRange(AIndex, 0, High(FPrintRanges)) then + Result := FPrintRanges[AIndex] + else + raise Exception.Create('[TsPageLayout.GetPrintRange] Illegal index.'); +end; + +{@@ ---------------------------------------------------------------------------- + Checks whether the worksheet defines columns to be printed repeatedly at the + left of each printed page +-------------------------------------------------------------------------------} +function TsPageLayout.HasRepeatedCols: Boolean; +begin + Result := Cardinal(FRepeatedCols.FirstIndex) <> Cardinal(UNASSIGNED_ROW_COL_INDEX); +end; + +{@@ ---------------------------------------------------------------------------- + Checks whether the worksheet defines rows to be printed repeatedly at the + top of each printed page +-------------------------------------------------------------------------------} +function TsPageLayout.HasRepeatedRows: Boolean; +begin + Result := Cardinal(FRepeatedRows.FirstIndex) <> Cardinal(UNASSIGNED_ROW_COL_INDEX); +end; + +{@@ ---------------------------------------------------------------------------- + Returns the count of print ranges defined for this worksheet +-------------------------------------------------------------------------------} +function TsPageLayout.NumPrintRanges: Integer; +begin + Result := Length(FPrintRanges); +end; + +{@@ ---------------------------------------------------------------------------- + Removes the print range specified by the index +-------------------------------------------------------------------------------} +procedure TsPageLayout.RemovePrintRange(AIndex: Integer); +var + i: Integer; +begin + if not InRange(AIndex, 0, High(FPrintRanges)) then exit; + for i := AIndex + 1 to High(FPrintRanges) do + FPrintRanges[i - 1] := FPrintRanges[i]; + SetLength(FPrintRanges, Length(FPrintRanges)-1); +end; + +procedure TsPageLayout.SetFitHeightToPages(AValue: Integer); +begin + FFitHeightToPages := AValue; + Include(FOptions, poFitPages); +end; + +procedure TsPageLayout.SetFitWidthToPages(AValue: Integer); +begin + FFitWidthToPages := AValue; + Include(FOptions, poFitPages); +end; + +procedure TsPageLayout.SetFooters(AIndex: Integer; const AValue: String); +begin + FFooters[AIndex] := AValue; +end; + +procedure TsPageLayout.SetHeaders(AIndex: Integer; const AValue: String); +begin + FHeaders[AIndex] := AValue; +end; + +procedure TsPageLayout.SetRepeatedCols(AFirstCol, ALastCol: Cardinal); +begin + if AFirstCol < ALastCol then + begin + FRepeatedCols.FirstIndex := AFirstCol; + FRepeatedCols.LastIndex := ALastCol; + end else + begin + FRepeatedCols.FirstIndex := ALastCol; + FRepeatedCols.LastIndex := AFirstCol; + end; +end; + +procedure TsPageLayout.SetRepeatedRows(AFirstRow, AlastRow: Cardinal); +begin + if AFirstRow < ALastRow then + begin + FRepeatedRows.FirstIndex := AFirstRow; + FRepeatedRows.LastIndex := ALastRow; + end else + begin + FRepeatedRows.FirstIndex := ALastRow; + FRepeatedRows.LastIndex := AFirstRow; + end; +end; + +procedure TsPageLayout.SetScalingFactor(AValue: Integer); +begin + FScalingFactor := AValue; + Exclude(FOptions, poFitPages); +end; + +procedure TsPageLayout.SetStartPageNumber(AValue: Integer); +begin + FStartPageNumber := AValue; + Include(FOptions, poUseStartPageNumber); +end; + +end. diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 2b92afd06..82899c8a8 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -34,7 +34,7 @@ uses clocale, {$endif}{$endif}{$endif} Classes, SysUtils, fpimage, AVL_Tree, avglvltree, lconvencoding, - fpsTypes, fpsClasses, fpsNumFormat; + fpsTypes, fpsClasses, fpsNumFormat, fpsPageLayout; type { Forward declarations } @@ -128,7 +128,7 @@ type FDefaultRowHeight: Single; // in "character heights", i.e. line count FSortParams: TsSortParams; // Parameters of the current sorting operation FBiDiMode: TsBiDiMode; - FPrintRanges: TsCellRangeArray; + FPageLayout: TsPageLayout; FOnChangeCell: TsCellEvent; FOnChangeFont: TsCellEvent; FOnCompareCells: TsCellCompareEvent; @@ -162,9 +162,6 @@ type procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal); public - {@@ Page layout parameters for printing } - PageLayout: TsPageLayout; - { Base methods } constructor Create; destructor Destroy; override; @@ -505,18 +502,6 @@ type AOffsetX: Integer = 0; AOffsetY: Integer = 0; AScaleX: Double = 1.0; AScaleY: Double = 1.0): Integer; - { Print ranges } - function AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload; - function AddPrintRange(const ARange: TsCellRange): Integer; overload; - function GetPrintRange(AIndex: Integer): TsCellRange; - function NumPrintRanges: Integer; - procedure RemovePrintRange(AIndex: Integer); - - procedure SetRepeatedPrintCols(AFirstCol: Cardinal; ALastCol: Cardinal = UNASSIGNED_ROW_COL_INDEX); - procedure SetRepeatedPrintRows(AFirstRow: Cardinal; ALastRow: Cardinal = UNASSIGNED_ROW_COL_INDEX); - function HasRepeatedPrintCols: Boolean; - function HasRepeatedPrintRows: Boolean; - // Notification of changed cells procedure ChangedCell(ARow, ACol: Cardinal); procedure ChangedFont(ARow, ACol: Cardinal); @@ -539,6 +524,8 @@ type {@@ Name of the sheet. In the popular spreadsheet applications this is displayed at the tab of the sheet. } property Name: string read FName write SetName; + {@@ Parameters to be used for printing by the Office applications } + property PageLayout: TsPageLayout read FPageLayout write FPageLayout; {@@ List of all row records of the worksheet having a non-standard row height } property Rows: TIndexedAVLTree read FRows; {@@ Workbook to which the worksheet belongs } @@ -1028,7 +1015,7 @@ begin FHyperlinks := TsHyperlinks.Create; FImages := TFPList.Create; - InitPageLayout(PageLayout); + FPageLayout := TsPageLayout.Create(self); FDefaultColWidth := 12; FDefaultRowHeight := 1; @@ -1038,8 +1025,8 @@ begin FLastRowIndex := UNASSIGNED_ROW_COL_INDEX; FLastColIndex := UNASSIGNED_ROW_COL_INDEX; - FActiveCellRow := UNASSIGNED_ROW_COL_INDEX; // Cardinal(-1); - FActiveCellCol := UNASSIGNED_ROW_COL_INDEX; // Cardinal(-1); + FActiveCellRow := UNASSIGNED_ROW_COL_INDEX; + FActiveCellCol := UNASSIGNED_ROW_COL_INDEX; FOptions := [soShowGridLines, soShowHeaders]; end; @@ -1056,6 +1043,7 @@ begin RemoveAllRows; RemoveAllCols; + FPageLayout.Free; FCells.Free; FRows.Free; FCols.Free; @@ -3482,121 +3470,6 @@ begin RemoveImage(i); end; -{@@ ---------------------------------------------------------------------------- - Adds a print range defined by the row/column indexes of its corner cells. --------------------------------------------------------------------------------} -function TsWorksheet.AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; -begin - Result := Length(FPrintRanges); - SetLength(FPrintRanges, Result + 1); - with FPrintRanges[Result] do - begin - if ARow1 < ARow2 then - begin - Row1 := ARow1; - Row2 := ARow2; - end else - begin - Row1 := ARow2; - Row2 := ARow1; - end; - if ACol1 < ACol2 then - begin - Col1 := ACol1; - Col2 := ACol2; - end else - begin - Col1 := ACol2; - Col2 := ACol1; - end; - end; -end; - -{@@ ---------------------------------------------------------------------------- - Adds a print range defined by a TsCellRange record --------------------------------------------------------------------------------} -function TsWorksheet.AddPrintRange(const ARange: TsCellRange): Integer; -begin - Result := AddPrintRange(ARange.Row1, ARange.Col1, ARange.Row2, ARange.Col2); -end; - -{@@ ---------------------------------------------------------------------------- - Returns the TsCellRange record of the print range with the specified index. --------------------------------------------------------------------------------} -function TsWorksheet.GetPrintRange(AIndex: Integer): TsCellRange; -begin - Result := FPrintRanges[AIndex]; -end; - -{@@ ---------------------------------------------------------------------------- - Returns the count of print ranges defined for this worksheet --------------------------------------------------------------------------------} -function TsWorksheet.NumPrintRanges: Integer; -begin - Result := Length(FPrintRanges); -end; - -{@@ ---------------------------------------------------------------------------- - Removes the print range specified by the index --------------------------------------------------------------------------------} -procedure TsWorksheet.RemovePrintRange(AIndex: Integer); -var - i: Integer; -begin - if not InRange(AIndex, 0, High(FPrintRanges)) then exit; - for i := AIndex + 1 to High(FPrintRanges) do - FPrintRanges[i - 1] := FPrintRanges[i]; - SetLength(FPrintRanges, Length(FPrintRanges)-1); -end; - -{@@ ---------------------------------------------------------------------------- - Defines a range of header columns for printing repeated on every page --------------------------------------------------------------------------------} -procedure TsWorksheet.SetRepeatedPrintCols(AFirstCol, ALastCol: Cardinal); -begin - if AFirstCol < ALastCol then - begin - PageLayout.RepeatedCols.FirstIndex := AFirstCol; - PageLayout.RepeatedCols.LastIndex := ALastCol; - end else - begin - PageLayout.RepeatedCols.FirstIndex := ALastCol; - PageLayout.RepeatedCols.LastIndex := AFirstCol; - end; -end; - -{@@ ---------------------------------------------------------------------------- - Defines a range of header rows for printing repeated on every page --------------------------------------------------------------------------------} -procedure TsWorksheet.SetRepeatedPrintRows(AFirstRow, ALastRow: Cardinal); -begin - if AFirstRow < ALastRow then - begin - PageLayout.RepeatedRows.FirstIndex := AFirstRow; - PageLayout.RepeatedRows.LastIndex := ALastRow; - end else - begin - PageLayout.RepeatedRows.FirstIndex := ALastRow; - PageLayout.RepeatedRows.LastIndex := AFirstRow; - end; -end; - -{@@ ---------------------------------------------------------------------------- - Determines whether the worksheet defines repeated print header columns --------------------------------------------------------------------------------} -function TsWorksheet.HasRepeatedPrintCols: Boolean; -begin - Result := Cardinal(PageLayout.RepeatedCols.FirstIndex) <> Cardinal(UNASSIGNED_ROW_COL_INDEX); -end; - -{@@ ---------------------------------------------------------------------------- - Determines whether the worksheet defines repeated print header rows --------------------------------------------------------------------------------} -function TsWorksheet.HasRepeatedPrintRows: Boolean; -begin - Result := Cardinal(PageLayout.RepeatedRows.FirstIndex) <> Cardinal(UNASSIGNED_ROW_COL_INDEX); -end; - {@@ ---------------------------------------------------------------------------- Removes the comment from a cell and releases the memory occupied by the node. -------------------------------------------------------------------------------} diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas index 6b1fc4ee2..12a20858d 100644 --- a/components/fpspreadsheet/fpstypes.pas +++ b/components/fpspreadsheet/fpstypes.pas @@ -674,6 +674,20 @@ type {@@ Pointer to a TCell record } PCell = ^TCell; + {@@ Embedded image } + TsImage = record + Row, Col: Cardinal; + Index: Integer; + OffsetX, OffsetY: Double; // mm + ScaleX, ScaleY: Double; + end; + PsImage = ^TsImage; + + {@@ Image embedded in header or footer} + TsHeaderFooterImage = record + Index: Integer; + end; + {@@ Page orientation for printing } TsPageOrientation = (spoPortrait, spoLandscape); @@ -686,48 +700,8 @@ type {@@ Set of options used by the page layout } TsPrintOptions = set of TsPrintOption; - {@@ Record defining parameters for printing by the Office applications } - TsPageLayout = record // all lengths in mm - Orientation: TsPageOrientation; - PageWidth: Double; // for "normal" orientation (mostly portrait) - PageHeight: Double; - LeftMargin: Double; - RightMargin: Double; - TopMargin: Double; - BottomMargin: Double; - HeaderMargin: Double; - FooterMargin: Double; - StartPageNumber: Integer; - ScalingFactor: Integer; // in percent - FitWidthToPages: Integer; - FitHeightToPages: Integer; - Copies: Integer; - Options: TsPrintOptions; - { Headers and footers are in Excel syntax: - - left/center/right sections begin with &L / &C / &R - - page number: &P - - page count: &N - - current date: &D - - current time: &T - - sheet name: &A - - file name without path: &F - - file path without file name: &Z - - bold/italic/underlining/double underlining/strike out/shadowed/ - outlined/superscript/subscript on/off: - &B / &I / &U / &E / &S / &H - &O / &X / &Y - There can be three headers/footers, for first ([0]) page and - odd ([1])/even ([2]) page numbers. - This is activated by Options poDifferentOddEven and poDifferentFirst. - Array index 1 contains the strings if these options are not used. } - Headers: array[0..2] of string; - Footers: array[0..2] of string; - RepeatedCols: TsRowColRange; - RepeatedRows: TsRowColRange; - end; - - {@@ Pointer to a page layout record } - PsPageLayout = ^TsPageLayout; + {@@ Headers and footers are divided into three parts: left, center and right } + TsHeaderFooterSection = (hfsLeft, hfsCenter, hfsRight); const {@@ Indexes to be used for the various headers and footers } @@ -774,15 +748,6 @@ type TsStreamParam = (spClipboard, spWindowsClipboardHTML); TsStreamParams = set of TsStreamParam; - {@@ Embedded image } - TsImage = record - Row, Col: Cardinal; - Index: Integer; - OffsetX, OffsetY: Double; // mm - ScaleX, ScaleY: Double; - end; - PsImage = ^TsImage; - implementation diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index 4f7db2e00..e94686457 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -163,7 +163,7 @@ procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload; procedure InitFormatRecord(out AValue: TsCellFormat); procedure InitImageRecord(out AValue: TsImage; ARow, ACol: Cardinal; AOffsetX, AOffsetY, AScaleX, AScaleY: Double); -procedure InitPageLayout(out APageLayout: TsPageLayout); +procedure InitHeaderFooterImageRecord(out AImage: TsHeaderFooterImage); procedure CopyCellValue(AFromCell, AToCell: PCell); function HasFormula(ACell: PCell): Boolean; @@ -2091,34 +2091,15 @@ begin end; {@@ ---------------------------------------------------------------------------- - Initializes the fields of a TsPageLayout record + Initializes the fields of a TsHeaderFooterImage record -------------------------------------------------------------------------------} -procedure InitPageLayout(out APageLayout: TsPageLayout); -var - i: Integer; +procedure InitHeaderFooterImageRecord(out AImage: TsHeaderFooterImage); begin - with APageLayout do begin - Orientation := spoPortrait; - PageWidth := 210; - PageHeight := 297; - LeftMargin := InToMM(0.7); - RightMargin := InToMM(0.7); - TopMargin := InToMM(0.78740157499999996); - BottomMargin := InToMM(0.78740157499999996); - HeaderMargin := InToMM(0.3); - FooterMargin := InToMM(0.3); - StartPageNumber := 1; - ScalingFactor := 100; // Percent - FitWidthToPages := 0; // use as many pages as needed - FitHeightToPages := 0; - Copies := 1; - Options := []; - for i:=0 to 2 do Headers[i] := ''; - for i:=0 to 2 do Footers[i] := ''; - RepeatedRows.FirstIndex := UNASSIGNED_ROW_COL_INDEX; - RepeatedRows.LastIndex := UNASSIGNED_ROW_COL_INDEX; - RepeatedCols.FirstIndex := UNASSIGNED_ROW_COL_INDEX; - RepeatedCols.LastIndex := UNASSIGNED_ROW_COL_INDEX; + with AImage do + begin + Index := -1; + //ScaleX := 1.0; + //ScaleY := 1.0; end; end; diff --git a/components/fpspreadsheet/tests/pagelayouttests.pas b/components/fpspreadsheet/tests/pagelayouttests.pas index 372d37852..67515dbfd 100644 --- a/components/fpspreadsheet/tests/pagelayouttests.pas +++ b/components/fpspreadsheet/tests/pagelayouttests.pas @@ -358,7 +358,7 @@ implementation uses typinfo, contnrs, strutils, - fpsutils, fpsHeaderFooterParser; + fpsutils, fpsHeaderFooterParser, fpsPageLayout; // uriparser, lazfileutils, fpsutils; const @@ -402,74 +402,79 @@ var begin TempFile := GetTempFileName; - InitPageLayout(sollPageLayout); - with SollPageLayout do - begin - TopMargin := 20; - BottomMargin := 30; - LeftMargin := 21; - RightMargin := 22; - HeaderMargin := 10; - FooterMargin := 11; - case AHeaderFooterMode of - 0: ; // header and footer already are empty strings - 1: Headers[HEADER_FOOTER_INDEX_ALL] := 'Test header'; - 2: Footers[HEADER_FOOTER_INDEX_ALL] := 'Test footer'; - 3: begin - Headers[HEADER_FOOTER_INDEX_ALL] := 'Test header'; - Footers[HEADER_FOOTER_INDEX_ALL] := 'Test footer'; - end; - end; - end; - - MyWorkbook := TsWorkbook.Create; + sollPageLayout := TsPageLayout.Create(nil); try - col := 0; - for p := 1 to ANumSheets do + with SollPageLayout do begin - MyWorkSheet:= MyWorkBook.AddWorksheet(PageLayoutSheet+IntToStr(p)); - for row := 0 to 9 do - Myworksheet.WriteNumber(row, 0, row+col*100+p*10000 ); - MyWorksheet.PageLayout := SollPageLayout; - end; - MyWorkBook.WriteToFile(TempFile, AFormat, true); - finally - MyWorkbook.Free; - end; - - // Open the spreadsheet - MyWorkbook := TsWorkbook.Create; - try - MyWorkbook.ReadFromFile(TempFile, AFormat); - for p := 0 to MyWorkbook.GetWorksheetCount-1 do - begin - MyWorksheet := MyWorkBook.GetWorksheetByIndex(p); - if MyWorksheet=nil then - fail('Error in test code. Failed to get worksheet by index'); - - actualPageLayout := MyWorksheet.PageLayout; - CheckEquals(sollPageLayout.TopMargin, actualPageLayout.TopMargin, EPS, 'Top margin mismatch, sheet "'+MyWorksheet.Name+'"'); - CheckEquals(sollPageLayout.BottomMargin, actualPageLayout.Bottommargin, EPS, 'Bottom margin mismatch, sheet "'+MyWorksheet.Name+'"'); - CheckEquals(sollPageLayout.LeftMargin, actualPageLayout.LeftMargin, EPS, 'Left margin mismatch, sheet "'+MyWorksheet.Name+'"'); - CheckEquals(sollPageLayout.RightMargin, actualPageLayout.RightMargin, EPS, 'Right margin mismatch, sheet "'+MyWorksheet.Name+'"'); - if (AFormat <> sfExcel2) then // No header/footer margin in BIFF2 - begin - if AHeaderFooterMode in [1, 3] then - CheckEquals(sollPageLayout.HeaderMargin, actualPageLayout.HeaderMargin, EPS, 'Header margin mismatch, sheet "'+MyWorksheet.Name+'"'); - if AHeaderFooterMode in [2, 3] then - CheckEquals(sollPageLayout.FooterMargin, actualPageLayout.FooterMargin, EPS, 'Footer margin mismatch, sheet "'+MyWorksheet.Name+'"'); + TopMargin := 20; + BottomMargin := 30; + LeftMargin := 21; + RightMargin := 22; + HeaderMargin := 10; + FooterMargin := 11; + case AHeaderFooterMode of + 0: ; // header and footer already are empty strings + 1: Headers[HEADER_FOOTER_INDEX_ALL] := 'Test header'; + 2: Footers[HEADER_FOOTER_INDEX_ALL] := 'Test footer'; + 3: begin + Headers[HEADER_FOOTER_INDEX_ALL] := 'Test header'; + Footers[HEADER_FOOTER_INDEX_ALL] := 'Test footer'; + end; end; end; + + MyWorkbook := TsWorkbook.Create; + try + col := 0; + for p := 1 to ANumSheets do + begin + MyWorkSheet:= MyWorkBook.AddWorksheet(PageLayoutSheet+IntToStr(p)); + for row := 0 to 9 do + Myworksheet.WriteNumber(row, 0, row+col*100+p*10000 ); + MyWorksheet.PageLayout.Assign(SollPageLayout); + end; + MyWorkBook.WriteToFile(TempFile, AFormat, true); + finally + MyWorkbook.Free; + end; + + // Open the spreadsheet + MyWorkbook := TsWorkbook.Create; + try + MyWorkbook.ReadFromFile(TempFile, AFormat); + for p := 0 to MyWorkbook.GetWorksheetCount-1 do + begin + MyWorksheet := MyWorkBook.GetWorksheetByIndex(p); + if MyWorksheet=nil then + fail('Error in test code. Failed to get worksheet by index'); + + actualPageLayout := MyWorksheet.PageLayout; + CheckEquals(sollPageLayout.TopMargin, actualPageLayout.TopMargin, EPS, 'Top margin mismatch, sheet "'+MyWorksheet.Name+'"'); + CheckEquals(sollPageLayout.BottomMargin, actualPageLayout.Bottommargin, EPS, 'Bottom margin mismatch, sheet "'+MyWorksheet.Name+'"'); + CheckEquals(sollPageLayout.LeftMargin, actualPageLayout.LeftMargin, EPS, 'Left margin mismatch, sheet "'+MyWorksheet.Name+'"'); + CheckEquals(sollPageLayout.RightMargin, actualPageLayout.RightMargin, EPS, 'Right margin mismatch, sheet "'+MyWorksheet.Name+'"'); + if (AFormat <> sfExcel2) then // No header/footer margin in BIFF2 + begin + if AHeaderFooterMode in [1, 3] then + CheckEquals(sollPageLayout.HeaderMargin, actualPageLayout.HeaderMargin, EPS, 'Header margin mismatch, sheet "'+MyWorksheet.Name+'"'); + if AHeaderFooterMode in [2, 3] then + CheckEquals(sollPageLayout.FooterMargin, actualPageLayout.FooterMargin, EPS, 'Footer margin mismatch, sheet "'+MyWorksheet.Name+'"'); + end; + end; + + finally + MyWorkbook.Free; + DeleteFile(TempFile); + end; finally - MyWorkbook.Free; - DeleteFile(TempFile); + SollPageLayout.Free; end; end; { ------------------------------------------------------------------------------ Main page layout test: it writes a file with a specific page layout and reads it - back. The written pagelayout ("Solllayout") must match the read pagelayout. + back. The written pagelayout ("SollLayout") must match the read pagelayout. ATestMode: 0 - Landscape page orientation for sheets 0 und 2, sheet 1 is portrait @@ -539,7 +544,7 @@ begin SetLength(SollPageLayout, ANumSheets); for p:=0 to High(SollPageLayout) do begin - InitPageLayout(sollPageLayout[p]); + sollPageLayout[p] := TsPageLayout.Create(nil); with SollPageLayout[p] do begin case ATestMode of @@ -557,7 +562,6 @@ begin begin if p = 0 then ScalingFactor := 50 else if p = 1 then ScalingFactor := 200; - Exclude(Options, poFitPages); end; 3: // Scale width to n pages begin @@ -566,7 +570,6 @@ begin 1: FitWidthToPages := 3; 2: FitWidthToPages := 1; end; - Include(Options, poFitPages); end; 4: // Scale height to n pages begin @@ -575,14 +578,12 @@ begin 1: FitHeightToPages := 3; 2: FitHeightToPages := 1; end; - Include(Options, poFitPages); end; 5: // Page number of first pge begin - Options := Options + [poUseStartPageNumber]; case p of 0: StartPageNumber := 3; - 1: Exclude(Options, poUseStartPageNumber); + 1: Options := Options - [poUseStartPageNumber]; 2: StartPageNumber := 1; end; Headers[HEADER_FOOTER_INDEX_ALL] := '&LPage &P of &N'; @@ -652,7 +653,7 @@ begin for row := 0 to 99 do for col := 0 to 29 do Myworksheet.WriteNumber(row, col, (row+1)+(col+1)*100+(p+1)*10000 ); - MyWorksheet.PageLayout := SollPageLayout[p]; + MyWorksheet.PageLayout.Assign(SollPageLayout[p]); end; MyWorkBook.WriteToFile(TempFile, AFormat, true); finally @@ -731,6 +732,9 @@ begin MyWorkbook.Free; DeleteFile(TempFile); end; + + for p:=0 to High(SollPageLayout) do + sollPageLayout[p].Free; end; { @@ -764,7 +768,7 @@ begin sheetname := PageLayoutSheet + IfThen(ASpaceInName, ' ', '') + IntToStr(i); MyWorksheet := MyWorkbook.AddWorksheet(sheetname); for j:=1 to ANumRanges do - MyWorksheet.AddPrintRange(SollRanges[j]); + MyWorksheet.PageLayout.AddPrintRange(SollRanges[j]); end; MyWorkBook.WriteToFile(TempFile, AFormat, true); finally @@ -779,10 +783,10 @@ begin for i := 1 to ANumSheets do begin MyWorksheet := MyWorkbook.GetWorksheetByIndex(i-1); - CheckEquals(ANumRanges, MyWorksheet.NumPrintRanges, 'Print range count mismatch'); + CheckEquals(ANumRanges, MyWorksheet.PageLayout.NumPrintRanges, 'Print range count mismatch'); for j:=1 to ANumRanges do begin - rng := MyWorksheet.GetPrintRange(j-1); + rng := MyWorksheet.PageLayout.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])); @@ -815,8 +819,8 @@ begin for r := 0 to 10 do for c := 0 to 10 do MyWorksheet.WriteNumber(r, c, r*100+c); - MyWorksheet.SetRepeatedPrintRows(AFirstRow, ALastRow); - MyWorksheet.SetRepeatedPrintCols(AFirstCol, ALastCol); + MyWorksheet.PageLayout.SetRepeatedRows(AFirstRow, ALastRow); + MyWorksheet.PageLayout.SetRepeatedCols(AFirstCol, ALastCol); MyWorkBook.WriteToFile(TempFile, AFormat, true); finally MyWorkbook.Free; diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 374aef9f5..a4149c5a0 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -1368,15 +1368,15 @@ begin try case AName of #06: begin // Print range - for j := 0 to AWorksheet.NumPrintRanges-1 do + for j := 0 to AWorksheet.PageLayout.NumPrintRanges-1 do begin - rng := AWorksheet.GetPrintRange(j); + rng := AWorksheet.PageLayout.PrintRange[j]; WriteRangeFormula(memstream, rng, AIndexToRef, j+1); end; end; #07: begin j := 1; - if AWorksheet.HasRepeatedPrintCols then + if AWorksheet.PageLayout.HasRepeatedCols then begin rng.Col1 := AWorksheet.PageLayout.RepeatedCols.FirstIndex; rng.Col2 := AWorksheet.PageLayout.RepeatedCols.LastIndex; @@ -1386,7 +1386,7 @@ begin WriteRangeFormula(memstream, rng, AIndexToRef, j); inc(j); end; - if AWorksheet.HasRepeatedPrintRows then + if AWorksheet.PageLayout.HasRepeatedRows then begin rng.Row1 := AWorksheet.PageLayout.RepeatedRows.FirstIndex; rng.Row2 := AWorksheet.PageLayout.RepeatedRows.LastIndex; diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 796282683..6beeb3255 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -2390,15 +2390,15 @@ begin try case AName of #06: begin // Print range - for j := 0 to AWorksheet.NumPrintRanges-1 do + for j := 0 to AWorksheet.PageLayout.NumPrintRanges-1 do begin - rng := AWorksheet.GetPrintRange(j); + rng := AWorksheet.PageLayout.PrintRange[j]; WriteRangeFormula(memstream, rng, AIndexToRef, j+1); end; end; #07: begin // Print titles j := 1; - if AWorksheet.HasRepeatedPrintCols then + if AWorksheet.PageLayout.HasRepeatedCols then begin rng.Col1 := AWorksheet.PageLayout.RepeatedCols.FirstIndex; rng.Col2 := AWorksheet.PageLayout.RepeatedCols.LastIndex; @@ -2408,7 +2408,7 @@ begin WriteRangeFormula(memstream, rng, AIndexToRef, j); inc(j); end; - if AWorksheet.HasRepeatedPrintRows then + if AWorksheet.PageLayout.HasRepeatedRows then begin rng.Row1 := AWorksheet.PageLayout.RepeatedRows.FirstIndex; rng.Row2 := AWorksheet.PageLayout.RepeatedRows.LastIndex; @@ -2539,13 +2539,15 @@ var sheet: TsWorksheet; i: Integer; n: Word; + writeIt: Boolean; begin n := 0; SetLength(sheets, FWorkbook.GetWorksheetCount); for i := 0 to FWorkbook.GetWorksheetCount-1 do begin sheet := FWorkbook.GetWorksheetByIndex(i); - if (sheet.NumPrintRanges > 0) or - sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then + with sheet.PageLayout do + writeIt := (NumPrintRanges > 0) or HasRepeatedCols or HasRepeatedRows; + if writeIt then begin sheets[n] := i; inc(n); diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index bf46da6c3..227c7a3cd 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -627,7 +627,7 @@ uses AVL_Tree, Math, Variants, {%H-}fpspatches, fpsStrings, fpsClasses, fpsNumFormat, xlsConst, //fpsrpn, - fpsExprParser; + fpsExprParser, fpsPageLayout; const { Helper table for rpn formulas: @@ -1105,7 +1105,7 @@ begin begin rng := defName.Ranges; for i := 0 to High(rng) do - AWorksheet.AddPrintRange(rng[i].Row1, rng[i].Col1, rng[i].Row2, rng[i].Col2); + AWorksheet.PageLayout.AddPrintRange(rng[i].Row1, rng[i].Col1, rng[i].Row2, rng[i].Col2); end; end; @@ -1123,10 +1123,10 @@ begin for i := 0 to High(rng) do begin if (rng[i].Col2 <> Cardinal(-1)) then - AWorksheet.SetRepeatedPrintCols(rng[i].Col1, rng[i].Col2) + AWorksheet.PageLayout.SetRepeatedCols(rng[i].Col1, rng[i].Col2) else if (rng[i].Row2 <> Cardinal(-1)) then - AWorksheet.SetRepeatedPrintRows(rng[i].Row1, rng[i].Row2); + AWorksheet.PageLayout.SetRepeatedRows(rng[i].Row1, rng[i].Row2); end; end; end; @@ -1660,7 +1660,9 @@ var w: word; begin w := WordLEToN(AStream.ReadWord); - if w = 1 then Include(FWorksheet.PageLayout.Options, poHorCentered); + if w = 1 then + with FWorksheet.PageLayout do + Options := Options + [poHorCentered]; end; {@@ ---------------------------------------------------------------------------- @@ -1679,16 +1681,19 @@ begin Len := AStream.ReadByte; SetLength(s, len*SizeOf(ansichar)); AStream.ReadBuffer(s[1], len*SizeOf(ansichar)); - if AIsHeader then + with FWorksheet.PageLayout do begin - FWorksheet.PageLayout.Headers[1] := ConvertEncoding(s, FCodePage, 'utf8'); - FWorksheet.PageLayout.Headers[2] := ''; - end else - begin - FWorksheet.PageLayout.Footers[1] := ConvertEncoding(s, FCodePage, 'utf8'); - FWorksheet.PageLayout.Footers[2] := ''; + if AIsHeader then + begin + Headers[1] := ConvertEncoding(s, FCodePage, 'utf8'); + Headers[2] := ''; + end else + begin + Footers[1] := ConvertEncoding(s, FCodePage, 'utf8'); + Footers[2] := ''; + end; + Options := Options - [poDifferentOddEven]; end; - Exclude(FWorksheet.PageLayout.Options, poDifferentOddEven); end; {@@ ---------------------------------------------------------------------------- @@ -1867,7 +1872,12 @@ procedure TsSpreadBIFFReader.ReadPageSetup(AStream: TStream); var w: Word; dbl: Double = 0.0; + optns: TsPrintOptions; begin + // Store current pagelayout options, they already can contain the poFitPages + // which gets altered when reading FitWidthToPages and FitHeightToPages + optns := FWorksheet.PageLayout.Options; + // Paper size w := WordLEToN(AStream.ReadWord); if (w <= High(PAPER_SIZES)) then @@ -1893,23 +1903,27 @@ begin // Option flags w := WordLEToN(AStream.ReadWord); - if w and $0001 <> 0 then - Include(FWorksheet.pageLayout.Options, poPrintPagesByRows); - if w and $0002 <> 0 then - FWorksheet.PageLayout.Orientation := spoPortrait else - FWorksheet.PageLayout.Orientation := spoLandscape; - if w and $0008 <> 0 then - Include(FWorksheet.PageLayout.Options, poMonochrome); - if w and $0010 <> 0 then - Include(FWorksheet.PageLayout.Options, poDraftQuality); - if w and $0020 <> 0 then - Include(FWorksheet.PageLayout.Options, poPrintCellComments); - if w and $0040 <> 0 then - Include(FWorksheet.PageLayout.Options, poDefaultOrientation); - if w and $0080 <> 0 then - Include(FWorksheet.PageLayout.Options, poUseStartPageNumber); - if w and $0200 <> 0 then - Include(FWorksheet.Pagelayout.Options, poCommentsAtEnd); + with FWorksheet.PageLayout do + begin + Options := optns; + if w and $0001 <> 0 then + Options := Options + [poPrintPagesByRows]; + if w and $0002 <> 0 then + Orientation := spoPortrait else + Orientation := spoLandscape; + if w and $0008 <> 0 then + Options := Options + [poMonochrome]; + if w and $0010 <> 0 then + Options := Options + [poDraftQuality]; + if w and $0020 <> 0 then + Options := Options + [poPrintCellComments]; + if w and $0040 <> 0 then + Options := Options + [poDefaultOrientation]; + if w and $0080 <> 0 then + Options := Options + [poUseStartPageNumber]; + if w and $0200 <> 0 then + Options := Options + [poCommentsAtEnd]; + end; // Print resolution in dpi -- ignoried w := WordLEToN(AStream.ReadWord); @@ -1969,7 +1983,8 @@ var begin w := WordLEToN(AStream.ReadWord); if w = 1 then - Include(FWorksheet.PageLayout.Options, poPrintGridLines); + with FWorksheet.PageLayout do + Options := Options + [poPrintGridLines]; end; {@@ ---------------------------------------------------------------------------- @@ -1981,7 +1996,8 @@ var begin w := WordLEToN(AStream.ReadWord); if w = 1 then - Include(FWorksheet.PageLayout.Options , poPrintHeaders); + with FWorksheet.PageLayout do + Options := Options + [poPrintHeaders]; end; {@@ ---------------------------------------------------------------------------- @@ -2667,8 +2683,11 @@ var flags: Word; begin flags := WordLEToN(AStream.ReadWord); - if flags and $0100 <> 0 then - Include(FWorksheet.PageLayout.Options, poFitPages); + with FWorksheet.PageLayout do + if flags and $0100 <> 0 then + Options := Options + [poFitPages] + else + Options := Options - [poFitPages]; // The other flags are ignored, so far. end; @@ -2706,7 +2725,9 @@ var w: word; begin w := WordLEToN(AStream.ReadWord); - if w = 1 then Include(FWorksheet.PageLayout.Options, poVertCentered); + if w = 1 then + with FWorksheet.PageLayout do + Options := Options + [poVertCentered]; end; {@@ ---------------------------------------------------------------------------- @@ -3294,12 +3315,12 @@ begin for i:=0 to FWorkbook.GetWorksheetCount-1 do begin sheet := FWorkbook.GetWorksheetByIndex(i); - if (sheet.NumPrintRanges > 0) or - sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then + if (sheet.PageLayout.NumPrintRanges > 0) or + sheet.PageLayout.HasRepeatedCols or sheet.PageLayout.HasRepeatedRows then begin - if sheet.NumPrintRanges > 0 then + if sheet.PageLayout.NumPrintRanges > 0 then WriteDefinedName(AStream, sheet, #6, n); - if sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then + if sheet.PageLayout.HasRepeatedCols or sheet.PageLayout.HasRepeatedRows then WriteDefinedName(AStream, sheet, #7, n); inc(n); end; @@ -3351,8 +3372,8 @@ begin for i := 0 to FWorkbook.GetWorksheetCount-1 do begin sheet := FWorkbook.GetWorksheetByIndex(i); - if (sheet.NumPrintRanges > 0) or - sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then inc(n); + with sheet.PageLayout do + if (NumPrintRanges > 0) or HasRepeatedCols or HasRepeatedRows then inc(n); end; if n < 1 then @@ -3373,12 +3394,14 @@ procedure TsSpreadBIFFWriter.WriteEXTERNSHEET(AStream: TStream); var sheet: TsWorksheet; i: Integer; + writeIt: Boolean; begin for i := 0 to FWorkbook.GetWorksheetCount-1 do begin sheet := FWorkbook.GetWorksheetByIndex(i); - if (sheet.NumPrintRanges > 0) or - sheet.HasRepeatedPrintCols or sheet.HasRepeatedPrintRows then + with sheet.PageLayout do + writeIt := (NumPrintRanges > 0) or HasRepeatedCols or HasRepeatedRows; + if writeIt then begin { BIFF record header } WriteBIFFHeader(AStream, INT_EXCEL_ID_EXTERNSHEET, 2 + Length(sheet.Name)); diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index c0716c88f..23a2aca51 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -1110,7 +1110,7 @@ begin end; ParseSheetCellString(Copy(s, 1, p-1), sheetname, r1, c1); ParseSheetCellString(Copy(s, p+1, MaxInt), sheetname, r2, c2); - sheet.AddPrintRange(r1, c1, r2, c2); + sheet.PageLayout.AddPrintRange(r1, c1, r2, c2); end; finally L.Free; @@ -1138,9 +1138,9 @@ begin if not ParseCellRowString(copy(s, p+1, MaxInt), r2) then r2 := UNASSIGNED_ROW_COL_INDEX; if (r1 <> cardinal(UNASSIGNED_ROW_COL_INDEX)) then - sheet.SetRepeatedPrintRows(r1, r2); + sheet.PageLayout.SetRepeatedRows(r1, r2); if (c1 <> cardinal(UNASSIGNED_ROW_COL_INDEX)) then - sheet.SetRepeatedPrintCols(c1, c2); + sheet.PageLayout.SetRepeatedCols(c1, c2); end; finally L.Free; @@ -1385,11 +1385,11 @@ begin s := GetAttrValue(ANode, 'differentOddEven'); if s = '1' then - Include(AWorksheet.PageLayout.Options, poDifferentOddEven); + with AWorksheet.PageLayout do Options := Options + [poDifferentOddEven]; s := GetAttrValue(ANode, 'differentFirst'); if s = '1' then - Include(AWorksheet.PageLayout.Options, poDifferentFirst); + with AWorksheet.PageLayout do Options := Options + [poDifferentFirst]; node := ANode.FirstChild; while node <> nil do @@ -1596,49 +1596,46 @@ begin // Scaling factor s := GetAttrValue(ANode, 'scale'); if s <> '' then - begin AWorksheet.PageLayout.ScalingFactor := StrToInt(s); - Exclude(AWorksheet.PageLayout.Options, poFitPages); - end; + // poFitPages is automatically excluded // Fit print job to pages s := GetAttrValue(ANode, 'fitToHeight'); if s <> '' then - begin AWorksheet.PageLayout.FitHeightToPages := StrToInt(s); - Include(AWorksheet.PageLayout.Options, poFitPages); - end; + // poFitPages is automatically included. s := GetAttrValue(ANode, 'fitToWidth'); if s <> '' then - begin AWorksheet.PageLayout.FitWidthToPages := StrToInt(s); - Include(AWorksheet.PageLayout.Options, poFitPages); - end; + // poFitPages is automatially included. // First page number - s := GetAttrValue(ANode, 'useFirstPageNumber'); - if s = '1' then - Include(AWorksheet.PageLayout.Options, poUseStartPageNumber); - s := GetAttrValue(ANode, 'firstPageNumber'); if s <> '' then AWorksheet.PageLayout.StartPageNumber := StrToInt(s); + s := GetAttrValue(ANode, 'useFirstPageNumber'); + with AWorksheet.PageLayout do + if s = '1' then + Options := Options + [poUseStartPageNumber] + else + Options := Options - [poUseStartPageNumber]; + // Print order s := GetAttrValue(ANode, 'pageOrder'); if s = 'overThenDown' then - Include(AWorksheet.PageLayout.Options, poPrintPagesByRows); + with AWorksheet.PageLayout do Options := Options + [poPrintPagesByRows]; // Monochrome s := GetAttrValue(ANode, 'blackAndWhite'); if s = '1' then - Include(AWorksheet.PageLayout.Options, poMonochrome); + with AWorksheet.PageLayout do Options := Options + [poMonochrome]; // Quality s := GetAttrValue(ANode, 'draft'); if s = '1' then - Include(AWorksheet.PageLayout.Options, poDraftQuality); + with AWorksheet.PageLayout do Options := Options + [poDraftQuality]; end; procedure TsSpreadOOXMLReader.ReadPalette(ANode: TDOMNode); @@ -1700,11 +1697,11 @@ begin exit; s := GetAttrValue(ANode, 'headings'); if (s = '1') then - Include(AWorksheet.PageLayout.Options, poPrintHeaders); + with AWorksheet.PageLayout do Options := Options + [poPrintHeaders]; s := GetAttrValue(ANode, 'gridLines'); if (s = '1') then - Include(AWorksheet.PageLayout.Options, poPrintGridLines); + with AWorksheet.PageLayout do Options := Options + [poPrintGridLines]; end; procedure TsSpreadOOXMLReader.ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet); @@ -3759,9 +3756,9 @@ begin // Cell block of print range srng := ''; - for j := 0 to sheet.numPrintRanges - 1 do + for j := 0 to sheet.PageLayout.NumPrintRanges - 1 do begin - prng := sheet.GetPrintRange(j); + prng := sheet.PageLayout.GetPrintRange(j); srng := srng + ',' + Format('%s!%s', [ sheetname, GetCellRangeString(prng.Row1, prng.Col1, prng.Row2, prng.Col2, []) ]);