fpspreadsheet: Avoid flicker of TsTabControl when new workbook is opened or worksheets are added manually. Fix some bugs in the notification system.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3758 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-11-21 13:08:46 +00:00
parent 8f4315465b
commit faea171374
2 changed files with 69 additions and 12 deletions

View File

@ -942,6 +942,7 @@ type
FCalculationLock: Integer;
FOptions: TsWorkbookOptions;
FActiveWorksheet: TsWorksheet;
FOnOpenWorkbook: TNotifyEvent;
FOnWriteCellData: TsWorkbookWriteCellDataEvent;
FOnReadCellData: TsWorkbookReadCellDataEvent;
FOnChangeWorksheet: TsWorksheetEvent;
@ -949,6 +950,7 @@ type
FOnRemoveWorksheet: TsRemoveWorksheetEvent;
FOnSelectWorksheet: TsWorksheetEvent;
FFileName: String;
FLockCount: Integer;
FLog: TStringList;
{ Setter/Getter }
@ -1063,6 +1065,8 @@ type
property OnAddWorksheet: TsWorksheetEvent read FOnAddWorksheet write FOnAddWorksheet;
{@@ This event fires whenever a worksheet is changed }
property OnChangeWorksheet: TsWorksheetEvent read FOnChangeWorksheet write FOnChangeWorksheet;
{@@ This event fires whenever a workbook is loaded }
property OnOpenWorkbook: TNotifyEvent read FOnOpenWorkbook write FOnOpenWorkbook;
{@@ This event fires when a worksheet is deleted }
property OnRemoveWorksheet: TsRemoveWorksheetEvent read FOnRemoveWorksheet write FOnRemoveWorksheet;
{@@ This event fires when a worksheet is made "active"}
@ -3366,7 +3370,7 @@ begin
if (FWorkbook <> nil) then //and FWorkbook.ValidWorksheetName(AName) then
begin
FName := AName;
if Assigned(FWorkbook.FOnChangeWorksheet) then
if (FWorkbook.FLockCount = 0) and Assigned(FWorkbook.FOnChangeWorksheet) then
FWorkbook.FOnChangeWorksheet(FWorkbook, self);
end;
end;
@ -6495,6 +6499,7 @@ procedure TsWorkbook.ReadFromFile(AFileName: string;
AFormat: TsSpreadsheetFormat);
var
AReader: TsCustomSpreadReader;
ok: Boolean;
begin
if not FileExists(AFileName) then
raise Exception.CreateFmt(rsFileNotFound, [AFileName]);
@ -6503,11 +6508,20 @@ begin
try
FFileName := AFileName;
PrepareBeforeReading;
ok := false;
inc(FLockCount); // This locks various notifications from being sent
try
AReader.ReadFromFile(AFileName, Self);
ok := true;
UpdateCaches;
if (boAutoCalc in Options) then
Recalc;
FFormat := AFormat;
finally
dec(FLockCount);
if ok and Assigned(FOnOpenWorkbook) then // ok is true if file has been read successfully
FOnOpenWorkbook(self); // send common notification
end;
finally
AReader.Free;
end;
@ -6596,11 +6610,21 @@ procedure TsWorkbook.ReadFromStream(AStream: TStream;
AFormat: TsSpreadsheetFormat);
var
AReader: TsCustomSpreadReader;
ok: Boolean;
begin
AReader := CreateSpreadReader(AFormat);
try
PrepareBeforeReading;
inc(FLockCount);
try
ok := false;
AReader.ReadFromStream(AStream, Self);
ok := true;
finally
dec(FLockCount);
if ok and Assigned(FOnOpenWorkbook) then
FOnOpenWorkbook(self);
end;
UpdateCaches;
if (boAutoCalc in Options) then
Recalc;
@ -6708,15 +6732,34 @@ end;
function TsWorkbook.AddWorksheet(AName: string;
ReplaceDuplicateName: Boolean = false): TsWorksheet;
begin
// Check worksheet name
if not ValidWorksheetName(AName, ReplaceDuplicateName) then
raise Exception.CreateFmt(rsInvalidWorksheetName, [AName]);
// Create worksheet...
Result := TsWorksheet.Create;
Result.FWorkbook := Self; // Must be before "SetName" needing the workbook
// Add it to the internal worksheet list
FWorksheets.Add(Pointer(Result));
// Remember the workbook to which it belongs (This must occur before
// setting the workbook name because the workbook is needed there).
Result.FWorkbook := Self;
// Set the name of the new worksheet.
// For this we turn off notification of listeners. This is not necessary here
// because it will be repeated at end when OnAddWorksheet is executed below.
inc(FLockCount);
try
Result.Name := AName;
if Assigned(FOnAddWorksheet) then FOnAddWorksheet(self, Result);
finally
dec(FLockCount);
end;
// Send notification for new worksheet to listeners. They get the worksheet
// name here as well.
if (FLockCount = 0) and Assigned(FOnAddWorksheet) then
FOnAddWorksheet(self, Result);
end;
{@@ ----------------------------------------------------------------------------

View File

@ -73,6 +73,7 @@ type
AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0);
procedure SetFileName(const AFileName: TFileName);
procedure SetOptions(AValue: TsWorkbookOptions);
procedure WorkbookOpenedHandler(Sender: TObject);
procedure WorksheetAddedHandler(Sender: TObject; ASheet: TsWorksheet);
procedure WorksheetChangedHandler(Sender: TObject; ASheet: TsWorksheet);
procedure WorksheetRemovedHandler(Sender: TObject; ASheetIndex: Integer);
@ -473,7 +474,7 @@ begin
SelectWorksheet(FWorksheet);
// notify listeners
NotifyListeners([lniWorkbook, lniWorksheet, lniSelection]);
// NotifyListeners([lniWorkbook, lniWorksheet, lniSelection]);
end;
{@@ ----------------------------------------------------------------------------
@ -571,6 +572,7 @@ begin
FreeAndNil(FWorkbook);
FWorksheet := nil;
FWorkbook := TsWorkbook.Create;
FWorkbook.OnOpenWorkbook := @WorkbookOpenedHandler;
FWorkbook.OnAddWorksheet := @WorksheetAddedHandler;
FWorkbook.OnChangeWorksheet := @WorksheetChangedHandler;
FWorkbook.OnRemoveWorksheet := @WorksheetRemovedHandler;
@ -881,6 +883,16 @@ begin
FPendingOperation := AOperation;
end;
{@@ ----------------------------------------------------------------------------
Event handler called whenever a new workbook is opened.
-------------------------------------------------------------------------------}
procedure TsWorkbookSource.WorkbookOpenedHandler(Sender: TObject);
begin
Unused(Sender);
NotifyListeners([lniWorkbook]);
SelectWorksheet(FWorkbook.GetFirstWorksheet);
end;
{@@ ----------------------------------------------------------------------------
Event handler called whenever a new worksheet is added to the workbook
@ -938,6 +950,7 @@ begin
sheet := Workbook.GetWorksheetbyIndex(ASheetIndex);
end else
sheet := FWorksheet;
FWorksheet := sheet; // is needed by listeners!
NotifyListeners([lniWorkbook]);
SelectWorksheet(sheet);
end;
@ -1453,8 +1466,9 @@ var
activeCell: PCell;
begin
Unused(AData);
if worksheet = nil then
if (Worksheet = nil) or ([lniCell, lniSelection]*AChangedItems = []) then
exit;
activeCell := Worksheet.FindCell(Worksheet.ActiveCellRow, Worksheet.ActiveCellCol);
if ((lniCell in AChangedItems) and (PCell(AData) = activeCell)) or
(lniSelection in AChangedItems)