fpspreadsheet: Add some more page layout properties (page size, orientation etc) for all Excel and ods formats (ods implementation, however, not correct at the moment).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4103 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-04-30 21:55:55 +00:00
parent 4f520e0bf2
commit 82117326a4
10 changed files with 952 additions and 104 deletions

View File

@@ -66,6 +66,7 @@ type
FRowStyleList: TFPList; FRowStyleList: TFPList;
FRowList: TFPList; FRowList: TFPList;
FDateMode: TDateMode; FDateMode: TDateMode;
FPageLayout: TsPageLayout;
// Applies internally stored column widths to current worksheet // Applies internally stored column widths to current worksheet
procedure ApplyColWidths; procedure ApplyColWidths;
// Applies a style to a cell // Applies a style to a cell
@@ -91,6 +92,7 @@ type
protected protected
FPointSeparatorSettings: TFormatSettings; FPointSeparatorSettings: TFormatSettings;
procedure AddBuiltinNumFormats; override; procedure AddBuiltinNumFormats; override;
procedure ReadAutomaticStyles(AStylesNode: TDOMNode);
procedure ReadNumFormats(AStylesNode: TDOMNode); procedure ReadNumFormats(AStylesNode: TDOMNode);
procedure ReadSettings(AOfficeSettingsNode: TDOMNode); procedure ReadSettings(AOfficeSettingsNode: TDOMNode);
procedure ReadStyles(AStylesNode: TDOMNode); procedure ReadStyles(AStylesNode: TDOMNode);
@@ -618,6 +620,8 @@ begin
Workbook.UseDefaultPalette; Workbook.UseDefaultPalette;
// Initial base date in case it won't be read from file // Initial base date in case it won't be read from file
FDateMode := dm1899; FDateMode := dm1899;
// Initialize internal PageLayout record
InitPageLayout(FPageLayout);
end; end;
destructor TsSpreadOpenDocReader.Destroy; destructor TsSpreadOpenDocReader.Destroy;
@@ -850,6 +854,79 @@ begin
Result := -1; Result := -1;
end; 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; procedure TsSpreadOpenDocReader.ReadBlank(ARow, ACol: Cardinal;
ACellNode: TDOMNode); ACellNode: TDOMNode);
var var
@@ -1317,6 +1394,9 @@ begin
ReadNumFormats(StylesNode); ReadNumFormats(StylesNode);
ReadStyles(StylesNode); ReadStyles(StylesNode);
StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles');
ReadAutomaticStyles(StylesNode);
Doc.Free; Doc.Free;
//process the content.xml file //process the content.xml file
@@ -1349,6 +1429,7 @@ begin
continue; continue;
end; end;
FWorkSheet := FWorkbook.AddWorksheet(GetAttrValue(TableNode,'table:name'), true); FWorkSheet := FWorkbook.AddWorksheet(GetAttrValue(TableNode,'table:name'), true);
FWorksheet.PageLayout := FPageLayout;
// Collect column styles used // Collect column styles used
ReadColumns(TableNode); ReadColumns(TableNode);
// Process each row inside the sheet and process each cell of the row // Process each row inside the sheet and process each cell of the row

View File

@@ -105,7 +105,6 @@ type
FDefaultColWidth: Single; // in "characters". Excel uses the width of char "0" in 1st font FDefaultColWidth: Single; // in "characters". Excel uses the width of char "0" in 1st font
FDefaultRowHeight: Single; // in "character heights", i.e. line count FDefaultRowHeight: Single; // in "character heights", i.e. line count
FSortParams: TsSortParams; // Parameters of the current sorting operation FSortParams: TsSortParams; // Parameters of the current sorting operation
FPageLayout: TsPageLayout;
FOnChangeCell: TsCellEvent; FOnChangeCell: TsCellEvent;
FOnChangeFont: TsCellEvent; FOnChangeFont: TsCellEvent;
FOnCompareCells: TsCellCompareEvent; FOnCompareCells: TsCellCompareEvent;
@@ -138,6 +137,9 @@ type
procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal); procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal);
public public
{@@ Page layout parameters for printing }
PageLayout: TsPageLayout;
{ Base methods } { Base methods }
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
@@ -468,8 +470,6 @@ type
{@@ The default row height is given in "line count" (height of the {@@ The default row height is given in "line count" (height of the
default font } default font }
property DefaultRowHeight: Single read FDefaultRowHeight write FDefaultRowHeight; 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 // These are properties to interface to TsWorksheetGrid
{@@ Parameters controlling visibility of grid lines and row/column headers, {@@ Parameters controlling visibility of grid lines and row/column headers,
@@ -1114,14 +1114,7 @@ begin
FMergedCells := TsMergedCells.Create; FMergedCells := TsMergedCells.Create;
FHyperlinks := TsHyperlinks.Create; FHyperlinks := TsHyperlinks.Create;
with FPageLayout do begin InitPageLayout(PageLayout);
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;
FDefaultColWidth := 12; FDefaultColWidth := 12;
FDefaultRowHeight := 1; FDefaultRowHeight := 1;
@@ -6767,6 +6760,8 @@ begin
// Remember the workbook to which it belongs (This must occur before // Remember the workbook to which it belongs (This must occur before
// setting the workbook name because the workbook is needed there). // setting the workbook name because the workbook is needed there).
Result.FWorkbook := Self; Result.FWorkbook := Self;
Result.FActiveCellRow := 0;
Result.FActiveCellCol := 0;
// Set the name of the new worksheet. // Set the name of the new worksheet.
// For this we turn off notification of listeners. This is not necessary here // For this we turn off notification of listeners. This is not necessary here

View File

@@ -2881,6 +2881,9 @@ end;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadsheetInspector.UpdateWorksheet(ASheet: TsWorksheet; procedure TsSpreadsheetInspector.UpdateWorksheet(ASheet: TsWorksheet;
AStrings: TStrings); AStrings: TStrings);
var
s: String;
po: TsPrintOption;
begin begin
if ASheet = nil then if ASheet = nil then
begin begin
@@ -2891,6 +2894,7 @@ begin
AStrings.Add('Last column='); AStrings.Add('Last column=');
AStrings.Add('Active cell='); AStrings.Add('Active cell=');
AStrings.Add('Selection='); AStrings.Add('Selection=');
AStrings.Add('Page layout=');
end else end else
begin begin
AStrings.Add(Format('Name=%s', [ASheet.Name])); AStrings.Add(Format('Name=%s', [ASheet.Name]));
@@ -2903,6 +2907,27 @@ begin
AStrings.Add(Format('Comments=%d items', [ASheet.Comments.Count])); AStrings.Add(Format('Comments=%d items', [ASheet.Comments.Count]));
AStrings.Add(Format('Hyperlinks=%d items', [ASheet.Hyperlinks.Count])); AStrings.Add(Format('Hyperlinks=%d items', [ASheet.Hyperlinks.Count]));
AStrings.Add(Format('MergedCells=%d items', [ASheet.MergedCells.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;
end; end;

View File

@@ -668,13 +668,39 @@ type
cctError : (ErrorValue: TsErrorValue); cctError : (ErrorValue: TsErrorValue);
end; 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; RightMargin: Double;
TopMargin: Double; TopMargin: Double;
BottomMargin: Double; BottomMargin: Double;
HeaderDistance: Double; HeaderMargin: Double;
FooterDistance: Double; FooterMargin: Double;
StartPageNumber: Integer;
ScalingFactor: Double; // in percent
FitWidthToPages: Integer;
FitHeightToPages: Integer;
Copies: Integer;
Options: TsPrintOptions;
end; end;
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String; function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;

View File

@@ -134,17 +134,19 @@ function TryStrToFloatAuto(AText: String; out ANumber: Double;
function TryFractionStrToFloat(AText: String; out ANumber: Double; function TryFractionStrToFloat(AText: String; out ANumber: Double;
out AMaxDigits: Integer): Boolean; out AMaxDigits: Integer): Boolean;
function TwipsToPts(AValue: Integer): Single; function TwipsToPts(AValue: Integer): Single; inline;
function PtsToTwips(AValue: Single): Integer; function PtsToTwips(AValue: Single): Integer; inline;
function cmToPts(AValue: Double): Double; function cmToPts(AValue: Double): Double; inline;
function PtsToCm(AValue: Double): Double; function PtsToCm(AValue: Double): Double; inline;
function InToPts(AValue: Double): Double; function InToMM(AValue: Double): Double; inline;
function PtsToIn(AValue: Double): Double; function InToPts(AValue: Double): Double; inline;
function mmToPts(AValue: Double): Double; function PtsToIn(AValue: Double): Double; inline;
function PtsToMM(AValue: Double): Double; function mmToPts(AValue: Double): Double; inline;
function pxToPts(AValue, AScreenPixelsPerInch: Integer): Double; function mmToIn(AValue: Double): Double; inline;
function PtsToPx(AValue: Double; AScreenPixelsPerInch: Integer): Integer; function PtsToMM(AValue: Double): Double; inline;
function HTMLLengthStrToPts(AValue: String): Double; 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 HTMLColorStrToColor(AValue: String): TsColorValue;
function ColorToHTMLColorStr(AValue: TsColorValue; AExcelDialect: Boolean = false): String; 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(out ACell: TCell); overload;
procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload; procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload;
procedure InitFormatRecord(out AValue: TsCellFormat); procedure InitFormatRecord(out AValue: TsCellFormat);
procedure InitPageLayout(out APageLayout: TsPageLayout);
procedure AppendToStream(AStream: TStream; const AString: String); inline; overload; procedure AppendToStream(AStream: TStream; const AString: String); inline; overload;
procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload; procedure AppendToStream(AStream: TStream; const AString1, AString2: String); inline; overload;
@@ -1977,6 +1980,28 @@ begin
Result := AValue / 72 * 2.54; Result := AValue / 72 * 2.54;
end; 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) Converts inches to points (72 pts = 1 inch)
@@ -2052,9 +2077,11 @@ end;
such as '1.25in'. These unit codes are accepted: such as '1.25in'. These unit codes are accepted:
'px' (pixels), 'pt' (points), 'in' (inches), 'mm' (millimeters), 'px' (pixels), 'pt' (points), 'in' (inches), 'mm' (millimeters),
'cm' (centimeters). 'cm' (centimeters).
@param DefaultUnits String identifying the units to be used if not contained
in AValue.
@return Extracted length in points @return Extracted length in points
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function HTMLLengthStrToPts(AValue: String): Double; function HTMLLengthStrToPts(AValue: String; DefaultUnits: String = 'pt'): Double;
var var
units: String; units: String;
x: Double; x: Double;
@@ -2062,10 +2089,11 @@ var
begin begin
if (Length(AValue) > 1) and (AValue[Length(AValue)] in ['a'..'z', 'A'..'Z']) then begin if (Length(AValue) > 1) and (AValue[Length(AValue)] in ['a'..'z', 'A'..'Z']) then begin
units := lowercase(Copy(AValue, Length(AValue)-1, 2)); units := lowercase(Copy(AValue, Length(AValue)-1, 2));
if units = '' then units := DefaultUnits;
val(copy(AValue, 1, Length(AValue)-2), x, res); val(copy(AValue, 1, Length(AValue)-2), x, res);
// No hasseling with the decimal point... // No hasseling with the decimal point...
end else begin end else begin
units := ''; units := DefaultUnits;
val(AValue, x, res); val(AValue, x, res);
end; end;
if res <> 0 then if res <> 0 then
@@ -2376,6 +2404,30 @@ begin
AValue.NumberFormatIndex := -1; // GENERAL format not contained in NumFormatList AValue.NumberFormatIndex := -1; // GENERAL format not contained in NumFormatList
end; 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 Appends a string to a stream

View File

@@ -455,27 +455,33 @@ begin
case RecordType of case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream); INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
INT_EXCEL_ID_BOTTOMMARGIN: ReadBottomMargin(AStream);
INT_EXCEL_ID_CODEPAGE : ReadCodePage(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_FONT : ReadFont(AStream);
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream); INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
INT_EXCEL_ID_FORMAT : ReadFormat(AStream); INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_INTEGER : ReadInteger(AStream); INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
INT_EXCEL_ID_IXFE : ReadIXFE(AStream); INT_EXCEL_ID_IXFE : ReadIXFE(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream); INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_LEFTMARGIN : ReadLeftMargin(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream); INT_EXCEL_ID_NOTE : ReadComment(AStream);
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream); INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(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_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_TOPMARGIN : ReadTopMargin(AStream);
INT_EXCEL_ID_DEFROWHEIGHT: ReadDefRowHeight(AStream); INT_EXCEL_ID_DEFROWHEIGHT: ReadDefRowHeight(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_XF : ReadXF(AStream); INT_EXCEL_ID_XF : ReadXF(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : BIFF2EOF := True;
else else
// nothing // nothing
end; end;
@@ -1229,8 +1235,18 @@ begin
raise Exception.Create(rsWorksheetNotFound1); raise Exception.Create(rsWorksheetNotFound1);
WriteBOF(AStream); WriteBOF(AStream);
WriteFonts(AStream);
WriteCodePage(AStream, FCodePage); 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); WriteFormatCount(AStream);
WriteNumFormats(AStream); WriteNumFormats(AStream);
WriteXFRecords(AStream); WriteXFRecords(AStream);

View File

@@ -390,25 +390,34 @@ begin
case RecordType of case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream); INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); 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_MULBLANK : ReadMulBlank(AStream);
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_NOTE : ReadComment(AStream); INT_EXCEL_ID_NOTE : ReadComment(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(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_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ; INT_EXCEL_ID_PAGESETUP : ReadPageSetup(AStream);
INT_EXCEL_ID_EOF : SectionEOF := True; 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 {$IFDEF FPSPREADDEBUG} // Only write out if debugging
else else
@@ -1030,9 +1039,19 @@ begin
AStream.Position := CurrentPos; AStream.Position := CurrentPos;
WriteBOF(AStream, INT_BOF_SHEET); WriteBOF(AStream, INT_BOF_SHEET);
WriteIndex(AStream); 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); WriteColInfos(AStream, FWorksheet);
WriteDimensions(AStream, FWorksheet); WriteDimensions(AStream, FWorksheet);
WriteWindow2(AStream, FWorksheet); WriteWindow2(AStream, FWorksheet);

View File

@@ -120,6 +120,7 @@ type
TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter) TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter)
protected protected
function GetPrintOptions: Word; override;
{ Record writing methods } { Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word); procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64;
@@ -675,39 +676,51 @@ begin
case RecordType of case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream); INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream); INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_CONTINUE : ReadCONTINUE(AStream); INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_BOTTOMMARGIN : ReadBottomMargin(AStream);
INT_EXCEL_ID_HYPERLINK : ReadHyperlink(AStream); INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_HLINKTOOLTIP: ReadHyperlinkToolTip(AStream); INT_EXCEL_ID_CONTINUE : ReadCONTINUE(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream); INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream);
INT_EXCEL_ID_MULBLANK : ReadMulBlank(AStream); INT_EXCEL_ID_EOF : SectionEOF := True;
INT_EXCEL_ID_NOTE : ReadNOTE(AStream); INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_NUMBER : ReadNumber(AStream); INT_EXCEL_ID_HCENTER : ReadHCENTER(AStream);
INT_EXCEL_ID_OBJ : ReadOBJ(AStream); INT_EXCEL_ID_HLINKTOOLTIP : ReadHyperlinkToolTip(AStream);
INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream); INT_EXCEL_ID_HYPERLINK : ReadHyperlink(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream); INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_TXO : ReadTXO(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). //(RSTRING) This record stores a formatted text cell (Rich-Text).
// In BIFF8 it is usually replaced by the LABELSST record. Excel still // In BIFF8 it is usually replaced by the LABELSST record. Excel still
// uses this record, if it copies formatted text cells to the clipboard. // 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 // (RK) This record represents a cell that contains an RK value
// (encoded integer or floating-point value). If a floating-point // (encoded integer or floating-point value). If a floating-point
// value cannot be encoded to an RK value, a NUMBER record will be written. // value cannot be encoded to an RK value, a NUMBER record will be written.
// This record replaces the record INTEGER written in BIFF2. // This record replaces the record INTEGER written in BIFF2.
INT_EXCEL_ID_RK : ReadRKValue(AStream); INT_EXCEL_ID_RK : ReadRKValue(AStream);
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_LABELSST : ReadLabelSST(AStream); //BIFF8 only INT_EXCEL_ID_SHAREDFMLA : ReadSharedFormula(AStream);
INT_EXCEL_ID_DEFCOLWIDTH : ReadDefColWidth(AStream); INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); INT_EXCEL_ID_TOPMARGIN : ReadTopMargin(AStream);
INT_EXCEL_ID_MERGEDCELLS : ReadMergedCells(AStream); INT_EXCEL_ID_TXO : ReadTXO(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream); INT_EXCEL_ID_VCENTER : ReadVCENTER(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_EOF : SectionEOF := True;
else else
// nothing // nothing
end; end;
@@ -1614,6 +1627,17 @@ begin
FDateMode := Excel8Settings.DateMode; FDateMode := Excel8Settings.DateMode;
end; 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 Writes an Excel BIFF8 file to the disc
@@ -1695,8 +1719,20 @@ begin
WriteBOF(AStream, INT_BOF_SHEET); WriteBOF(AStream, INT_BOF_SHEET);
WriteIndex(AStream); WriteIndex(AStream);
WritePrintHeaders(AStream);
WritePrintGridLines(AStream);
//WriteSheetPR(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); WriteColInfos(AStream, FWorksheet);
WriteDimensions(AStream, FWorksheet); WriteDimensions(AStream, FWorksheet);
//WriteRowAndCellBlock(AStream, sheet); //WriteRowAndCellBlock(AStream, sheet);

View File

@@ -20,6 +20,12 @@ const
INT_EXCEL_ID_NOTE = $001C; INT_EXCEL_ID_NOTE = $001C;
INT_EXCEL_ID_SELECTION = $001D; INT_EXCEL_ID_SELECTION = $001D;
INT_EXCEL_ID_DATEMODE = $0022; 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_CONTINUE = $003C;
INT_EXCEL_ID_WINDOW1 = $003D; INT_EXCEL_ID_WINDOW1 = $003D;
INT_EXCEL_ID_PANE = $0041; INT_EXCEL_ID_PANE = $0041;
@@ -33,6 +39,8 @@ const
{ RECORD IDs which did not change across version 3-8} { RECORD IDs which did not change across version 3-8}
INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2 INT_EXCEL_ID_COLINFO = $007D; // does not exist in BIFF2
INT_EXCEL_ID_SHEETPR = $0081; // 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_COUNTRY = $008C; // does not exist in BIFF2
INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2 INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2
INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000 INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000
@@ -215,6 +223,100 @@ const
{ Index of last built-in XF format record } { Index of last built-in XF format record }
LAST_BUILTIN_XF = 15; 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 type
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28 TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
@@ -263,6 +365,7 @@ type
// Read a blank cell // Read a blank cell
procedure ReadBlank(AStream: TStream); override; procedure ReadBlank(AStream: TStream); override;
procedure ReadBool(AStream: TStream); override; procedure ReadBool(AStream: TStream); override;
procedure ReadBottomMargin(AStream: TStream);
procedure ReadCodePage(AStream: TStream); procedure ReadCodePage(AStream: TStream);
// Read column info // Read column info
procedure ReadColInfo(const AStream: TStream); procedure ReadColInfo(const AStream: TStream);
@@ -278,6 +381,8 @@ type
procedure ReadFormat(AStream: TStream); virtual; procedure ReadFormat(AStream: TStream); virtual;
// Read FORMULA record // Read FORMULA record
procedure ReadFormula(AStream: TStream); override; procedure ReadFormula(AStream: TStream); override;
procedure ReadHCENTER(AStream: TStream);
procedure ReadLeftMargin(AStream: TStream);
// Read multiple blank cells // Read multiple blank cells
procedure ReadMulBlank(AStream: TStream); procedure ReadMulBlank(AStream: TStream);
// Read multiple RK cells // Read multiple RK cells
@@ -286,8 +391,13 @@ type
procedure ReadNumber(AStream: TStream); override; procedure ReadNumber(AStream: TStream); override;
// Read palette // Read palette
procedure ReadPalette(AStream: TStream); procedure ReadPalette(AStream: TStream);
// Read page setup
procedure ReadPageSetup(AStream: TStream);
// Read PANE record // Read PANE record
procedure ReadPane(AStream: TStream); procedure ReadPane(AStream: TStream);
procedure ReadPrintGridLines(AStream: TStream);
procedure ReadPrintHeaders(AStream: TStream);
procedure ReadRightMargin(AStream: TStream);
// Read an RK value cell // Read an RK value cell
procedure ReadRKValue(AStream: TStream); procedure ReadRKValue(AStream: TStream);
// Read the row, column, and XF index at the current stream position // Read the row, column, and XF index at the current stream position
@@ -310,11 +420,13 @@ type
ASharedFormulaBase: PCell = nil): Boolean; ASharedFormulaBase: PCell = nil): Boolean;
function ReadRPNTokenArraySize(AStream: TStream): word; virtual; function ReadRPNTokenArraySize(AStream: TStream): word; virtual;
procedure ReadSharedFormula(AStream: TStream); procedure ReadSharedFormula(AStream: TStream);
procedure ReadTopMargin(AStream: TStream);
// Helper function for reading a string with 8-bit length // Helper function for reading a string with 8-bit length
function ReadString_8bitLen(AStream: TStream): String; virtual; function ReadString_8bitLen(AStream: TStream): String; virtual;
// Read STRING record (result of string formula) // Read STRING record (result of string formula)
procedure ReadStringRecord(AStream: TStream); virtual; procedure ReadStringRecord(AStream: TStream); virtual;
procedure ReadVCENTER(AStream: TStream);
// Read WINDOW2 record (gridlines, sheet headers) // Read WINDOW2 record (gridlines, sheet headers)
procedure ReadWindow2(AStream: TStream); virtual; procedure ReadWindow2(AStream: TStream); virtual;
@@ -335,6 +447,7 @@ type
function FixColor(AColor: TsColor): TsColor; override; function FixColor(AColor: TsColor): TsColor; override;
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer; function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
function GetLastColIndex(AWorksheet: TsWorksheet): Word; function GetLastColIndex(AWorksheet: TsWorksheet): Word;
function GetPrintOptions: Word; virtual;
// Helper function for writing the BIFF header // Helper function for writing the BIFF header
procedure WriteBIFFHeader(AStream: TStream; ARecID, ARecSize: Word); procedure WriteBIFFHeader(AStream: TStream; ARecID, ARecSize: Word);
@@ -347,6 +460,8 @@ type
// Write out BOOLEAN cell record // Write out BOOLEAN cell record
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Boolean; ACell: PCell); override; const AValue: Boolean; ACell: PCell); override;
// Writes out bottom page margin for printing
procedure WriteBottomMargin(AStream: TStream);
// Writes out used codepage for character encoding // Writes out used codepage for character encoding
procedure WriteCodePage(AStream: TStream; ACodePage: String); virtual; procedure WriteCodePage(AStream: TStream; ACodePage: String); virtual;
// Writes out column info(s) // Writes out column info(s)
@@ -365,6 +480,9 @@ type
// Writes out a FORMULA record; formula is stored in cell already // Writes out a FORMULA record; formula is stored in cell already
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
ACell: PCell); override; ACell: PCell); override;
procedure WriteHCenter(AStream: TStream);
// Writes out left page margin for printing
procedure WriteLeftMargin(AStream: TStream);
// Writes out a FORMAT record // Writes out a FORMAT record
procedure WriteNumFormat(AStream: TStream; ANumFormatStr: String; procedure WriteNumFormat(AStream: TStream; ANumFormatStr: String;
ANumFormatIndex: Integer); virtual; ANumFormatIndex: Integer); virtual;
@@ -379,6 +497,11 @@ type
// Writes out a PANE record // Writes out a PANE record
procedure WritePane(AStream: TStream; ASheet: TsWorksheet; IsBiff58: Boolean; procedure WritePane(AStream: TStream; ASheet: TsWorksheet; IsBiff58: Boolean;
out ActivePane: Byte); 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 // Writes out a ROW record
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet; procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual; ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual;
@@ -414,6 +537,9 @@ type
*) *)
procedure WriteSheetPR(AStream: TStream); procedure WriteSheetPR(AStream: TStream);
procedure WriteStringRecord(AStream: TStream; AString: String); virtual; 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 // Writes cell content received by workbook in OnNeedCellData event
procedure WriteVirtualCells(AStream: TStream); procedure WriteVirtualCells(AStream: TStream);
// Writes out a WINDOW1 record // Writes out a WINDOW1 record
@@ -510,6 +636,7 @@ type
TextLen: Word; TextLen: Word;
end; end;
function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double; function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double;
ADateMode: TDateMode): TDateTime; ADateMode: TDateMode): TDateTime;
begin begin
@@ -851,6 +978,18 @@ begin
Workbook.OnReadCellData(Workbook, r, c, cell); Workbook.OnReadCellData(Workbook, r, c, cell);
end; 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 Reads the code page used in the xls file
In BIFF8 it seams to always use the UTF-16 codepage In BIFF8 it seams to always use the UTF-16 codepage
@@ -1141,6 +1280,30 @@ begin
Workbook.OnReadCellData(Workbook, ARow, ACol, cell); Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
end; 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 Reads multiple blank cell records
Valid for BIFF5 and BIFF8 (does not exist before) Valid for BIFF5 and BIFF8 (does not exist before)
@@ -1294,6 +1457,72 @@ begin
FPaletteFound := true; FPaletteFound := true;
end; 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 Reads pane sizes
Valid for all BIFF versions Valid for all BIFF versions
@@ -1321,6 +1550,30 @@ begin
[9] 1 Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4) } [9] 1 Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4) }
end; 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 Reads the row, column and xf index
NOT VALID for BIFF2 NOT VALID for BIFF2
@@ -1336,6 +1589,18 @@ begin
AXF := WordLEtoN(AStream.ReadWord); AXF := WordLEtoN(AStream.ReadWord);
end; 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 Reads an RK value cell from the stream
Valid since BIFF3. Valid since BIFF3.
@@ -1799,6 +2064,29 @@ begin
Unused(AStream); Unused(AStream);
end; 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", Reads the WINDOW2 record containing information like "show grid lines",
"show sheet headers", "panes are frozen", etc. "show sheet headers", "panes are frozen", etc.
@@ -1893,6 +2181,46 @@ begin
Result := AWorksheet.GetLastColIndex; Result := AWorksheet.GetLastColIndex;
end; 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 Writes the BIFF record header consisting of the record ID and the size of
data to be written immediately afterwards. data to be written immediately afterwards.
@@ -1970,6 +2298,21 @@ begin
AStream.WriteBuffer(rec, SizeOf(rec)); AStream.WriteBuffer(rec, SizeOf(rec));
end; 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. 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 BIFF2 has to be overridden because is uses cp1252, but has a different
@@ -2192,6 +2535,21 @@ begin
AStream.WriteBuffer(rec, SizeOf(rec)); AStream.WriteBuffer(rec, SizeOf(rec));
end; 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 Writes a BIFF number format record defined in the specified format string
(in Excel dialect). (in Excel dialect).
@@ -2245,6 +2603,22 @@ begin
SetLength(formula, 0); SetLength(formula, 0);
end; 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. Writes a 64-bit floating point NUMBER record.
Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure). Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure).
@@ -2304,30 +2678,64 @@ end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes a PAGESETUP record containing information on printing Writes a PAGESETUP record containing information on printing
Valid for BIFF5-8
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadBIFFWriter.WritePageSetup(AStream: TStream); procedure TsSpreadBIFFWriter.WritePageSetup(AStream: TStream);
var var
dbl: Double; dbl: Double;
i: Integer;
w: Word;
begin begin
{ BIFF record header } { BIFF record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_PAGESETUP, 9*2 + 2*8); WriteBIFFHeader(AStream, INT_EXCEL_ID_PAGESETUP, 9*2 + 2*8);
{ Paper size } { 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 } { Scaling factor in percent }
AStream.WriteWord(WordToLE(100)); // 100 % w := Round(FWorksheet.PageLayout.ScalingFactor);
AStream.WriteWord(WordToLE(w));
{ Start page number } { 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 } { 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 } { 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 } { Print resolution in dpi }
AStream.WriteWord(WordToLE(600)); AStream.WriteWord(WordToLE(600));
@@ -2336,13 +2744,16 @@ begin
AStream.WriteWord(WordToLE(600)); AStream.WriteWord(WordToLE(600));
{ Header margin } { Header margin }
dbl := 0.5; dbl := mmToIn(FWorksheet.PageLayout.HeaderMargin);
AStream.WriteBuffer(dbl, SizeOf(dbl)); AStream.WriteBuffer(dbl, SizeOf(dbl));
{ Footer margin } { Footer margin }
dbl := mmToIn(FWorksheet.PageLayout.FooterMargin);
AStream.WriteBuffer(dbl, SizeOf(dbl)); AStream.WriteBuffer(dbl, SizeOf(dbl));
{ Number of copies to print } { Number of copies to print }
AStream.WriteWord(WordToLE(1)); // 1 copy w := FWorksheet.PageLayout.Copies;
AStream.WriteWord(WordToLE(w));
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@@ -2418,6 +2829,36 @@ begin
{ Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4 } { Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4 }
end; 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 Writes the address of a cell as used in an RPN formula and returns the
count of bytes written. count of bytes written.
@@ -2426,7 +2867,7 @@ end;
function TsSpreadBIFFWriter.WriteRPNCellAddress(AStream: TStream; function TsSpreadBIFFWriter.WriteRPNCellAddress(AStream: TStream;
ARow, ACol: Cardinal; AFlags: TsRelFlags): Word; ARow, ACol: Cardinal; AFlags: TsRelFlags): Word;
var var
r: Cardinal; // row index containing encoded relativ/absolute address info r: Cardinal; // row index containing encoded relative/absolute address info
begin begin
// Encoded row address // Encoded row address
r := ARow and MASK_EXCEL_ROW; r := ARow and MASK_EXCEL_ROW;
@@ -2813,6 +3254,22 @@ begin
AStream.WriteWord(WordToLE(ASize)); AStream.WriteWord(WordToLE(ASize));
end; 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 Writes an Excel 3-8 ROW record
Valid for BIFF3-BIFF8 Valid for BIFF3-BIFF8
@@ -3106,6 +3563,38 @@ begin
Unused(AStream, AString); Unused(AStream, AString);
end; 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); procedure TsSpreadBIFFWriter.WriteVirtualCells(AStream: TStream);
var var
r,c: Cardinal; r,c: Cardinal;

View File

@@ -79,6 +79,7 @@ type
procedure ReadNumFormats(ANode: TDOMNode); procedure ReadNumFormats(ANode: TDOMNode);
procedure ReadPageMargins(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadPageMargins(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadPalette(ANode: TDOMNode); procedure ReadPalette(ANode: TDOMNode);
procedure ReadPrintOptions(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet);
procedure ReadSharedStrings(ANode: TDOMNode); procedure ReadSharedStrings(ANode: TDOMNode);
procedure ReadSheetFormatPr(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadSheetFormatPr(ANode: TDOMNode; AWorksheet: TsWorksheet);
@@ -131,7 +132,10 @@ type
procedure WriteNumFormatList(AStream: TStream); procedure WriteNumFormatList(AStream: TStream);
procedure WritePalette(AStream: TStream); procedure WritePalette(AStream: TStream);
procedure WritePageMargins(AStream: TStream; AWorksheet: TsWorksheet); 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 WriteSheetData(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteSheetPr(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteSheetViews(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteSheetViews(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteStyleList(AStream: TStream; ANodeName: String); procedure WriteStyleList(AStream: TStream; ANodeName: String);
procedure WriteVmlDrawings(AWorksheet: TsWorksheet); procedure WriteVmlDrawings(AWorksheet: TsWorksheet);
@@ -1307,38 +1311,33 @@ procedure TsSpreadOOXMLReader.ReadPageMargins(ANode: TDOMNode;
AWorksheet: TsWorksheet); AWorksheet: TsWorksheet);
var var
s: String; s: String;
layout: TsPageLayout;
begin begin
if ANode = nil then if (ANode = nil) or (AWorksheet = nil) then // just to make sure...
exit; exit;
layout := AWorksheet.PageLayout;
s := GetAttrValue(ANode, 'left'); s := GetAttrValue(ANode, 'left');
if s <> '' then if s <> '' then
layout.LeftMargin := HtmlLengthStrToPts(s); AWorksheet.PageLayout.LeftMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
s := GetAttrValue(ANode, 'right'); s := GetAttrValue(ANode, 'right');
if s <> '' then if s <> '' then
layout.RightMargin := HtmlLengthStrToPts(s); AWorksheet.PageLayout.RightMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
s := GetAttrValue(ANode, 'top'); s := GetAttrValue(ANode, 'top');
if s <> '' then if s <> '' then
layout.TopMargin := HtmlLengthStrToPts(s); AWorksheet.PageLayout.TopMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
s := GetAttrValue(ANode, 'bottom'); s := GetAttrValue(ANode, 'bottom');
if s <> '' then if s <> '' then
layout.BottomMargin := HtmlLengthStrToPts(s); AWorksheet.PageLayout.BottomMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
s := GetAttrValue(ANode, 'header'); s := GetAttrValue(ANode, 'header');
if s <> '' then if s <> '' then
layout.HeaderDistance := HtmlLengthStrToPts(s); AWorksheet.PageLayout.HeaderMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
s := GetAttrValue(ANode, 'footer'); s := GetAttrValue(ANode, 'footer');
if s <> '' then if s <> '' then
layout.FooterDistance := HtmlLengthStrToPts(s); AWorksheet.PageLayout.FooterMargin := PtsToMM(HtmlLengthStrToPts(s, 'in'));
AWorksheet.PageLayout := layout;
end; end;
procedure TsSpreadOOXMLReader.ReadPalette(ANode: TDOMNode); procedure TsSpreadOOXMLReader.ReadPalette(ANode: TDOMNode);
@@ -1385,6 +1384,22 @@ begin
end; end;
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); procedure TsSpreadOOXMLReader.ReadRowHeight(ANode: TDOMNode; AWorksheet: TsWorksheet);
var var
s: String; s: String;
@@ -1709,6 +1724,7 @@ begin
ReadWorksheet(Doc.DocumentElement.FindNode('sheetData'), FWorksheet); ReadWorksheet(Doc.DocumentElement.FindNode('sheetData'), FWorksheet);
ReadMergedCells(Doc.DocumentElement.FindNode('mergeCells'), FWorksheet); ReadMergedCells(Doc.DocumentElement.FindNode('mergeCells'), FWorksheet);
ReadHyperlinks(Doc.DocumentElement.FindNode('hyperlinks')); ReadHyperlinks(Doc.DocumentElement.FindNode('hyperlinks'));
ReadPrintOptions(Doc.DocumentElement.FindNode('printOptions'), FWorksheet);
ReadPageMargins(Doc.DocumentElement.FindNode('pageMargins'), FWorksheet); ReadPageMargins(Doc.DocumentElement.FindNode('pageMargins'), FWorksheet);
FreeAndNil(Doc); FreeAndNil(Doc);
@@ -2309,12 +2325,87 @@ begin
with AWorksheet.PageLayout do with AWorksheet.PageLayout do
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<pageMargins left="%g" right="%g" top="%g" bottom="%g" header="%g" footer="%g" />', [ '<pageMargins left="%g" right="%g" top="%g" bottom="%g" header="%g" footer="%g" />', [
PtsToIn(LeftMargin), PtsToIn(RightMargin), PtsToIn(TopMargin), PtsToIn(BottomMargin), mmToIn(LeftMargin), mmToIn(RightMargin), mmToIn(TopMargin), mmToIn(BottomMargin),
PtsToIn(HeaderDistance), PtsToIn(FooterDistance) ], mmToIn(HeaderMargin), mmToIn(FooterMargin) ],
FPointSeparatorSettings FPointSeparatorSettings
)); ));
end; 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,
'<pageSetup' + s + ' />');
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,
'<printOptions' + s + ' />');
end;
procedure TsSpreadOOXMLWriter.WriteSheetData(AStream: TStream; procedure TsSpreadOOXMLWriter.WriteSheetData(AStream: TStream;
AWorksheet: TsWorksheet); AWorksheet: TsWorksheet);
var var
@@ -2424,6 +2515,21 @@ begin
'</sheetData>'); '</sheetData>');
end; 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 := '<pageSetUpPr' + s + ' />';
if s <> '' then
AppendToStream(AStream,
'<sheetPr>' + s + '</sheetPr>');
end;
procedure TsSpreadOOXMLWriter.WriteSheetViews(AStream: TStream; procedure TsSpreadOOXMLWriter.WriteSheetViews(AStream: TStream;
AWorksheet: TsWorksheet); AWorksheet: TsWorksheet);
var var
@@ -2936,13 +3042,16 @@ begin
AppendToStream(FSSheets[FCurSheetNum], Format( AppendToStream(FSSheets[FCurSheetNum], Format(
'<worksheet xmlns="%s" xmlns:r="%s">', [SCHEMAS_SPREADML, SCHEMAS_DOC_RELS])); '<worksheet xmlns="%s" xmlns:r="%s">', [SCHEMAS_SPREADML, SCHEMAS_DOC_RELS]));
WriteSheetPr(FSSheets[FCurSheetNum], AWorksheet);
WriteDimension(FSSheets[FCurSheetNum], AWorksheet); WriteDimension(FSSheets[FCurSheetNum], AWorksheet);
WriteSheetViews(FSSheets[FCurSheetNum], AWorksheet); WriteSheetViews(FSSheets[FCurSheetNum], AWorksheet);
WriteCols(FSSheets[FCurSheetNum], AWorksheet); WriteCols(FSSheets[FCurSheetNum], AWorksheet);
WriteSheetData(FSSheets[FCurSheetNum], AWorksheet); WriteSheetData(FSSheets[FCurSheetNum], AWorksheet);
WriteHyperlinks(FSSheets[FCurSheetNum], AWorksheet); WriteHyperlinks(FSSheets[FCurSheetNum], AWorksheet);
WriteMergedCells(FSSheets[FCurSheetNum], AWorksheet); WriteMergedCells(FSSheets[FCurSheetNum], AWorksheet);
WritePrintOptions(FSSheets[FCurSheetNum], AWorksheet);
WritePageMargins(FSSheets[FCurSheetNum], AWorksheet); WritePageMargins(FSSheets[FCurSheetNum], AWorksheet);
WritePageSetup(FSSheets[FCurSheetNum], AWorksheet);
// Footer // Footer
if AWorksheet.Comments.Count > 0 then if AWorksheet.Comments.Count > 0 then