diff --git a/components/fpspreadsheet/examples/excel8demo/excel8write.lpi b/components/fpspreadsheet/examples/excel8demo/excel8write.lpi index d7de14f65..c7d897b8e 100644 --- a/components/fpspreadsheet/examples/excel8demo/excel8write.lpi +++ b/components/fpspreadsheet/examples/excel8demo/excel8write.lpi @@ -15,8 +15,71 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -59,5 +122,8 @@ + + + diff --git a/components/fpspreadsheet/fpspreadsheet.chm b/components/fpspreadsheet/fpspreadsheet.chm index 5ee46482e..c02d08c1b 100755 Binary files a/components/fpspreadsheet/fpspreadsheet.chm and b/components/fpspreadsheet/fpspreadsheet.chm differ diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index d8f902b76..a8b4739ed 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -437,9 +437,8 @@ type @param soShowHeaders Show or hide the column or row headers of the spreadsheet @param soHasFrozenPanes If set a number of rows and columns of the spreadsheet is fixed and does not scroll. The number is defined by - LeftPaneWidth and TopPaneHeight. - @param soSelected (currently not used) } - TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes, soSelected); + LeftPaneWidth and TopPaneHeight. } + TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes); {@@ Set of user interface options @ see TsSheetOption } @@ -1083,15 +1082,15 @@ type const FEProps: array[TFEKind] of TFEProp = ( { Operands } - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCell - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellRef - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellRange - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellNum - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellInteger - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellString - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellBool - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellErr - (Symbol:''; MinParams:-1; MaxParams:Byte(-1)), // fekCellMissingArg + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCell + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellRef + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellRange + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellNum + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellInteger + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellString + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellBool + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellErr + (Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1)), // fekCellMissingArg { Basic operations } (Symbol:'+'; MinParams:2; MaxParams:2), // fekAdd (Symbol:'-'; MinParams:2; MaxParams:2), // fekSub @@ -1278,14 +1277,10 @@ procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer); var i: Integer; begin + {$PUSH}{$R-} for i := 0 to APaletteSize-1 do - {$IFDEF RNGCHECK} - {$R-} - {$ENDIF} APalette^[i] := LongRGBToExcelPhysical(APalette^[i]) - {$IFDEF RNGCHECK} - {$R+} - {$ENDIF} + {$POP} end; {@@ @@ -3754,8 +3749,8 @@ end; It is added to the end of the list of worksheets @param AName The name of the new worksheet - @return The instace of the newly created worksheet - @see TsWorkbook + @return The instance of the newly created worksheet + @see TsWorksheet } function TsWorkbook.AddWorksheet(AName: string): TsWorksheet; begin @@ -3849,7 +3844,29 @@ procedure TsWorkbook.RemoveAllWorksheets; begin FWorksheets.ForEachCall(RemoveWorksheetsCallback, nil); end; + (* +{@@ + Sets the selected flag for the sheet with the given index. + Excel requires one sheet to be selected, otherwise strange things happen when + the file is loaded into Excel (cannot print, hanging instance of Excel - see + bug 0026386). + @param AIndex Index of the worksheet to be selected +} +procedure TsWorkbook.SelectWorksheet(AIndex: Integer); +var + i: Integer; + sheet: TsWorksheet; +begin + for i:=0 to FWorksheets.Count-1 do begin + sheet := TsWorksheet(FWorksheets.Items[i]); + if i = AIndex then + sheet.Options := sheet.Options + [soSelected] + else + sheet.Options := sheet.Options - [soSelected]; + end; +end; + *) { Font handling } diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index a13dc859d..b95223eaa 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -28,9 +28,8 @@ type { TsCustomWorksheetGrid } {@@ - TsCustomWorksheetGrid is a grid which displays spreadsheet data along with - their formatting. Being linked to an instance of TsWorkbook it provides - methods for reading data from or writing to spreadsheet files. + TsCustomWorksheetGrid is the ancestor of TsWorkseetGrid and is able to + display spreadsheet data along with their formatting. } TsCustomWorksheetGrid = class(TCustomDrawGrid) private @@ -288,8 +287,8 @@ type {@@ TsWorksheetGrid is a grid which displays spreadsheet data along with formatting. As it is linked to an instance of TsWorkbook, it provides - methods for reading data from or writing to spreadsheet files. In contrast - to TsCustomWorksheetGrid it has all properties published. + methods for reading data from or writing to spreadsheet files. It has the + same funtionality as TsCustomWorksheetGrid, but publishes has all properties. } TsWorksheetGrid = class(TsCustomWorksheetGrid) published @@ -853,7 +852,8 @@ begin if ShowHeaders and ((ACol = 0) or (ARow = 0)) then Canvas.Brush.Color := FixedColor end; - if FWorksheet <> nil then begin + if (FWorksheet <> nil) and (ARow >= FHeaderCount) and (ACol >= FHeaderCount) + then begin r := ARow - FHeaderCount; c := ACol - FHeaderCount; lCell := FWorksheet.FindCell(r, c); @@ -1150,12 +1150,15 @@ var txtLeft, txtRight: String; justif: Byte; begin - if FWorksheet = nil then + if (FWorksheet = nil) then exit; c := ACol - FHeaderCount; r := ARow - FHeaderCount; - lCell := FWorksheet.FindCell(r, c); + if (r >= 0) and (c >= 0) then + lCell := FWorksheet.FindCell(r, c) + else + lCell := nil; // Header if lCell = nil then begin @@ -2887,7 +2890,7 @@ end; If the file format is not known is is written as BIFF8/XLS. @param AOverwriteExisting If this file already exists it is overwritten if AOverwriteExisting = true, or an exception is raised - if AOverwriteExisting = false: + if AOverwriteExisting = false. } procedure TsCustomWorksheetGrid.SaveToSpreadsheetFile(AFileName: String; AOverwriteExisting: Boolean = true); diff --git a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas index 404bfde36..db66d2d19 100644 --- a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas +++ b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas @@ -86,6 +86,7 @@ type procedure ShowRow; procedure ShowSelection; procedure ShowSheet; + procedure ShowSheetPR; procedure ShowSST; procedure ShowString; procedure ShowStyle; @@ -326,6 +327,8 @@ begin ShowRecalc; $007D: ShowColInfo; + $0081: + ShowSheetPR; $0085: ShowSheet; $0086: @@ -3233,6 +3236,62 @@ begin end; +procedure TBIFFGrid.ShowSheetPR; +var + numBytes: Integer; + w: Word; +begin + RowCount := FixedRows + 1; + + numBytes := 2; + Move(FBuffer[FBufferIndex], w, numBytes); + w := WordLEToN(w); + if Row = FCurrRow then begin + FDetails.Add('Option flags:'#13); + if w and $0001 = 0 + then FDetails.Add('Bit $0001 = 0: Do not show automatic page breaks') + else FDetails.Add('Bit $0001 = 1: Show automatic page breaks'); + if w and $0010 = 0 + then FDetails.Add('Bit $0010 = 0: Standard sheet') + else FDetails.Add('Bit $0010 = 1: Dialog sheet (BIFF5-BIFF8)'); + if w and $0020 = 0 + then FDetails.Add('Bit $0020 = 0: No automatic styles in outlines') + else FDetails.Add('Bit $0020 = 1: Apply automatic styles to outlines'); + if w and $0040 = 0 + then FDetails.Add('Bit $0040 = 0: Outline buttons above outline group') + else FDetails.Add('Bit $0040 = 1: Outline buttons below outline group'); + if w and $0080 = 0 + then FDetails.Add('Bit $0080 = 0: Outline buttons left of outline group') + else FDetails.Add('Bit $0080 = 1: Outline buttons right of outline group'); + if w and $0100 = 0 + then FDetails.Add('Bit $0100 = 0: Scale printout in percent') + else FDetails.Add('Bit $0100 = 1: Fit printout to number of pages'); + if w and $0200 = 0 + then FDetails.Add('Bit $0200 = 0: Save external linked values (BIFF3-BIFF4 only)') + else FDetails.Add('Bit $0200 = 1: Do NOT save external linked values (BIFF3-BIFF4 only)'); + if w and $0400 = 0 + then FDetails.Add('Bit $0400 = 0: Do not show row outline symbols') + else FDetails.Add('Bit $0400 = 1: Show row outline symbols'); + if w and $0800 = 0 + then FDetails.Add('Bit $0800 = 0: Do not show column outline symbols') + else FDetails.Add('Bit $0800 = 1: Show column outline symbols'); + case (w and $3000) shr 12 of + 0: FDetails.Add('Bits $3000 = $0000: Arrange windows tiled'); + 1: FDetails.Add('Bits $3000 = $1000: Arrange windows horizontal'); + 2: FDetails.Add('Bits $3000 = $2000: Arrange windows vertical'); + 3: FDetails.Add('Bits $3000 = $3000: Arrange windows cascaded'); + end; + if w and $4000 = 0 + then FDetails.Add('Bits $4000 = 0: Excel like expression evaluation (BIFF4-BIFF8 only)') + else FDetails.Add('Bits $4000 = 1: Lotus like expression evaluation (BIFF4-BIFF8 only)'); + if w and $8000 = 0 + then FDetails.Add('Bits $8000 = 0: Excel like formula editing (BIFF4-BIFF8 only)') + else FDetails.Add('Bits $8000 = 1: Lotus like formula editing (BIFF4-BIFF8 only)'); + end; + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x (%d)', [w, w]), + 'Option flags'); +end; + procedure TBIFFGrid.ShowSST; var numBytes: Integer; diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index 5052664bb..39a51d640 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -961,6 +961,7 @@ end; procedure TsSpreadBIFF2Writer.WriteToStream(AStream: TStream); var sheet: TsWorksheet; + pane: Byte; begin sheet := Workbook.GetFirstWorksheet; @@ -976,7 +977,7 @@ begin WriteWindow1(AStream); // { -- currently not working WriteWindow2(AStream, sheet); - WritePane(AStream, sheet, false); // false for "is not BIFF5 or BIFF8" + WritePane(AStream, sheet, false, pane); // false for "is not BIFF5 or BIFF8" WriteSelections(AStream, sheet); //} WriteEOF(AStream); diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 450dc7b71..229443663 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -361,6 +361,7 @@ var Boundsheets: array of Int64; i, len: Integer; sheet : TsWorksheet; + pane: Byte; begin { Store some data about the workbook that other routines need } WorkBookEncoding := Workbook.Encoding; @@ -383,7 +384,7 @@ begin begin len := Length(Boundsheets); SetLength(Boundsheets, len + 1); - Boundsheets[len] := WriteBoundsheet(AStream, UTF8ToAnsi(Workbook.GetWorksheetByIndex(i).Name)); + Boundsheets[len] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i).Name); // BIFF8 does not support unicode --> Need UTF8ToAnsi ! end; @@ -404,10 +405,12 @@ begin WriteBOF(AStream, INT_BOF_SHEET); WriteIndex(AStream); +// WritePageSetup(AStream); WriteColInfos(AStream, sheet); WriteDimensions(AStream, sheet); WriteWindow2(AStream, sheet); - WritePane(AStream, sheet, true); // true for "is BIFF5 or BIFF8" + WritePane(AStream, sheet, true, pane); // true for "is BIFF5 or BIFF8" + WriteSelection(AStream, sheet, pane); WriteRows(AStream, sheet); WriteCellsToStream(AStream, sheet.Cells); WriteEOF(AStream); @@ -985,7 +988,9 @@ begin MASK_WINDOW2_OPTION_SHOW_ZERO_VALUES or MASK_WINDOW2_OPTION_AUTO_GRIDLINE_COLOR or MASK_WINDOW2_OPTION_SHOW_OUTLINE_SYMBOLS or + MASK_WINDOW2_OPTION_SHEET_SELECTED or MASK_WINDOW2_OPTION_SHEET_ACTIVE; + { Bug 0026386 -> every sheet must be selected/active, otherwise Excel cannot print } if (soShowGridLines in ASheet.Options) then Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES; @@ -993,8 +998,6 @@ begin Options := Options or MASK_WINDOW2_OPTION_SHOW_SHEET_HEADERS; if (soHasFrozenPanes in ASheet.Options) and ((ASheet.LeftPaneWidth > 0) or (ASheet.TopPaneHeight > 0)) then Options := Options or MASK_WINDOW2_OPTION_PANES_ARE_FROZEN; - if (soSelected in ASheet.Options) then - Options := Options or MASK_WINDOW2_OPTION_SHEET_SELECTED; AStream.WriteWord(WordToLE(Options)); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 97c39253a..48f9b065e 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -395,6 +395,7 @@ var Boundsheets: array of Int64; sheet: TsWorksheet; i, len: Integer; + pane: Byte; begin { Write workbook globals } @@ -433,6 +434,8 @@ begin WriteBOF(AStream, INT_BOF_SHEET); WriteIndex(AStream); + //WriteSheetPR(AStream); +// WritePageSetup(AStream); WriteColInfos(AStream, sheet); WriteDimensions(AStream, sheet); //WriteRowAndCellBlock(AStream, sheet); @@ -441,7 +444,8 @@ begin WriteCellsToStream(AStream, sheet.Cells); WriteWindow2(AStream, sheet); - WritePane(AStream, sheet, isBIFF8); + WritePane(AStream, sheet, isBIFF8, pane); + WriteSelection(AStream, sheet, pane); WriteEOF(AStream); end; @@ -1101,7 +1105,9 @@ begin MASK_WINDOW2_OPTION_SHOW_ZERO_VALUES or MASK_WINDOW2_OPTION_AUTO_GRIDLINE_COLOR or MASK_WINDOW2_OPTION_SHOW_OUTLINE_SYMBOLS or + MASK_WINDOW2_OPTION_SHEET_SELECTED or MASK_WINDOW2_OPTION_SHEET_ACTIVE; + { Bug 0026386 -> every sheet must be selected/active, otherwise Excel cannot print } if (soShowGridLines in ASheet.Options) then Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES; @@ -1109,9 +1115,6 @@ begin Options := Options or MASK_WINDOW2_OPTION_SHOW_SHEET_HEADERS; if (soHasFrozenPanes in ASheet.Options) and ((ASheet.LeftPaneWidth > 0) or (ASheet.TopPaneHeight > 0)) then Options := Options or MASK_WINDOW2_OPTION_PANES_ARE_FROZEN; - if (soSelected in ASheet.Options) then - Options := Options or MASK_WINDOW2_OPTION_SHEET_SELECTED; - AStream.WriteWord(WordToLE(Options)); { Index to first visible row } diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index f1a96195e..5d77e0da6 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -30,6 +30,7 @@ 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_COUNTRY = $008C; // does not exist in BIFF2 INT_EXCEL_ID_PALETTE = $0092; // does not exist in BIFF2 INT_EXCEL_ID_DIMENSIONS = $0200; // BIFF2: $0000 @@ -44,6 +45,7 @@ const INT_EXCEL_ID_STYLE = $0293; // does not exist in BIFF2 { RECORD IDs which did not change across version 4-8 } + INT_EXCEL_ID_PAGESETUP = $00A1; // does not exist before BIFF4 INT_EXCEL_ID_FORMAT = $041E; // BIFF2-3: $001E { RECORD IDs which did not change across versions 5-8 } @@ -468,10 +470,12 @@ type // Writes out a floating point NUMBER record procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: Double; ACell: PCell); override; + procedure WritePageSetup(AStream: TStream); // Writes out a PALETTE record containing all colors defined in the workbook procedure WritePalette(AStream: TStream); // Writes out a PANE record - procedure WritePane(AStream: TStream; ASheet: TsWorksheet; IsBiff58: Boolean); + procedure WritePane(AStream: TStream; ASheet: TsWorksheet; IsBiff58: Boolean; + out ActivePane: Byte); // Writes out a ROW record procedure WriteRow(AStream: TStream; ASheet: TsWorksheet; ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); virtual; @@ -480,6 +484,7 @@ type // Writes out a SELECTION record procedure WriteSelection(AStream: TStream; ASheet: TsWorksheet; APane: Byte); procedure WriteSelections(AStream: TStream; ASheet: TsWorksheet); + procedure WriteSheetPR(AStream: TStream); // Writes out a WINDOW1 record procedure WriteWindow1(AStream: TStream); virtual; // Writes the index of the XF record used in the given cell @@ -1573,11 +1578,6 @@ begin else FWorksheet.Options := FWorksheet.Options - [soShowHeaders]; - if (flags and MASK_WINDOW2_OPTION_SHEET_SELECTED <> 0) then - FWorksheet.Options := FWorksheet.Options + [soSelected] - else - FWorksheet.Options := FWorksheet.Options - [soSelected]; - if (flags and MASK_WINDOW2_OPTION_PANES_ARE_FROZEN <> 0) then FWorksheet.Options := FWorksheet.Options + [soHasFrozenPanes] else @@ -1848,15 +1848,62 @@ begin AStream.WriteDWord(DWordToLE($FFFFFF)); end; +{@@ + Writes a PAGESETUP record containing information on printing +} +procedure TsSpreadBIFFWriter.WritePageSetup(AStream: TStream); +var + flags: Word; + dbl: Double; +begin + { BIFF record header } + AStream.WriteWord(WordToLE(INT_EXCEL_ID_PAGESETUP)); + AStream.WriteWord(WordToLE(9*2 + 2*8)); + + { Paper size } + AStream.WriteWord(WordToLE(0)); // 1 = Letter, 9 = A4 + + { Scaling factor in percent } + AStream.WriteWord(WordToLE(100)); // 100 % + + { Start page number } + AStream.WriteWord(WordToLE(1)); // starting at page 1 + + { Fit worksheet width to this number of pages, 0 = use as many as needed } + AStream.WriteWord(WordToLE(0)); + + { Fit worksheet height to this number of pages, 0 = use as many as needed } + AStream.WriteWord(WordToLE(0)); + + flags := 0; + AStream.WriteWord(WordToLE(0)); + + { Print resolution in dpi } + AStream.WriteWord(WordToLE(600)); + + { Vertical print resolution in dpi } + AStream.WriteWord(WordToLE(600)); + + { Header margin } + dbl := 0.5; + AStream.WriteBuffer(dbl, SizeOf(dbl)); + { Footer margin } + AStream.WriteBuffer(dbl, SizeOf(dbl)); + + { Number of copies to print } + AStream.WriteWord(WordToLE(1)); // 1 copy +end; + { Writes a PANE record to the stream. Valid for all BIFF versions. The difference for BIFF5-BIFF8 is a non-used byte at the end. Activate IsBiff58 in these cases. } procedure TsSpreadBIFFWriter.WritePane(AStream: TStream; ASheet: TsWorksheet; - IsBiff58: Boolean); + IsBiff58: Boolean; out ActivePane: Byte); var n: Word; - active_pane: Byte; begin + ActivePane := 3; + if not (soHasFrozenPanes in ASheet.Options) then exit; if (ASheet.LeftPaneWidth = 0) and (ASheet.TopPaneHeight = 0) then @@ -1901,18 +1948,18 @@ begin 3 = left-top } if (soHasFrozenPanes in ASheet.Options) then begin if (ASheet.LeftPaneWidth = 0) and (ASheet.TopPaneHeight = 0) then - active_pane := 3 + ActivePane := 3 else if (ASheet.LeftPaneWidth = 0) then - active_pane := 2 + ActivePane := 2 else if (ASheet.TopPaneHeight =0) then - active_pane := 1 + ActivePane := 1 else - active_pane := 0; + ActivePane := 0; end else - active_pane := 0; - AStream.WriteByte(active_pane); + ActivePane := 0; + AStream.WriteByte(ActivePane); if IsBIFF58 then AStream.WriteByte(0); @@ -2080,6 +2127,20 @@ begin end; end; +{ Writes a SHEETPR Record. + Valid for BIFF3-BIFF8. } +procedure TsSpreadBIFFWriter.WriteSheetPR(AStream: TStream); +var + flags: Word; +begin + { BIFF Record header } + AStream.WriteWord(WordToLE(INT_EXCEL_ID_SHEETPR)); + AStream.WriteWord(WordToLE(2)); + + flags := $04C1; + AStream.WriteWord(WordToLE(flags)); +end; + { Writes an Excel 5/8 WINDOW1 record This record contains general settings for the document window and global workbook settings.