diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index 135054995..e82c9f6c9 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -66,6 +66,7 @@ type FRowStyleList: TFPList; FRowList: TFPList; FDateMode: TDateMode; + FPageLayout: TsPageLayout; // Applies internally stored column widths to current worksheet procedure ApplyColWidths; // Applies a style to a cell @@ -91,6 +92,7 @@ type protected FPointSeparatorSettings: TFormatSettings; procedure AddBuiltinNumFormats; override; + procedure ReadAutomaticStyles(AStylesNode: TDOMNode); procedure ReadNumFormats(AStylesNode: TDOMNode); procedure ReadSettings(AOfficeSettingsNode: TDOMNode); procedure ReadStyles(AStylesNode: TDOMNode); @@ -618,6 +620,8 @@ begin Workbook.UseDefaultPalette; // Initial base date in case it won't be read from file FDateMode := dm1899; + // Initialize internal PageLayout record + InitPageLayout(FPageLayout); end; destructor TsSpreadOpenDocReader.Destroy; @@ -850,6 +854,79 @@ begin Result := -1; end; +procedure TsSpreadOpenDocReader.ReadAutomaticStyles(AStylesNode: TDOMNode); +var + nodeName: String; + layoutNode: TDOMNode; + node: TDOMNode; + s: String; +begin + if not Assigned(AStylesNode) then + exit; + layoutNode := AStylesNode.FirstChild; + while layoutNode <> nil do + begin + nodeName := layoutNode.NodeName; + if nodeName = 'style:page-layout' then begin + s := GetAttrValue(layoutNode, 'style:name'); + if s = 'Mpm1' then + begin + node := layoutNode.FirstChild; + while node <> nil do + begin + nodeName := node.NodeName; + if nodeName = 'style:page-layout-properties' then + begin + s := GetAttrValue(node, 'fo:margin-top'); + if s <> '' then + FPageLayout.TopMargin := PtsToMM(HTMLLengthStrToPts(s)); + + s := GetAttrValue(node, 'fo:margin-bottom'); + if s <> '' then + FPageLayout.BottomMargin := PtsToMM(HTMLLengthStrToPts(s)); + + s := GetAttrValue(node, 'fo:margin-left'); + if s <> '' then + FPageLayout.LeftMargin := PtsToMM(HTMLLengthStrToPts(s)); + + s := GetAttrValue(node, 'fo:margin-right'); + if s <> '' then + FPageLayout.RightMargin := PtsToMM(HTMLLengthStrToPts(s)); + + s := GetAttrValue(node, 'style:scale-to'); + if (s <> '') then + begin + if s[Length(s)] = '%' then Delete(s, Length(s), 1); + FPageLayout.ScalingFactor := StrToFloat(s, FPointSeparatorSettings); + end; + + s := GetAttrValue(node, 'style:print'); + if pos('grid', s) > 0 then + Include(FPageLayout.Options, poPrintGridLines); + if pos('headers', s) > 0 then + Include(FPageLayout.Options, poPrintHeaders); + if pos('annotations', s) > 0 then + Include(FPageLayout.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(FPageLayout.Options, poPrintPagesByRows); + + s := GetAttrValue(node, 'style:first-page-number'); + if s = 'continue' then + Exclude(FPageLayout.Options, poUseStartPageNumber) + else + if TryStrToInt(s, FPageLayout.StartPageNumber) then + Include(FPageLayout.Options, poUseStartPageNumber); + end; + node := node.NextSibling; + end; + end; + end; + layoutNode := layoutNode.NextSibling; + end; +end; + procedure TsSpreadOpenDocReader.ReadBlank(ARow, ACol: Cardinal; ACellNode: TDOMNode); var @@ -1317,6 +1394,9 @@ begin ReadNumFormats(StylesNode); ReadStyles(StylesNode); + StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles'); + ReadAutomaticStyles(StylesNode); + Doc.Free; //process the content.xml file @@ -1349,6 +1429,7 @@ begin continue; end; FWorkSheet := FWorkbook.AddWorksheet(GetAttrValue(TableNode,'table:name'), true); + FWorksheet.PageLayout := FPageLayout; // Collect column styles used ReadColumns(TableNode); // Process each row inside the sheet and process each cell of the row diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 59d9d9d6b..fe8361d3c 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -105,7 +105,6 @@ type FDefaultColWidth: Single; // in "characters". Excel uses the width of char "0" in 1st font FDefaultRowHeight: Single; // in "character heights", i.e. line count FSortParams: TsSortParams; // Parameters of the current sorting operation - FPageLayout: TsPageLayout; FOnChangeCell: TsCellEvent; FOnChangeFont: TsCellEvent; FOnCompareCells: TsCellCompareEvent; @@ -138,6 +137,9 @@ type procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal); public + {@@ Page layout parameters for printing } + PageLayout: TsPageLayout; + { Base methods } constructor Create; destructor Destroy; override; @@ -468,8 +470,6 @@ type {@@ The default row height is given in "line count" (height of the default font } property DefaultRowHeight: Single read FDefaultRowHeight write FDefaultRowHeight; - {@@ Page layout parameters for printing } - property PageLayout: TsPageLayout read FPageLayout write FPageLayout; // These are properties to interface to TsWorksheetGrid {@@ Parameters controlling visibility of grid lines and row/column headers, @@ -1114,14 +1114,7 @@ begin FMergedCells := TsMergedCells.Create; FHyperlinks := TsHyperlinks.Create; - with FPageLayout do begin - LeftMargin := InToPts(0.7); - RightMargin := InToPts(0.7); - TopMargin := InToPts(0.78740157499999996); - BottomMargin := InToPts(0.78740157499999996); - HeaderDistance := InToPts(0.3); - FooterDistance := InToPts(0.3); - end; + InitPageLayout(PageLayout); FDefaultColWidth := 12; FDefaultRowHeight := 1; @@ -6767,6 +6760,8 @@ begin // Remember the workbook to which it belongs (This must occur before // setting the workbook name because the workbook is needed there). Result.FWorkbook := Self; + Result.FActiveCellRow := 0; + Result.FActiveCellCol := 0; // Set the name of the new worksheet. // For this we turn off notification of listeners. This is not necessary here diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index 0fd2f8dcd..a865d6164 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -2881,6 +2881,9 @@ end; -------------------------------------------------------------------------------} procedure TsSpreadsheetInspector.UpdateWorksheet(ASheet: TsWorksheet; AStrings: TStrings); +var + s: String; + po: TsPrintOption; begin if ASheet = nil then begin @@ -2891,6 +2894,7 @@ begin AStrings.Add('Last column='); AStrings.Add('Active cell='); AStrings.Add('Selection='); + AStrings.Add('Page layout='); end else begin AStrings.Add(Format('Name=%s', [ASheet.Name])); @@ -2903,6 +2907,27 @@ begin AStrings.Add(Format('Comments=%d items', [ASheet.Comments.Count])); AStrings.Add(Format('Hyperlinks=%d items', [ASheet.Hyperlinks.Count])); AStrings.Add(Format('MergedCells=%d items', [ASheet.MergedCells.Count])); + AStrings.Add('Page layout='); + AStrings.Add(Format(' Orientation=%s', [GetEnumName(TypeInfo(TsPageOrientation), ord(ASheet.PageLayout.Orientation))])); + AStrings.Add(Format(' Page width=%.1f mm', [ASheet.PageLayout.PageWidth])); + AStrings.Add(Format(' Page height=%.1f mm', [ASheet.PageLayout.PageHeight])); + AStrings.Add(Format(' Left margin=%.1f mm', [ASheet.PageLayout.LeftMargin])); + AStrings.Add(Format(' Right margin=%.1f mm', [ASheet.PageLayout.RightMargin])); + AStrings.Add(Format(' Top margin=%.1f mm', [ASheet.PageLayout.TopMargin])); + AStrings.Add(Format(' Bottom margin=%.1f mm', [ASheet.PageLayout.BottomMargin])); + AStrings.Add(Format(' Header distance=%.1f mm', [ASheet.PageLayout.HeaderMargin])); + AStrings.Add(Format(' Footer distance=%.1f mm', [ASheet.PageLayout.FooterMargin])); + if poUseStartPageNumber in ASheet.PageLayout.Options then + AStrings.Add(Format(' Start page number=%d', [ASheet.pageLayout.StartPageNumber])) + else + AStrings.Add (' Start page number=automatic'); + AStrings.Add(Format(' Scaling factor=%.0f%%', [ASheet.PageLayout.ScalingFactor])); + AStrings.Add(Format(' Copies=%d', [ASheet.PageLayout.Copies])); + s := ''; + for po in TsPrintOption do + if po in ASheet.PageLayout.Options then s := s + '; ' + GetEnumName(typeInfo(TsPrintOption), ord(po)); + if s <> '' then Delete(s, 1, 2); + AStrings.Add(Format(' Options=%s', [s])); end; end; diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas index 42154bc24..8a42fed07 100644 --- a/components/fpspreadsheet/fpstypes.pas +++ b/components/fpspreadsheet/fpstypes.pas @@ -668,13 +668,39 @@ type cctError : (ErrorValue: TsErrorValue); end; - TsPageLayout = record - LeftMargin: Double; // in Points +{ + TsPaperSize = (psUndefined, psLetter, psLetterSmall, psTabloid, psLedger, + psLegal, psStatement, psExecutive, psA3, psA4, psA4small, psA5, psB4, psB5, + psFolie, psQuarto, ps10x14, ps11x17, psNote, psEnvelope9, psEnvelope10, + psEnvelope11, psEnvelope12, psEnvelope14, psC, psD, psE, psEnvelopeDL, + psEnvelopeC5, psEnvelopeC3, psEnvelopeC4, psEnvelopeC6, psEnvelopeC6C5, + psB4ISO, psB5ISO, psB6ISO, + } + + TsPageOrientation = (spoPortrait, spoLandscape); + + TsPrintOption = (poPrintGridLines, poPrintHeaders, poPrintPagesByRows, + poMonochrome, poDraftQuality, poPrintCellComments, poDefaultOrientation, + poUseStartPageNumber, poCommentsAtEnd, poHorCentered, poVertCentered); + + TsPrintOptions = set of TsPrintOption; + + 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; - HeaderDistance: Double; - FooterDistance: Double; + HeaderMargin: Double; + FooterMargin: Double; + StartPageNumber: Integer; + ScalingFactor: Double; // in percent + FitWidthToPages: Integer; + FitHeightToPages: Integer; + Copies: Integer; + Options: TsPrintOptions; end; function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String; diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index af14408d1..a951222e2 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -134,17 +134,19 @@ function TryStrToFloatAuto(AText: String; out ANumber: Double; function TryFractionStrToFloat(AText: String; out ANumber: Double; out AMaxDigits: Integer): Boolean; -function TwipsToPts(AValue: Integer): Single; -function PtsToTwips(AValue: Single): Integer; -function cmToPts(AValue: Double): Double; -function PtsToCm(AValue: Double): Double; -function InToPts(AValue: Double): Double; -function PtsToIn(AValue: Double): Double; -function mmToPts(AValue: Double): Double; -function PtsToMM(AValue: Double): Double; -function pxToPts(AValue, AScreenPixelsPerInch: Integer): Double; -function PtsToPx(AValue: Double; AScreenPixelsPerInch: Integer): Integer; -function HTMLLengthStrToPts(AValue: String): Double; +function TwipsToPts(AValue: Integer): Single; inline; +function PtsToTwips(AValue: Single): Integer; inline; +function cmToPts(AValue: Double): Double; inline; +function PtsToCm(AValue: Double): Double; inline; +function InToMM(AValue: Double): Double; inline; +function InToPts(AValue: Double): Double; inline; +function PtsToIn(AValue: Double): Double; inline; +function mmToPts(AValue: Double): Double; inline; +function mmToIn(AValue: Double): Double; inline; +function PtsToMM(AValue: Double): Double; inline; +function pxToPts(AValue, AScreenPixelsPerInch: Integer): Double; inline; +function PtsToPx(AValue: Double; AScreenPixelsPerInch: Integer): Integer; inline; +function HTMLLengthStrToPts(AValue: String; DefaultUnits: String = 'pt'): Double; function HTMLColorStrToColor(AValue: String): TsColorValue; function ColorToHTMLColorStr(AValue: TsColorValue; AExcelDialect: Boolean = false): String; @@ -165,6 +167,7 @@ procedure FixHyperlinkPathDelims(var ATarget: String); procedure InitCell(out ACell: TCell); overload; procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload; procedure InitFormatRecord(out AValue: TsCellFormat); +procedure InitPageLayout(out APageLayout: TsPageLayout); procedure AppendToStream(AStream: TStream; const AString: String); inline; overload; procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload; @@ -1977,6 +1980,28 @@ begin Result := AValue / 72 * 2.54; end; +{@@ ---------------------------------------------------------------------------- + Converts inches to millimeters + + @param AValue Length value in inches + @return Value converted to mm +-------------------------------------------------------------------------------} +function InToMM(AValue: Double): Double; +begin + Result := AValue * 25.4; +end; + +{@@ ---------------------------------------------------------------------------- + Converts millimeters to inches + + @param AValue Length value in millimeters + @return Value converted to inches +-------------------------------------------------------------------------------} +function mmToIn(AValue: Double): Double; +begin + Result := AValue / 25.4; +end; + {@@ ---------------------------------------------------------------------------- Converts inches to points (72 pts = 1 inch) @@ -2052,9 +2077,11 @@ end; such as '1.25in'. These unit codes are accepted: 'px' (pixels), 'pt' (points), 'in' (inches), 'mm' (millimeters), 'cm' (centimeters). + @param DefaultUnits String identifying the units to be used if not contained + in AValue. @return Extracted length in points -------------------------------------------------------------------------------} -function HTMLLengthStrToPts(AValue: String): Double; +function HTMLLengthStrToPts(AValue: String; DefaultUnits: String = 'pt'): Double; var units: String; x: Double; @@ -2062,10 +2089,11 @@ var begin if (Length(AValue) > 1) and (AValue[Length(AValue)] in ['a'..'z', 'A'..'Z']) then begin units := lowercase(Copy(AValue, Length(AValue)-1, 2)); + if units = '' then units := DefaultUnits; val(copy(AValue, 1, Length(AValue)-2), x, res); // No hasseling with the decimal point... end else begin - units := ''; + units := DefaultUnits; val(AValue, x, res); end; if res <> 0 then @@ -2376,6 +2404,30 @@ begin AValue.NumberFormatIndex := -1; // GENERAL format not contained in NumFormatList end; +{@@ ---------------------------------------------------------------------------- + Initializes the fields of a TsPageLayout record +-------------------------------------------------------------------------------} +procedure InitPageLayout(out APageLayout: TsPageLayout); +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 := []; + end; +end; + {@@ ---------------------------------------------------------------------------- Appends a string to a stream diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index 31c172a01..84e29b42f 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -455,27 +455,33 @@ begin case RecordType of INT_EXCEL_ID_BLANK : ReadBlank(AStream); + INT_EXCEL_ID_BOF : ; INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); + INT_EXCEL_ID_BOTTOMMARGIN: ReadBottomMargin(AStream); INT_EXCEL_ID_CODEPAGE : ReadCodePage(AStream); - INT_EXCEL_ID_NOTE : ReadComment(AStream); + INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream); + INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); + INT_EXCEL_ID_EOF : BIFF2EOF := True; INT_EXCEL_ID_FONT : ReadFont(AStream); INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream); INT_EXCEL_ID_FORMAT : ReadFormat(AStream); + INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_INTEGER : ReadInteger(AStream); INT_EXCEL_ID_IXFE : ReadIXFE(AStream); - INT_EXCEL_ID_NUMBER : ReadNumber(AStream); INT_EXCEL_ID_LABEL : ReadLabel(AStream); - INT_EXCEL_ID_FORMULA : ReadFormula(AStream); - INT_EXCEL_ID_STRING : ReadStringRecord(AStream); - INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream); - INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); + INT_EXCEL_ID_LEFTMARGIN : ReadLeftMargin(AStream); + INT_EXCEL_ID_NOTE : ReadComment(AStream); + INT_EXCEL_ID_NUMBER : ReadNumber(AStream); + INT_EXCEL_ID_PANE : ReadPane(AStream); + INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream); + INT_EXCEL_ID_PRINTHEADERS: ReadPrintHeaders(AStream); + INT_EXCEL_ID_RIGHTMARGIN : ReadRightMargin(AStream); INT_EXCEL_ID_ROW : ReadRowInfo(AStream); + INT_EXCEL_ID_STRING : ReadStringRecord(AStream); + INT_EXCEL_ID_TOPMARGIN : ReadTopMargin(AStream); INT_EXCEL_ID_DEFROWHEIGHT: ReadDefRowHeight(AStream); INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); - INT_EXCEL_ID_PANE : ReadPane(AStream); INT_EXCEL_ID_XF : ReadXF(AStream); - INT_EXCEL_ID_BOF : ; - INT_EXCEL_ID_EOF : BIFF2EOF := True; else // nothing end; @@ -1229,8 +1235,18 @@ begin raise Exception.Create(rsWorksheetNotFound1); WriteBOF(AStream); - WriteFonts(AStream); WriteCodePage(AStream, FCodePage); + WritePrintHeaders(AStream); + WritePrintGridLines(AStream); + WriteFonts(AStream); + + // Page settings block + WriteLeftMargin(AStream); + WriteRightMargin(AStream); + WriteTopMargin(AStream); + WriteBottomMargin(AStream); +// WritePageSetup(AStream); // does not exist in BIFF2 + WriteFormatCount(AStream); WriteNumFormats(AStream); WriteXFRecords(AStream); diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index b632cacda..59e9818ba 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -390,25 +390,34 @@ begin case RecordType of INT_EXCEL_ID_BLANK : ReadBlank(AStream); + INT_EXCEL_ID_BOF : ; INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); + INT_EXCEL_ID_BOTTOMMARGIN : ReadBottomMargin(AStream); + INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); + INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); + INT_EXCEL_ID_EOF : SectionEOF := True; + INT_EXCEL_ID_FORMULA : ReadFormula(AStream); + INT_EXCEL_ID_HCENTER : ReadHCENTER(AStream); + INT_EXCEL_ID_LABEL : ReadLabel(AStream); + INT_EXCEL_ID_LEFTMARGIN : ReadLeftMargin(AStream); INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream); + INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream); INT_EXCEL_ID_NOTE : ReadComment(AStream); INT_EXCEL_ID_NUMBER : ReadNumber(AStream); - INT_EXCEL_ID_LABEL : ReadLabel(AStream); - INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard. - INT_EXCEL_ID_RK : ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2. - INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream); - INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); - INT_EXCEL_ID_STANDARDWIDTH : ReadStandardWidth(AStream, FWorksheet); - INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); - INT_EXCEL_ID_ROW : ReadRowInfo(AStream); - INT_EXCEL_ID_FORMULA : ReadFormula(AStream); - INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream); - INT_EXCEL_ID_STRING : ReadStringRecord(AStream); - INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); INT_EXCEL_ID_PANE : ReadPane(AStream); - INT_EXCEL_ID_BOF : ; - INT_EXCEL_ID_EOF : SectionEOF := True; + INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream); + INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream); + INT_EXCEL_ID_PRINTHEADERS : ReadPrintHeaders(AStream); + INT_EXCEL_ID_RIGHTMARGIN : ReadRightMargin(AStream); + INT_EXCEL_ID_RK : ReadRKValue(AStream); //(RK) This record represents a cell that contains an RK value (encoded integer or floating-point value). If a floating-point value cannot be encoded to an RK value, a NUMBER record will be written. This record replaces the record INTEGER written in BIFF2. + INT_EXCEL_ID_ROW : ReadRowInfo(AStream); + INT_EXCEL_ID_RSTRING : ReadRichString(AStream); //(RSTRING) This record stores a formatted text cell (Rich-Text). In BIFF8 it is usually replaced by the LABELSST record. Excel still uses this record, if it copies formatted text cells to the clipboard. + INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream); + INT_EXCEL_ID_STANDARDWIDTH : ReadStandardWidth(AStream, FWorksheet); + INT_EXCEL_ID_TOPMARGIN : ReadTopMargin(AStream); + INT_EXCEL_ID_STRING : ReadStringRecord(AStream); + INT_EXCEL_ID_VCENTER : ReadVCENTER(AStream); + INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); {$IFDEF FPSPREADDEBUG} // Only write out if debugging else @@ -1030,9 +1039,19 @@ begin AStream.Position := CurrentPos; WriteBOF(AStream, INT_BOF_SHEET); - WriteIndex(AStream); -// WritePageSetup(AStream); + WritePrintHeaders(AStream); + WritePrintGridLines(AStream); + + // Page settings block + WriteHCenter(AStream); + WriteVCenter(AStream); + WriteLeftMargin(AStream); + WriteRightMargin(AStream); + WriteTopMargin(AStream); + WriteBottomMargin(AStream); + WritePageSetup(AStream); + WriteColInfos(AStream, FWorksheet); WriteDimensions(AStream, FWorksheet); WriteWindow2(AStream, FWorksheet); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 301499268..87bd2912b 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -120,6 +120,7 @@ type TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter) protected + function GetPrintOptions: Word; override; { Record writing methods } procedure WriteBOF(AStream: TStream; ADataType: Word); function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; @@ -675,39 +676,51 @@ begin case RecordType of - INT_EXCEL_ID_BLANK : ReadBlank(AStream); - INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); - INT_EXCEL_ID_CONTINUE : ReadCONTINUE(AStream); - INT_EXCEL_ID_FORMULA : ReadFormula(AStream); - INT_EXCEL_ID_HYPERLINK : ReadHyperlink(AStream); - INT_EXCEL_ID_HLINKTOOLTIP: ReadHyperlinkToolTip(AStream); - INT_EXCEL_ID_LABEL : ReadLabel(AStream); - INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream); - INT_EXCEL_ID_NOTE : ReadNOTE(AStream); - INT_EXCEL_ID_NUMBER : ReadNumber(AStream); - INT_EXCEL_ID_OBJ : ReadOBJ(AStream); - INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream); - INT_EXCEL_ID_STRING : ReadStringRecord(AStream); - INT_EXCEL_ID_TXO : ReadTXO(AStream); + INT_EXCEL_ID_BLANK : ReadBlank(AStream); + INT_EXCEL_ID_BOF : ; + INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); + INT_EXCEL_ID_BOTTOMMARGIN : ReadBottomMargin(AStream); + INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); + INT_EXCEL_ID_CONTINUE : ReadCONTINUE(AStream); + INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); + INT_EXCEL_ID_EOF : SectionEOF := True; + INT_EXCEL_ID_FORMULA : ReadFormula(AStream); + INT_EXCEL_ID_HCENTER : ReadHCENTER(AStream); + INT_EXCEL_ID_HLINKTOOLTIP : ReadHyperlinkToolTip(AStream); + INT_EXCEL_ID_HYPERLINK : ReadHyperlink(AStream); + INT_EXCEL_ID_LABEL : ReadLabel(AStream); + INT_EXCEL_ID_LABELSST : ReadLabelSST(AStream); + INT_EXCEL_ID_LEFTMARGIN : ReadLeftMargin(AStream); + INT_EXCEL_ID_MERGEDCELLS : ReadMergedCells(AStream); + INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream); + INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream); + INT_EXCEL_ID_NOTE : ReadNOTE(AStream); + INT_EXCEL_ID_NUMBER : ReadNumber(AStream); + INT_EXCEL_ID_OBJ : ReadOBJ(AStream); + INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream); + INT_EXCEL_ID_PANE : ReadPane(AStream); + INT_EXCEL_ID_PRINTGRID : ReadPrintGridLines(AStream); + INT_EXCEL_ID_PRINTHEADERS : ReadPrintHeaders(AStream); + INT_EXCEL_ID_RIGHTMARGIN : ReadRightMargin(AStream); + INT_EXCEL_ID_ROW : ReadRowInfo(AStream); + //(RSTRING) This record stores a formatted text cell (Rich-Text). // In BIFF8 it is usually replaced by the LABELSST record. Excel still // uses this record, if it copies formatted text cells to the clipboard. - INT_EXCEL_ID_RSTRING : ReadRichString(AStream); + INT_EXCEL_ID_RSTRING : ReadRichString(AStream); + // (RK) This record represents a cell that contains an RK value // (encoded integer or floating-point value). If a floating-point // value cannot be encoded to an RK value, a NUMBER record will be written. // This record replaces the record INTEGER written in BIFF2. - INT_EXCEL_ID_RK : ReadRKValue(AStream); - INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream); - INT_EXCEL_ID_LABELSST : ReadLabelSST(AStream); //BIFF8 only - INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); - INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); - INT_EXCEL_ID_MERGEDCELLS : ReadMergedCells(AStream); - INT_EXCEL_ID_ROW : ReadRowInfo(AStream); - INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); - INT_EXCEL_ID_PANE : ReadPane(AStream); - INT_EXCEL_ID_BOF : ; - INT_EXCEL_ID_EOF : SectionEOF := True; + INT_EXCEL_ID_RK : ReadRKValue(AStream); + + INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream); + INT_EXCEL_ID_STRING : ReadStringRecord(AStream); + INT_EXCEL_ID_TOPMARGIN : ReadTopMargin(AStream); + INT_EXCEL_ID_TXO : ReadTXO(AStream); + INT_EXCEL_ID_VCENTER : ReadVCENTER(AStream); + INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); else // nothing end; @@ -1614,6 +1627,17 @@ begin FDateMode := Excel8Settings.DateMode; end; +function TsSpreadBIFF8Writer.GetPrintOptions: Word; +Begin + Result := inherited GetPrintOptions; +{ The following flags are valid for BIFF8 only: + Bit 9: 0 = Print notes as displayed; 1 = Print notes at end of sheet + Bit 11-10: 00 = Print errors as displayed; 1 = Do not print errors + 2 = Print errors as “--”; 3 = Print errors as “#N/A” } + if poCommentsAtEnd in FWorksheet.PageLayout.Options then + Result := Result or $0200; +end; + {@@ ---------------------------------------------------------------------------- Writes an Excel BIFF8 file to the disc @@ -1695,8 +1719,20 @@ begin WriteBOF(AStream, INT_BOF_SHEET); WriteIndex(AStream); + WritePrintHeaders(AStream); + WritePrintGridLines(AStream); + //WriteSheetPR(AStream); -// WritePageSetup(AStream); + + // Page setting block + WriteHCenter(AStream); + WriteVCenter(AStream); + WriteLeftMargin(AStream); + WriteRightMargin(AStream); + WriteTopMargin(AStream); + WriteBottomMargin(AStream); + WritePageSetup(AStream); + WriteColInfos(AStream, FWorksheet); WriteDimensions(AStream, FWorksheet); //WriteRowAndCellBlock(AStream, sheet); diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 5354bffc8..ca8ee2dc4 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -20,6 +20,12 @@ const INT_EXCEL_ID_NOTE = $001C; INT_EXCEL_ID_SELECTION = $001D; INT_EXCEL_ID_DATEMODE = $0022; + INT_EXCEL_ID_LEFTMARGIN = $0026; + INT_EXCEL_ID_RIGHTMARGIN = $0027; + INT_EXCEL_ID_TOPMARGIN = $0028; + INT_EXCEL_ID_BOTTOMMARGIN= $0029; + INT_EXCEL_ID_PRINTHEADERS= $002A; + INT_EXCEL_ID_PRINTGRID = $002B; INT_EXCEL_ID_CONTINUE = $003C; INT_EXCEL_ID_WINDOW1 = $003D; INT_EXCEL_ID_PANE = $0041; @@ -33,6 +39,8 @@ const { RECORD IDs which did not change across version 3-8} INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2 INT_EXCEL_ID_SHEETPR = $0081; // does not exist in BIFF2 + INT_EXCEL_ID_HCENTER = $0083; // does not exist in BIFF2 + INT_EXCEL_ID_VCENTER = $0084; // does not exist in BIFF2 INT_EXCEL_ID_COUNTRY = $008C; // does not exist in BIFF2 INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2 INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000 @@ -215,6 +223,100 @@ const { Index of last built-in XF format record } LAST_BUILTIN_XF = 15; + PAPER_SIZES: array[0..90] of array[0..1] of Double = ( // Dimensions in mm + ( 0.0 , 0.0 ), // 0 - undefined + (2.54* 8.5 , 11.0 *2.54), // 1 - Letter + (2.54* 8.5 , 11.0 *2.54), // 2 - Letter small + (2.54* 11.0 , 17.0 *2.54), // 3 - Tabloid + (2.54* 17.0 , 11.0 *2.54), // 4 - Ledger + (2.54* 8.5 , 14.0 *2.54), // 5 - Legal + (2.54* 5.5 , 8.5 *2.54), // 6 - Statement + (2.54* 7.25 , 10.5 *2.54), // 7 - Executive + ( 297.0 , 420.0 ), // 8 - A3 + ( 210.0 , 297.0 ), // 9 - A4 + ( 210.0 , 297.0 ), // 10 - A4 small + ( 148.0 , 210.0 ), // 11 - A5 + ( 257.0 , 364.0 ), // 12 - B4 (JIS) + ( 182.0 , 257.0 ), // 13 - B5 (JIS) + (2.54* 8.5 , 13.0 *2.54), // 14 - Folie + ( 215.0 , 275.0 ), // 15 - Quarto + (2.54* 10.0 , 14.0 *2.54), // 16 - 10x14 + (2.54* 11.0 , 17.0 *2.54), // 17 - 11x17 + (2.54* 8.5 , 11.0 *2.54), // 18 - Note + (2.54* 3.875, 8.875*2.54), // 19 - Envelope #9 + (2.54* 4.125, 9.5 *2.54), // 20 - Envelope #10 + (2.54* 4.5 , 10.375*2.54), // 21 - Envelope #11 + (2.54* 4.75 , 11.0 *2.54), // 22 - Envelope #12 + (2.54* 5.0 , 11.5 *2.54), // 23 - Envelope #14 + (2.54* 17.0 , 22.0 *2.54), // 24 - C + (2.54* 22.0 , 34.0 *2.54), // 25 - D + (2.54* 34.0 , 44.0 *2.54), // 26 - E + ( 110.0 , 220.0 ), // 27 - Envelope DL + ( 162.0 , 229.0 ), // 28 - Envelope C5 + ( 324.0 , 458.0 ), // 29 - Envelope C3 + ( 229.0 , 324.0 ), // 30 - Envelope C4 + ( 114.0 , 162.0 ), // 31 - Envelope C6 + ( 114.0 , 229.0 ), // 32 - Envelope C6/C5 + ( 250.0 , 353.0 ), // 33 - B4 (ISO) + ( 176.0 , 250.0 ), // 34 - B5 (ISO) + ( 125.0 , 176.0 ), // 35 - B6 (ISO) + ( 110.0 , 230.0 ), // 36 - Envelope Italy + (2.54* 3.875, 7.5 *2.54), // 37 - Envelope Monarch + (2.54* 3.625, 6.5 *2.54), // 38 - 6 3/4 Envelope + (2.54* 14.875, 11.0 *2.54), // 39 - US Standard Fanfold + (2.54* 8.5 , 12.0 *2.54), // 40 - German Std Fanfold + (2.54* 8.5 , 13.0 *2.54), // 41 - German Legal Fanfold + ( 250.0 , 353.0 ), // 42 - B4 (ISO) + ( 100.0 , 148.0 ), // 43 - Japanese Postcard + (2.54* 9.0 , 11.0 *2.54), // 44 - 9x11 + (2.54* 10.0 , 11.0 *2.54), // 45 - 10x11 + (2.54* 15.0 , 11.0 *2.54), // 46 - 15x11 + ( 220.0 , 220.0 ), // 47 - Envelope Invite + ( 0.0 , 0.0 ), // 48 - undefined + ( 0.0 , 0.0 ), // 49 - undefined + (2.54* 9.5 , 11.0 *2.54), // 50 - Letter Extra + (2.54* 9.5 , 15.0 *2.54), // 51 - Legal Extra + (2.54* 11.6875, 18.0 *2.54), // 52 - Tabloid Extra + ( 235.0 , 322.0 ), // 53 - A4 Extra + (2.54* 8.5 , 11.0 *2.54), // 54 - Letter Transverse + ( 210.0 , 297.0 ), // 55 - A4 Transverse + (2.54* 9.5 , 11.0 *2.54), // 56 - Letter Extra Transverse + ( 227.0 , 356.0 ), // 57 - Super A/A4 + ( 305.0 , 487.0 ), // 58 - Super B/B4 + (2.54* 8.5 , 12.6875*2.54), // 59 - Letter plus + ( 210.0 , 330.0 ), // 60 - A4 plus + ( 148.0 , 210.0 ), // 61 - A5 transverse + ( 182.0 , 257.0 ), // 62 - B5 (JIS) transverse + ( 322.0 , 445.0 ), // 63 - A3 Extra + ( 174.0 , 235.0 ), // 64 - A5 Extra + ( 201.0 , 276.0 ), // 65 - B5 (ISO) Extra + ( 420.0 , 594.0 ), // 66 - A2 + ( 297.0 , 420.0 ), // 67 - A3 Transverse + ( 322.0 , 445.0 ), // 68 - A3 Extra Transverse + ( 200.0 , 148.0 ), // 69 - Double Japanese Postcard + ( 105.0 , 148.0 ), // 70 - A6 + ( 0.0 , 0.0 ), // 71 - undefined + ( 0.0 , 0.0 ), // 72 - undefined + ( 0.0 , 0.0 ), // 73 - undefined + ( 0.0 , 0.0 ), // 74 - undefined + (2.54* 11.0 , 8.5 *2.54), // 75 - Letter rotated + ( 420.0 , 297.0 ), // 76 - A3 rotated + ( 297.0 , 210.0 ), // 77 - A4 rotated + ( 210.0 , 148.0 ), // 78 - A5 rotated + ( 364.0 , 257.0 ), // 79 - B4 (JIS) rotated + ( 257.0 , 182.0 ), // 80 - B5 (JIS) rotated + ( 148.0 , 100.0 ), // 81 - Japanese Postcard rotated + ( 148.0 , 200.0 ), // 82 - Double Japanese Postcard rotated + ( 148.0 , 105.0 ), // 83 - A6 rotated + ( 0.0 , 0.0 ), // 84 - undefined + ( 0.0 , 0.0 ), // 85 - undefined + ( 0.0 , 0.0 ), // 86 - undefined + ( 0.0 , 0.0 ), // 87 - undefined + ( 128.0 , 182.0 ), // 88 - B6 (JIS) + ( 182.0 , 128.0 ), // 89 - B6 (JIS) rotated + (2.54* 12.0 , 11.0 *2.54) // 90 - 12x11 + ); + type TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28 @@ -263,6 +365,7 @@ type // Read a blank cell procedure ReadBlank(AStream: TStream); override; procedure ReadBool(AStream: TStream); override; + procedure ReadBottomMargin(AStream: TStream); procedure ReadCodePage(AStream: TStream); // Read column info procedure ReadColInfo(const AStream: TStream); @@ -278,6 +381,8 @@ type procedure ReadFormat(AStream: TStream); virtual; // Read FORMULA record procedure ReadFormula(AStream: TStream); override; + procedure ReadHCENTER(AStream: TStream); + procedure ReadLeftMargin(AStream: TStream); // Read multiple blank cells procedure ReadMulBlank(AStream: TStream); // Read multiple RK cells @@ -286,8 +391,13 @@ type procedure ReadNumber(AStream: TStream); override; // Read palette procedure ReadPalette(AStream: TStream); + // Read page setup + procedure ReadPageSetup(AStream: TStream); // Read PANE record procedure ReadPane(AStream: TStream); + procedure ReadPrintGridLines(AStream: TStream); + procedure ReadPrintHeaders(AStream: TStream); + procedure ReadRightMargin(AStream: TStream); // Read an RK value cell procedure ReadRKValue(AStream: TStream); // Read the row, column, and XF index at the current stream position @@ -310,11 +420,13 @@ type ASharedFormulaBase: PCell = nil): Boolean; function ReadRPNTokenArraySize(AStream: TStream): word; virtual; procedure ReadSharedFormula(AStream: TStream); + procedure ReadTopMargin(AStream: TStream); // Helper function for reading a string with 8-bit length function ReadString_8bitLen(AStream: TStream): String; virtual; // Read STRING record (result of string formula) procedure ReadStringRecord(AStream: TStream); virtual; + procedure ReadVCENTER(AStream: TStream); // Read WINDOW2 record (gridlines, sheet headers) procedure ReadWindow2(AStream: TStream); virtual; @@ -335,6 +447,7 @@ type function FixColor(AColor: TsColor): TsColor; override; function GetLastRowIndex(AWorksheet: TsWorksheet): Integer; function GetLastColIndex(AWorksheet: TsWorksheet): Word; + function GetPrintOptions: Word; virtual; // Helper function for writing the BIFF header procedure WriteBIFFHeader(AStream: TStream; ARecID, ARecSize: Word); @@ -347,6 +460,8 @@ type // Write out BOOLEAN cell record procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal; const AValue: Boolean; ACell: PCell); override; + // Writes out bottom page margin for printing + procedure WriteBottomMargin(AStream: TStream); // Writes out used codepage for character encoding procedure WriteCodePage(AStream: TStream; ACodePage: String); virtual; // Writes out column info(s) @@ -365,6 +480,9 @@ type // Writes out a FORMULA record; formula is stored in cell already procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override; + procedure WriteHCenter(AStream: TStream); + // Writes out left page margin for printing + procedure WriteLeftMargin(AStream: TStream); // Writes out a FORMAT record procedure WriteNumFormat(AStream: TStream; ANumFormatStr: String; ANumFormatIndex: Integer); virtual; @@ -379,6 +497,11 @@ type // Writes out a PANE record procedure WritePane(AStream: TStream; ASheet: TsWorksheet; IsBiff58: Boolean; out ActivePane: Byte); + // Writes out whether grid lines are printed + procedure WritePrintGridLines(AStream: TStream); + procedure WritePrintHeaders(AStream: TStream); + // Writes out right page margin for printing + procedure WriteRightMargin(AStream: TStream); // Writes out a ROW record procedure WriteRow(AStream: TStream; ASheet: TsWorksheet; ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual; @@ -414,6 +537,9 @@ type *) procedure WriteSheetPR(AStream: TStream); procedure WriteStringRecord(AStream: TStream; AString: String); virtual; + // Writes out the top page margin used when printing + procedure WriteTopMargin(AStream: TStream); + procedure WriteVCenter(AStream: TStream); // Writes cell content received by workbook in OnNeedCellData event procedure WriteVirtualCells(AStream: TStream); // Writes out a WINDOW1 record @@ -510,6 +636,7 @@ type TextLen: Word; end; + function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime; begin @@ -851,6 +978,18 @@ begin Workbook.OnReadCellData(Workbook, r, c, cell); end; +{@@ ---------------------------------------------------------------------------- + Reads the bottom page margin of the current worksheet (for printing). + The file value is in inches. +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadBottomMargin(AStream: TStream); +var + dbl: Double; +begin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.BottomMargin := InToMM(dbl); +end; + {@@ ---------------------------------------------------------------------------- Reads the code page used in the xls file In BIFF8 it seams to always use the UTF-16 codepage @@ -1141,6 +1280,30 @@ begin Workbook.OnReadCellData(Workbook, ARow, ACol, cell); end; +{@@ ---------------------------------------------------------------------------- + Reads whether the page is to be centered horizontally for printing +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadHCENTER(AStream: TStream); +var + w: word; +begin + w := WordLEToN(AStream.ReadWord); + if w = 1 then Include(FWorksheet.PageLayout.Options, poHorCentered); +end; + + +{@@ ---------------------------------------------------------------------------- + Reads the left page margin of the current worksheet (for printing). + The file value is in inches. +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadLeftMargin(AStream: TStream); +var + dbl: Double; +begin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.LeftMargin := InToMM(dbl); +end; + {@@ ---------------------------------------------------------------------------- Reads multiple blank cell records Valid for BIFF5 and BIFF8 (does not exist before) @@ -1294,6 +1457,72 @@ begin FPaletteFound := true; end; +{@@ ---------------------------------------------------------------------------- + Reads the page setup record containing some parameters for printing +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadPageSetup(AStream: TStream); +var + w: Word; + dbl: Double; +begin + // Paper size + w := WordLEToN(AStream.ReadWord); + if (w >= 0) and (w <= High(PAPER_SIZES)) then + begin + FWorksheet.PageLayout.PageWidth := PAPER_SIZES[w, 0]; + FWorksheet.PageLayout.PageHeight := PAPER_SIZES[w, 1]; + end; + + // Scaling factor in percent + FWorksheet.PageLayout.ScalingFactor := WordLEToN(AStream.ReadWord); + + // Start page number + FWorksheet.PageLayout.StartPageNumber := WordLEToN(AStream.ReadWord); + + // Fit worksheet width to this number of pages (0 = use as many as neede) + FWorksheet.PageLayout.FitWidthToPages := WordLEToN(AStream.ReadWord); + + // Fit worksheet height to this number of pages (0 = use as many as needed) + FWorksheet.PageLayout.FitHeightToPages := WordLEToN(AStream.ReadWord); + + // 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); + + // Print resolution in dpi -- ignoried + w := WordLEToN(AStream.ReadWord); + + // Vertical print resolution in dpi -- ignored + w := WordLEToN(AStream.ReadWord); + + // Header margin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.HeaderMargin := InToMM(dbl); + + // Footer margin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.FooterMargin := InToMM(dbl); + + // Number of copies + FWorksheet.PageLayout.Copies := WordLEToN(AStream.ReadWord); +end; + {@@ ---------------------------------------------------------------------------- Reads pane sizes Valid for all BIFF versions @@ -1321,6 +1550,30 @@ begin [9] 1 Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4) } end; +{@@ ---------------------------------------------------------------------------- + Reads whether the gridlines are printed or not +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadPrintGridLines(AStream: TStream); +var + w: Word; +begin + w := WordLEToN(AStream.ReadWord); + if w = 1 then + Include(FWorksheet.PageLayout.Options, poPrintGridLines); +end; + +{@@ ---------------------------------------------------------------------------- + Reads whether the spreadsheet row/column headers are printed or not +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadPrintHeaders(AStream: TStream); +var + w: Word; +begin + w := WordLEToN(AStream.ReadWord); + if w = 1 then + Include(FWorksheet.PageLayout.Options , poPrintHeaders); +end; + {@@ ---------------------------------------------------------------------------- Reads the row, column and xf index NOT VALID for BIFF2 @@ -1336,6 +1589,18 @@ begin AXF := WordLEtoN(AStream.ReadWord); end; +{@@ ---------------------------------------------------------------------------- + Reads the right page margin of the current worksheet (for printing). + The file value is in inches. +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadRightMargin(AStream: TStream); +var + dbl: Double; +begin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.RightMargin := InToMM(dbl); +end; + {@@ ---------------------------------------------------------------------------- Reads an RK value cell from the stream Valid since BIFF3. @@ -1799,6 +2064,29 @@ begin Unused(AStream); end; +{@@ ---------------------------------------------------------------------------- + Reads the top page margin of the current worksheet (for printing). + The file value is in inches. +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadTopMargin(AStream: TStream); +var + dbl: Double; +begin + AStream.ReadBuffer(dbl, SizeOf(dbl)); + FWorksheet.PageLayout.TopMargin := InToMM(dbl); +end; + +{@@ ---------------------------------------------------------------------------- + Reads whether the page is to be centered vertically for printing +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFReader.ReadVCENTER(AStream: TStream); +var + w: word; +begin + w := WordLEToN(AStream.ReadWord); + if w = 1 then Include(FWorksheet.PageLayout.Options, poVertCentered); +end; + {@@ ---------------------------------------------------------------------------- Reads the WINDOW2 record containing information like "show grid lines", "show sheet headers", "panes are frozen", etc. @@ -1893,6 +2181,46 @@ begin Result := AWorksheet.GetLastColIndex; end; +{@@ ---------------------------------------------------------------------------- + Converts the Options of the worksheet's PageLayout to the bitmap required + by the PageSetup record + Is overridden by BIFF8 which uses more bits. Not used by BIFF2. +-------------------------------------------------------------------------------} +function TsSpreadBIFFWriter.GetPrintOptions: Word; +begin + { Options: + Bit 0: 0 = Print pages in columns; 1 = Print pages in rows + Bit 1: 0 = Landscape; 1 = Portrait + Bit 2: 1 = Paper size, scaling factor, paper orientation (portrait/landscape), + print resolution and number of copies are not initialised + Bit 3: 0 = Print coloured; 1 = Print black and white + Bit 4: 0 = Default print quality; 1 = Draft quality + Bit 5: 0 = Do not print cell notes; 1 = Print cell notes + Bit 6: 0 = Use paper orientation (portrait/landscape) flag above + 1 = Use default paper orientation (landscape for chart sheets, portrait otherwise) + Bit 7: 0 = Automatic page numbers; 1 = Use start page number above + + The following flags are valid for BIFF8 only: + Bit 9: 0 = Print notes as displayed; 1 = Print notes at end of sheet + Bit 11-10: 00 = Print errors as displayed; 1 = Do not print errors + 2 = Print errors as “--”; 3 = Print errors as “#N/A” } + Result := 0; + if poPrintPagesByRows in FWorksheet.PageLayout.Options then + Result := Result or $0001; + if FWorksheet.PageLayout.Orientation = spoPortrait then + Result := Result or $0002; + if poMonochrome in FWorksheet.PageLayout.Options then + Result := Result or $0008; + if poDraftQuality in FWorksheet.PageLayout.Options then + Result := Result or $0010; + if poPrintCellComments in FWorksheet.PageLayout.Options then + Result := Result or $0020; + if poDefaultOrientation in FWorksheet.PageLayout.Options then + Result := Result or $0040; + if poUseStartPageNumber in FWorksheet.PageLayout.Options then + Result := Result or $0080; +end; + {@@ ---------------------------------------------------------------------------- Writes the BIFF record header consisting of the record ID and the size of data to be written immediately afterwards. @@ -1970,6 +2298,21 @@ begin AStream.WriteBuffer(rec, SizeOf(rec)); end; +{@@ ---------------------------------------------------------------------------- + Write the bottom margin of the printed page (in inches) +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteBottomMargin(AStream: TStream); +var + dbl: double; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_BOTTOMMARGIN, SizeOf(Double)); + + { Page margin value, written in inches } + dbl := mmToIn(FWorksheet.PageLayout.BottomMargin); + AStream.WriteBuffer(dbl, SizeOf(dbl)); +end; + {@@ ---------------------------------------------------------------------------- Writes the code page identifier defined by the workbook to the stream. BIFF2 has to be overridden because is uses cp1252, but has a different @@ -2192,6 +2535,21 @@ begin AStream.WriteBuffer(rec, SizeOf(rec)); end; +{@@ ---------------------------------------------------------------------------- + Write the left margin of the printed page (in inches) +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteLeftMargin(AStream: TStream); +var + dbl: double; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_LEFTMARGIN, SizeOf(Double)); + + { Page margin value, written in inches } + dbl := mmToIn(FWorksheet.PageLayout.LeftMargin); + AStream.WriteBuffer(dbl, SizeOf(dbl)); +end; + {@@ ---------------------------------------------------------------------------- Writes a BIFF number format record defined in the specified format string (in Excel dialect). @@ -2245,6 +2603,22 @@ begin SetLength(formula, 0); end; +{@@ ---------------------------------------------------------------------------- + Writes an Excel HCENTER record which determines whether the page is to be + centered horizontally for printing +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteHCenter(AStream: TStream); +var + w: Word; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_HCENTER, SizeOf(w)); + + { Data } + if poHorCentered in FWorksheet.PageLayout.Options then w := 1 else w := 0; + AStream.WriteWord(WordToLE(w)); +end; + {@@ ---------------------------------------------------------------------------- Writes a 64-bit floating point NUMBER record. Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure). @@ -2304,30 +2678,64 @@ end; {@@ ---------------------------------------------------------------------------- Writes a PAGESETUP record containing information on printing + Valid for BIFF5-8 -------------------------------------------------------------------------------} procedure TsSpreadBIFFWriter.WritePageSetup(AStream: TStream); var dbl: Double; + i: Integer; + w: Word; begin { BIFF record header } WriteBIFFHeader(AStream, INT_EXCEL_ID_PAGESETUP, 9*2 + 2*8); { Paper size } - AStream.WriteWord(WordToLE(0)); // 1 = Letter, 9 = A4 + w := 0; + for i:=0 to High(PAPER_SIZES) do + if (SameValue(PAPER_SIZES[i,0], FWorksheet.PageLayout.PageHeight) and + SameValue(PAPER_SIZES[i,1], FWorksheet.PageLayout.PageWidth)) + or (SameValue(PAPER_SIZES[i,1], FWorksheet.PageLayout.PageHeight) and + SameValue(PAPER_SIZES[i,0], FWorksheet.PageLayout.PageWidth)) + then begin + w := i; + break; + end; + AStream.WriteWord(WordToLE(w)); { Scaling factor in percent } - AStream.WriteWord(WordToLE(100)); // 100 % + w := Round(FWorksheet.PageLayout.ScalingFactor); + AStream.WriteWord(WordToLE(w)); { Start page number } - AStream.WriteWord(WordToLE(1)); // starting at page 1 + w := FWorksheet.PageLayout.StartPageNumber; + AStream.WriteWord(WordToLE(w)); { Fit worksheet width to this number of pages, 0 = use as many as needed } - AStream.WriteWord(WordToLE(0)); + w := FWorksheet.PageLayout.FitWidthToPages; + AStream.WriteWord(WordToLE(w)); { Fit worksheet height to this number of pages, 0 = use as many as needed } - AStream.WriteWord(WordToLE(0)); + w := FWorksheet.PageLayout.FitHeightToPages; + AStream.WriteWord(WordToLE(w)); - AStream.WriteWord(WordToLE(0)); + { Options: + Bit 0: 0 = Print pages in columns; 1 = Print pages in rows + Bit 1: 0 = Landscape; 1 = Portrait + Bit 2: 1 = Paper size, scaling factor, paper orientation (portrait/landscape), + print resolution and number of copies are not initialised + Bit 3: 0 = Print coloured; 1 = Print black and white + Bit 4: 0 = Default print quality; 1 = Draft quality + Bit 5: 0 = Do not print cell notes; 1 = Print cell notes + Bit 6: 0 = Use paper orientation (portrait/landscape) flag above + 1 = Use default paper orientation (landscape for chart sheets, portrait otherwise) + Bit 7: 0 = Automatic page numbers; 1 = Use start page number above + + The following flags are valid for BIFF8 only: + Bit 9: 0 = Print notes as displayed; 1 = Print notes at end of sheet + Bit 11-10: 00 = Print errors as displayed; 1 = Do not print errors + 2 = Print errors as “--”; 3 = Print errors as “#N/A” } + w := GetPrintOptions; + AStream.WriteWord(WordToLE(w)); { Print resolution in dpi } AStream.WriteWord(WordToLE(600)); @@ -2336,13 +2744,16 @@ begin AStream.WriteWord(WordToLE(600)); { Header margin } - dbl := 0.5; + dbl := mmToIn(FWorksheet.PageLayout.HeaderMargin); AStream.WriteBuffer(dbl, SizeOf(dbl)); + { Footer margin } + dbl := mmToIn(FWorksheet.PageLayout.FooterMargin); AStream.WriteBuffer(dbl, SizeOf(dbl)); { Number of copies to print } - AStream.WriteWord(WordToLE(1)); // 1 copy + w := FWorksheet.PageLayout.Copies; + AStream.WriteWord(WordToLE(w)); end; {@@ ---------------------------------------------------------------------------- @@ -2418,6 +2829,36 @@ begin { Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4 } end; +{@@ ---------------------------------------------------------------------------- + Writes out whether grid lines are printed or not +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WritePrintGridLines(AStream: TStream); +var + w: Word; +begin + { Biff record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_PRINTGRID, SizeOf(w)); + + { Data } + if poPrintGridLines in FWorksheet.PageLayout.Options then w := 1 else w := 0; + AStream.WriteWord(WordToLE(w)); +end; + +{@@ ---------------------------------------------------------------------------- + Writes out whether column and row headers are printed or not +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WritePrintHeaders(AStream: TStream); +var + w: Word; +begin + { Biff record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_PRINTHEADERS, SizeOf(w)); + + { Data } + if poPrintHeaders in FWorksheet.PageLayout.Options then w := 1 else w := 0; + AStream.WriteWord(WordToLE(w)); +end; + {@@ ---------------------------------------------------------------------------- Writes the address of a cell as used in an RPN formula and returns the count of bytes written. @@ -2426,7 +2867,7 @@ end; function TsSpreadBIFFWriter.WriteRPNCellAddress(AStream: TStream; ARow, ACol: Cardinal; AFlags: TsRelFlags): Word; var - r: Cardinal; // row index containing encoded relativ/absolute address info + r: Cardinal; // row index containing encoded relative/absolute address info begin // Encoded row address r := ARow and MASK_EXCEL_ROW; @@ -2813,6 +3254,22 @@ begin AStream.WriteWord(WordToLE(ASize)); end; +{@@ ---------------------------------------------------------------------------- + Writes the right margin of the printed page (in inches) +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteRightMargin(AStream: TStream); +var + dbl: double; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_RIGHTMARGIN, SizeOf(Double)); + + { Page margin value, written in inches } + dbl := mmToIn(FWorksheet.PageLayout.RightMargin); + AStream.WriteBuffer(dbl, SizeOf(dbl)); +end; + + {@@ ---------------------------------------------------------------------------- Writes an Excel 3-8 ROW record Valid for BIFF3-BIFF8 @@ -3106,6 +3563,38 @@ begin Unused(AStream, AString); end; +{@@ ---------------------------------------------------------------------------- + Write the top margin of the printed page (in inches) +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteTopMargin(AStream: TStream); +var + dbl: double; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_TOPMARGIN, SizeOf(Double)); + + { Page margin value, written in inches } + dbl := mmToIn(FWorksheet.PageLayout.TopMargin); + AStream.WriteBuffer(dbl, SizeOf(dbl)); +end; + +{@@ ---------------------------------------------------------------------------- + Writes an Excel VCENTER record which determines whether the page is to be + centered vertically for printing +-------------------------------------------------------------------------------} +procedure TsSpreadBIFFWriter.WriteVCenter(AStream: TStream); +var + w: Word; +begin + { BIFF record header } + WriteBIFFHeader(AStream, INT_EXCEL_ID_VCENTER, SizeOf(w)); + + { Data } + if poVertCentered in FWorksheet.PageLayout.Options then w := 1 else w := 0; + AStream.WriteWord(WordToLE(w)); +end; + + procedure TsSpreadBIFFWriter.WriteVirtualCells(AStream: TStream); var r,c: Cardinal; diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index 199595cfe..1db5356a7 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -79,6 +79,7 @@ type procedure ReadNumFormats(ANode: TDOMNode); procedure ReadPageMargins(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadPalette(ANode: TDOMNode); + procedure ReadPrintOptions(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadSharedStrings(ANode: TDOMNode); procedure ReadSheetFormatPr(ANode: TDOMNode; AWorksheet: TsWorksheet); @@ -131,7 +132,10 @@ type procedure WriteNumFormatList(AStream: TStream); procedure WritePalette(AStream: TStream); procedure WritePageMargins(AStream: TStream; AWorksheet: TsWorksheet); + procedure WritePageSetup(AStream: TStream; AWorksheet: TsWorksheet); + procedure WritePrintOptions(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteSheetData(AStream: TStream; AWorksheet: TsWorksheet); + procedure WriteSheetPr(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteSheetViews(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteStyleList(AStream: TStream; ANodeName: String); procedure WriteVmlDrawings(AWorksheet: TsWorksheet); @@ -1307,38 +1311,33 @@ procedure TsSpreadOOXMLReader.ReadPageMargins(ANode: TDOMNode; AWorksheet: TsWorksheet); var s: String; - layout: TsPageLayout; begin - if ANode = nil then + if (ANode = nil) or (AWorksheet = nil) then // just to make sure... exit; - layout := AWorksheet.PageLayout; - s := GetAttrValue(ANode, 'left'); if s <> '' then - layout.LeftMargin := HtmlLengthStrToPts(s); + AWorksheet.PageLayout.LeftMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); s := GetAttrValue(ANode, 'right'); if s <> '' then - layout.RightMargin := HtmlLengthStrToPts(s); + AWorksheet.PageLayout.RightMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); s := GetAttrValue(ANode, 'top'); if s <> '' then - layout.TopMargin := HtmlLengthStrToPts(s); + AWorksheet.PageLayout.TopMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); s := GetAttrValue(ANode, 'bottom'); if s <> '' then - layout.BottomMargin := HtmlLengthStrToPts(s); + AWorksheet.PageLayout.BottomMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); s := GetAttrValue(ANode, 'header'); if s <> '' then - layout.HeaderDistance := HtmlLengthStrToPts(s); + AWorksheet.PageLayout.HeaderMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); s := GetAttrValue(ANode, 'footer'); if s <> '' then - layout.FooterDistance := HtmlLengthStrToPts(s); - - AWorksheet.PageLayout := layout; + AWorksheet.PageLayout.FooterMargin := PtsToMM(HtmlLengthStrToPts(s, 'in')); end; procedure TsSpreadOOXMLReader.ReadPalette(ANode: TDOMNode); @@ -1385,6 +1384,22 @@ begin end; end; +procedure TsSpreadOOXMLReader.ReadPrintOptions(ANode: TDOMNode; + AWorksheet: TsWorksheet); +var + s: String; +begin + if ANode = nil then + exit; + s := GetAttrValue(ANode, 'headings'); + if (s = '1') then + Include(AWorksheet.PageLayout.Options, poPrintHeaders); + + s := GetAttrValue(ANode, 'gridLines'); + if (s = '1') then + Include(AWorksheet.PageLayout.Options, poPrintGridLines); +end; + procedure TsSpreadOOXMLReader.ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet); var s: String; @@ -1709,6 +1724,7 @@ begin ReadWorksheet(Doc.DocumentElement.FindNode('sheetData'), FWorksheet); ReadMergedCells(Doc.DocumentElement.FindNode('mergeCells'), FWorksheet); ReadHyperlinks(Doc.DocumentElement.FindNode('hyperlinks')); + ReadPrintOptions(Doc.DocumentElement.FindNode('printOptions'), FWorksheet); ReadPageMargins(Doc.DocumentElement.FindNode('pageMargins'), FWorksheet); FreeAndNil(Doc); @@ -2309,12 +2325,87 @@ begin with AWorksheet.PageLayout do AppendToStream(AStream, Format( '', [ - PtsToIn(LeftMargin), PtsToIn(RightMargin), PtsToIn(TopMargin), PtsToIn(BottomMargin), - PtsToIn(HeaderDistance), PtsToIn(FooterDistance) ], + mmToIn(LeftMargin), mmToIn(RightMargin), mmToIn(TopMargin), mmToIn(BottomMargin), + mmToIn(HeaderMargin), mmToIn(FooterMargin) ], FPointSeparatorSettings )); end; +procedure TsSpreadOOXMLWriter.WritePageSetup(AStream: TStream; + AWorksheet: TsWorksheet); +var + s: String; + i: Integer; +begin + s := ''; + + // Paper size + for i:=0 to High(PAPER_SIZES) do + if (SameValue(PAPER_SIZES[i,0], AWorksheet.PageLayout.PageHeight) and + SameValue(PAPER_SIZES[i,1], AWorksheet.PageLayout.PageWidth)) + or (SameValue(PAPER_SIZES[i,1], AWorksheet.PageLayout.PageHeight) and + SameValue(PAPER_SIZES[i,0], AWorksheet.PageLayout.PageWidth)) + then begin + s := Format('%s paperSize="%d"', [s, i]); + break; + end; + + // Scaling factor + if AWorksheet.PageLayout.ScalingFactor <> 100 then + s := Format('%s scale="%.0f" fitToHeight="0" fitToWidth="0"', [ + s, AWorksheet.PageLayout.ScalingFactor + ], FPointSeparatorSettings); + + // Fit width pages + if AWorksheet.PageLayout.FitWidthToPages > 0 then + s := Format('%s fitToWidth="%d"', [s, AWorksheet.PageLayout.FitWidthToPages]); + + // Fit height pages + if AWorksheet.PageLayout.FitHeightToPages > 0 then + s := Format('%s fitToHeight="%d"', [s, AWorksheet.PageLayout.FitHeightToPages]); + + // Orientation + s := Format('%s orientation="%s"', [ + s, IfThen(AWorksheet.PageLayout.Orientation = spoPortrait, 'portrait', 'landscape') + ]); + + // First page number + if poUseStartPageNumber in FWorksheet.PageLayout.Options then + s := Format('%s useFirstPageNumber="%d"', [s, AWorksheet.PageLayout.StartPageNumber]); + + // Print order + if poPrintPagesByRows in AWorksheet.PageLayout.Options then + s := s + ' pageOrder="overThenDown"'; + + // Monochrome + if poMonochrome in AWorksheet.PageLayout.Options then + s := s + ' blackAndWhite="1"'; + + // Quality + if poDraftQuality in AWOrksheet.PageLayout.Options then + s := s + ' draft="1"'; + + if s <> '' then + AppendToStream(AStream, + ''); +end; + +procedure TsSpreadOOXMLWriter.WritePrintOptions(AStream: TStream; + AWorksheet: TsWorksheet); +var + s: String; +begin + s := ''; + if poPrintGridLines in AWorksheet.PageLayout.Options then + s := s + ' gridLines="1"'; + if poPrintHeaders in AWorksheet.PageLayout.Options then + s := s + ' headings="1"'; + + if s <> '' then + AppendToStream(AStream, + ''); +end; + procedure TsSpreadOOXMLWriter.WriteSheetData(AStream: TStream; AWorksheet: TsWorksheet); var @@ -2424,6 +2515,21 @@ begin ''); end; +procedure TsSpreadOOXMLWriter.WriteSheetPr(AStream: TStream; AWorksheet: TsWorksheet); +var + s: String; +begin + s := ''; + if (AWorksheet.PageLayout.FitWidthToPages > 0) or + (AWorksheet.PageLayout.FitHeightToPages > 0) then + s := s + ' fitToPage="1"'; + if s <> '' then s := ''; + + if s <> '' then + AppendToStream(AStream, + '' + s + ''); +end; + procedure TsSpreadOOXMLWriter.WriteSheetViews(AStream: TStream; AWorksheet: TsWorksheet); var @@ -2936,13 +3042,16 @@ begin AppendToStream(FSSheets[FCurSheetNum], Format( '', [SCHEMAS_SPREADML, SCHEMAS_DOC_RELS])); + WriteSheetPr(FSSheets[FCurSheetNum], AWorksheet); WriteDimension(FSSheets[FCurSheetNum], AWorksheet); WriteSheetViews(FSSheets[FCurSheetNum], AWorksheet); WriteCols(FSSheets[FCurSheetNum], AWorksheet); WriteSheetData(FSSheets[FCurSheetNum], AWorksheet); WriteHyperlinks(FSSheets[FCurSheetNum], AWorksheet); WriteMergedCells(FSSheets[FCurSheetNum], AWorksheet); + WritePrintOptions(FSSheets[FCurSheetNum], AWorksheet); WritePageMargins(FSSheets[FCurSheetNum], AWorksheet); + WritePageSetup(FSSheets[FCurSheetNum], AWorksheet); // Footer if AWorksheet.Comments.Count > 0 then