From 6a6f290fda3341fd9be16b266751b488da854235 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Mon, 3 Aug 2015 19:04:40 +0000 Subject: [PATCH] fpspreadsheet: Read/write name of active worksheet (biff5, biff8, xlsx, ods, visual controls) git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4240 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpsopendocument.pas | 52 +++++++++---------- components/fpspreadsheet/fpspreadsheet.pas | 7 ++- .../fpspreadsheet/fpspreadsheetctrls.pas | 42 ++++++++++++--- .../fpspreadsheet/fpspreadsheetgrid.pas | 6 ++- components/fpspreadsheet/xlsbiff5.pas | 13 +++-- components/fpspreadsheet/xlsbiff8.pas | 14 +++-- components/fpspreadsheet/xlscommon.pas | 3 ++ components/fpspreadsheet/xlsxooxml.pas | 34 +++++++++++- 8 files changed, 125 insertions(+), 46 deletions(-) diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index c9c55f4f8..94b842b62 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -89,6 +89,7 @@ type FPageLayoutList: TFPList; FMasterPageList: TFPList; FHeaderFooterFontList: TObjectList; + FActiveSheet: String; FDateMode: TDateMode; // Applies internally stored column widths to current worksheet procedure ApplyColWidths; @@ -1865,6 +1866,7 @@ var OfficeSettingsNode: TDOMNode; nodename: String; pageLayout: PsPageLayout; + sheet: TsWorksheet; begin //unzip files into AFileName path FilePath := GetTempDir(false); @@ -1958,6 +1960,12 @@ begin ReadSettings(OfficeSettingsNode); end; + // Active sheet + if FActiveSheet <> '' then + sheet := FWorkbook.GetWorksheetByName(FActiveSheet) else + sheet := FWorkbook.GetWorksheetByIndex(0); + FWorkbook.SelectWorksheet(sheet); + finally if Assigned(Doc) then Doc.Free; end; @@ -1966,32 +1974,14 @@ end; procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream); var Doc : TXMLDocument; -// FilePath : string; -// UnZip : TUnZipper; -// FileList : TStringList; BodyNode, SpreadSheetNode, TableNode: TDOMNode; StylesNode: TDOMNode; OfficeSettingsNode: TDOMNode; nodename: String; pageLayout: PsPageLayout; XMLStream: TStream; + sheet: TsWorksheet; begin - { - //unzip files into AFileName path - FilePath := GetTempDir(false); - UnZip := TUnZipper.Create; - FileList := TStringList.Create; - try - FileList.Add('styles.xml'); - FileList.Add('content.xml'); - FileList.Add('settings.xml'); - UnZip.OutputPath := FilePath; - Unzip.UnZipFiles(AFileName,FileList); - finally - FreeAndNil(FileList); - FreeAndNil(UnZip); - end; //try - } Doc := nil; try // process the styles.xml file @@ -2079,17 +2069,17 @@ begin XMLStream.Free; end; + // Active sheet + if FActiveSheet <> '' then + sheet := FWorkbook.GetWorksheetByName(FActiveSheet) else + sheet := FWorkbook.GetWorksheetByIndex(0); + FWorkbook.SelectWorksheet(sheet); + finally FreeAndNil(Doc); end; end; -{ -begin - Unused(AStream); - raise Exception.Create('[TsSpreadOpenDocReader.ReadFromStream] '+ - 'Method not implemented. Use "ReadFromFile" instead.'); -end; - } + procedure TsSpreadOpenDocReader.ReadHeaderFooterFont(ANode: TDOMNode; var AFontName: String; var AFontSize: Double; var AFontStyle: TsHeaderFooterFontStyles; var AFontColor: TsColor); @@ -2997,6 +2987,11 @@ begin if (nodeName = 'config:config-item') then begin cfgName := lowercase(GetAttrValue(cfgEntryItemNode, 'config:name')); + if cfgName = 'activetable' then + begin + cfgValue := GetNodeValue(cfgEntryItemNode); + FActiveSheet := cfgValue; + end else if cfgName = 'showgrid' then begin cfgValue := GetNodeValue(cfgEntryItemNode); @@ -3734,15 +3729,18 @@ var i: Integer; showGrid, showHeaders: Boolean; sheet: TsWorksheet; + actSheet: String; begin // Open/LibreOffice allow to change showGrid and showHeaders only globally. // As a compromise, we check whether there is at least one page with these // settings off. Then we assume it to be valid also for the other sheets. showGrid := true; showHeaders := true; + actSheet := 'Table1'; for i:=0 to Workbook.GetWorksheetCount-1 do begin sheet := Workbook.GetWorksheetByIndex(i); + if sheet = Workbook.ActiveWorksheet then actSheet := sheet.Name; if not (soShowGridLines in sheet.Options) then showGrid := false; if not (soShowHeaders in sheet.Options) then showHeaders := false; end; @@ -3758,7 +3756,7 @@ begin '' + '' + '' + - 'Tabelle1' + + ''+actSheet+'' + '100' + '100' + 'false' + diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index d72d613c0..e94686586 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -735,7 +735,7 @@ type procedure ClearErrorList; {@@ Identifies the "active" worksheet (only for visual controls)} - property ActiveWorksheet: TsWorksheet read FActiveWorksheet; + property ActiveWorksheet: TsWorksheet read FActiveWorksheet write SelectWorksheet; {@@ Retrieves error messages collected during reading/writing } property ErrorMsg: String read GetErrorMsg; {@@ Filename of the saved workbook } @@ -7110,7 +7110,10 @@ begin if (AWorksheet <> nil) and (FWorksheets.IndexOf(AWorksheet) = -1) then raise Exception.Create('[TsWorkbook.SelectSheet] Worksheet does not belong to the workbook'); FActiveWorksheet := AWorksheet; - if Assigned(FOnSelectWorksheet) then FOnSelectWorksheet(self, AWorksheet); + if FReadWriteFlag = rwfRead then + exit; + if Assigned(FOnSelectWorksheet) then + FOnSelectWorksheet(self, AWorksheet); end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index 13baa9829..0da168407 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -76,7 +76,7 @@ type procedure CellSelectedHandler(Sender: TObject; ARow, ACol: Cardinal); procedure InternalCreateNewWorkbook; procedure InternalLoadFromFile(AFileName: string; AAutoDetect: Boolean; - AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); + AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); procedure SetFileName(const AFileName: TFileName); procedure SetOptions(AValue: TsWorkbookOptions); // procedure WorkbookChangedPaletteHandler(Sender: TObject); @@ -105,9 +105,9 @@ type procedure CreateNewWorkbook; procedure LoadFromSpreadsheetFile(AFileName: string; - AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); overload; + AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); overload; procedure LoadFromSpreadsheetFile(AFileName: string; - AWorksheetIndex: Integer = 0); overload; + AWorksheetIndex: Integer = -1); overload; procedure SaveToSpreadsheetFile(AFileName: string; AOverwriteExisting: Boolean = true); overload; @@ -835,7 +835,7 @@ end; @param AWorksheetIndex Index of the worksheet to be selected after loading. -------------------------------------------------------------------------------} procedure TsWorkbookSource.InternalLoadFromFile(AFileName: string; - AAutoDetect: Boolean; AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); + AAutoDetect: Boolean; AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); begin // Create a new empty workbook InternalCreateNewWorkbook; @@ -851,6 +851,12 @@ begin EnableControls; end; + if AWorksheetIndex = -1 then + begin + if FWorkbook.ActiveWorksheet <> nil then + AWorksheetIndex := FWorkbook.GetWorksheetIndex(FWorkbook.ActiveWorksheet) else + AWorksheetIndex := 0; + end; SelectWorksheet(FWorkbook.GetWorkSheetByIndex(AWorksheetIndex)); // If required, display loading error message @@ -879,9 +885,10 @@ end; @param AFilename Name of the spreadsheet file to be loaded @param AFormat Spreadsheet file format assumed for the file @param AWorksheetIndex Index of the worksheet to be selected after loading. + (If empty then the active worksheet is loaded) -------------------------------------------------------------------------------} procedure TsWorkbookSource.LoadFromSpreadsheetFile(AFileName: string; - AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); + AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); begin InternalLoadFromFile(AFileName, false, AFormat, AWorksheetIndex); end; @@ -895,9 +902,10 @@ end; @param AFilename Name of the spreadsheet file to be loaded @param AWorksheetIndex Index of the worksheet to be selected after loading. + (If empty then the active worksheet is loaded) -------------------------------------------------------------------------------} procedure TsWorkbookSource.LoadFromSpreadsheetFile(AFileName: string; - AWorksheetIndex: Integer = 0); + AWorksheetIndex: Integer = -1); const sfNotNeeded = sfExcel8; // The parameter AFormat if InternalLoadFromFile is not needed here, @@ -924,6 +932,17 @@ var I: IsSpreadsheetControl; C: TComponent; begin + { + // Select worksheet in tab control first + if lniWorksheet in AChangedItems then + for j:=0 to FListeners.Count-1 do begin + C := TComponent(FListeners[j]); + if C is TsWorkbookTabControl then begin + C.GetInterface(GUID_SpreadsheetControl, I); + I.ListenerNotification(AChangedItems, AData); + end; + end; + } for j:=0 to FListeners.Count-1 do begin C := TComponent(FListeners[j]); if C.GetInterface(GUID_SpreadsheetControl, I) then @@ -1275,7 +1294,9 @@ procedure TsWorkbookSource.WorkbookOpenedHandler(Sender: TObject); begin Unused(Sender); NotifyListeners([lniWorkbook]); - SelectWorksheet(FWorkbook.GetFirstWorksheet); + if FWorkbook.ActiveWorksheet = nil then + SelectWorksheet(FWorkbook.GetFirstWorksheet) else + SelectWorksheet(FWorkbook.ActiveWorksheet); end; {@@ ---------------------------------------------------------------------------- @@ -1478,9 +1499,16 @@ begin begin inc(FLockCount); // avoid WorkbookSelect message when adding each tab GetSheetList(Tabs); + { if (lniWorkbook in AChangedItems) then TabIndex := 0 else + } + if (lniWorkbook in AChangedItems) and (Workbook <> nil) then + begin + i := Workbook.GetWorksheetIndex(Workbook.ActiveWorksheet); + if i > -1 then TabIndex := i else TabIndex := 0 + end else if (lniWorksheetAdd in AChangedItems) then TabIndex := Tabs.Count-1 else diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index 1550650ba..cdd7e1a48 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -237,9 +237,9 @@ type procedure InsertCol(AGridCol: Integer); procedure InsertRow(AGridRow: Integer); procedure LoadFromSpreadsheetFile(AFileName: string; - AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); overload; + AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = -1); overload; procedure LoadFromSpreadsheetFile(AFileName: string; - AWorksheetIndex: Integer = 0); overload; + AWorksheetIndex: Integer = -1); overload; procedure NewWorkbook(AColCount, ARowCount: Integer); procedure SaveToSpreadsheetFile(AFileName: string; AOverwriteExisting: Boolean = true); overload; @@ -3433,6 +3433,7 @@ end; @param AFileName Name of the file to be loaded @param AFormat Spreadsheet file format assumed for the file @param AWorksheetIndex Index of the worksheet to be displayed in the grid + (If empty then the active worksheet is loaded) -------------------------------------------------------------------------------} procedure TsCustomWorksheetGrid.LoadFromSpreadsheetFile(AFileName: string; AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer); @@ -3461,6 +3462,7 @@ end; @param AFileName Name of the file to be loaded @param AWorksheetIndex Index of the worksheet to be shown in the grid + (If empty then the active worksheet is loaded) -------------------------------------------------------------------------------} procedure TsCustomWorksheetGrid.LoadFromSpreadsheetFile(AFileName: string; AWorksheetIndex: Integer); diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 63abb497f..853980582 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -1605,6 +1605,7 @@ procedure TsSpreadBIFF5Writer.WriteWindow2(AStream: TStream; ASheet: TsWorksheet); var Options: Word; + actSheet: TsWorksheet; begin { BIFF Record header } WriteBiffHeader(AStream, INT_EXCEL_ID_WINDOW2, 10); @@ -1613,10 +1614,11 @@ begin Options := MASK_WINDOW2_OPTION_SHOW_ZERO_VALUES or MASK_WINDOW2_OPTION_AUTO_GRIDLINE_COLOR or - MASK_WINDOW2_OPTION_SHOW_OUTLINE_SYMBOLS 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 } + MASK_WINDOW2_OPTION_SHEET_ACTIVE; } + { Bug 0026386 -> every sheet must be selected/active, otherwise Excel cannot print + ---> wp: after changes for issue 0028452: this is not necessary any more. } if (soShowGridLines in ASheet.Options) then Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES; @@ -1624,6 +1626,11 @@ 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 FWorkbook.ActiveWorksheet <> nil then + actSheet := FWorkbook.ActiveWorksheet else + actSheet := Fworkbook.GetWorksheetByIndex(0); + if (ASheet = actSheet) then + Options := Options or MASK_WINDOW2_OPTION_SHEET_ACTIVE or MASK_WINDOW2_OPTION_SHEET_SELECTED; AStream.WriteWord(WordToLE(Options)); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index b0f4886e4..b8f794a3c 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -3147,6 +3147,7 @@ procedure TsSpreadBIFF8Writer.WriteWINDOW2(AStream: TStream; ASheet: TsWorksheet); var Options: Word; + actSheet: TsWorksheet; begin { BIFF Record header } WriteBiffHeader(AStream, INT_EXCEL_ID_WINDOW2, 18); @@ -3155,10 +3156,12 @@ begin Options := MASK_WINDOW2_OPTION_SHOW_ZERO_VALUES or MASK_WINDOW2_OPTION_AUTO_GRIDLINE_COLOR or - MASK_WINDOW2_OPTION_SHOW_OUTLINE_SYMBOLS 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 } + MASK_WINDOW2_OPTION_SHEET_ACTIVE;} + { Bug 0026386 -> every sheet must be selected/active, otherwise Excel cannot print + ---> wp: after changes for issue 0028452: this is not necessary any more. } if (soShowGridLines in ASheet.Options) then Options := Options or MASK_WINDOW2_OPTION_SHOW_GRID_LINES; @@ -3166,6 +3169,11 @@ 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 FWorkbook.ActiveWorksheet <> nil then + actSheet := FWorkbook.ActiveWorksheet else + actSheet := Fworkbook.GetWorksheetByIndex(0); + if (ASheet = actSheet) then + Options := Options or MASK_WINDOW2_OPTION_SHEET_ACTIVE 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 4ce4ec9d5..45a2bfd55 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -2280,6 +2280,9 @@ begin FWorksheet.Options := FWorksheet.Options + [soHasFrozenPanes] else FWorksheet.Options := FWorksheet.Options - [soHasFrozenPanes]; + + if (flags and MASK_WINDOW2_OPTION_SHEET_ACTIVE <> 0) then + FWorkbook.SelectWorksheet(FWorksheet); end; { Reads the workbook globals. } diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index b862f6875..ed635edd0 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -65,6 +65,7 @@ type procedure ApplyCellFormatting(ACell: PCell; XfIndex: Integer); procedure ApplyHyperlinks(AWorksheet: TsWorksheet); function FindCommentsFileName(ANode: TDOMNode): String; + procedure ReadActiveSheet(ANode: TDOMNode; out ActiveSheetIndex: Integer); procedure ReadBorders(ANode: TDOMNode); procedure ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadCellXfs(ANode: TDOMNode); @@ -421,6 +422,20 @@ begin Result := ''; end; +procedure TsSpreadOOXMLReader.ReadActiveSheet(ANode: TDOMNode; + out ActiveSheetIndex: Integer); +var + S: string; + i: Integer; +begin + ActiveSheetIndex := -1; + if ANode = nil then + Exit; + S := GetAttrValue(ANode.FindNode('workbookView'), 'activeTab'); + if TryStrToInt(S, i) then + ActiveSheetIndex := i; +end; + procedure TsSpreadOOXMLReader.ReadBorders(ANode: TDOMNode); function ReadBorderStyle(ANode: TDOMNode; @@ -1883,7 +1898,7 @@ var i: Integer; fn: String; fn_comments: String; - XMLStream: TStream; + actSheetIndex: Integer; begin //unzip "content.xml" of "AFileName" to folder "FilePath" FilePath := GetTempDir(false); @@ -1920,6 +1935,7 @@ begin ReadFileVersion(Doc.DocumentElement.FindNode('fileVersion')); ReadDateMode(Doc.DocumentElement.FindNode('workbookPr')); ReadSheetList(Doc.DocumentElement.FindNode('sheets'), SheetList); + ReadActiveSheet(Doc.DocumentElement.FindNode('bookViews'), actSheetIndex); FreeAndNil(Doc); // process the styles.xml file @@ -2004,6 +2020,10 @@ begin end; // Add hyperlinks to cells ApplyHyperlinks(FWorksheet); + + // Active worksheet + if i = actSheetIndex then + FWorkbook.SelectWorksheet(FWorksheet); end; // for finally @@ -2021,6 +2041,7 @@ var fn: String; fn_comments: String; XMLStream: TStream; + actSheetIndex: Integer; begin Doc := nil; SheetList := TStringList.Create; @@ -2047,6 +2068,7 @@ begin ReadFileVersion(Doc.DocumentElement.FindNode('fileVersion')); ReadDateMode(Doc.DocumentElement.FindNode('workbookPr')); ReadSheetList(Doc.DocumentElement.FindNode('sheets'), SheetList); + ReadActiveSheet(Doc.DocumentElement.FindNode('bookViews'), actSheetIndex); FreeAndNil(Doc); finally XMLStream.Free; @@ -2163,6 +2185,10 @@ begin // Add hyperlinks to cells ApplyHyperlinks(FWorksheet); + + // Active worksheet + if i = actSheetIndex then + FWorkbook.SelectWorksheet(FWorksheet); end; // for finally @@ -3371,6 +3397,7 @@ end; procedure TsSpreadOOXMLWriter.WriteContent; var i, counter: Integer; + actTab: String; begin { --- WorkbookRels --- } { Workbook relations - Mark relation to all sheets } @@ -3396,6 +3423,9 @@ begin { --- Workbook --- } { Global workbook data - Mark all sheets } + actTab := IfThen(FWorkbook.ActiveWorksheet = nil, '', + 'activeTab="' + IntToStr(FWorkbook.GetWorksheetIndex(FWOrkbook.ActiveWorksheet)) + '"'); + AppendToStream(FSWorkbook, XML_HEADER); AppendToStream(FSWorkbook, Format( @@ -3406,7 +3436,7 @@ begin ''); AppendToStream(FSWorkbook, '' + - '' + + '' + ''); AppendToStream(FSWorkbook, '');