Unify code for refreshing Virtual Trees in a new helper method InvalidateVT. Fixes issue #1789 and issue #1790.

* Don't try to access a passed tree if it has been destroyed by some earlier event.
* Don't try to access registry in DoDisconnect after key has been closed.
* Now that DoDisconnect lives in FormDestroy it is save to call it slightly earlier, before registry has been closed. There should be no later paint events which will trigger random database queries.
This commit is contained in:
Ansgar Becker
2010-03-21 10:43:16 +00:00
parent 3168a3e277
commit be645ac79b
4 changed files with 60 additions and 76 deletions

View File

@ -87,8 +87,7 @@ begin
if not chklistColumns.Checked[i] then if not chklistColumns.Checked[i] then
Mainform.DataGridHiddenColumns.Add(chklistColumns.Items[i]); Mainform.DataGridHiddenColumns.Add(chklistColumns.Items[i]);
end; end;
Mainform.DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
Mainform.DataGrid.Invalidate;
btnCancel.OnClick(Sender); btnCancel.OnClick(Sender);
end; end;

View File

@ -315,8 +315,7 @@ procedure TDataSortingForm.btnOKClick(Sender: TObject);
begin begin
// TODO: apply ordering // TODO: apply ordering
Mainform.DataGridSortColumns := OrderColumns; Mainform.DataGridSortColumns := OrderColumns;
Mainform.DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
Mainform.DataGrid.Invalidate;
btnCancel.OnClick(Sender); btnCancel.OnClick(Sender);
end; end;

View File

@ -249,6 +249,7 @@ type
function GetIndexIcon(IndexType: String): Integer; function GetIndexIcon(IndexType: String): Integer;
function KeyPressed(Code: Integer): Boolean; function KeyPressed(Code: Integer): Boolean;
function GeneratePassword(Len: Integer): String; function GeneratePassword(Len: Integer): String;
procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean);
var var
MainReg: TRegistry; MainReg: TRegistry;
@ -3442,6 +3443,19 @@ begin
end; end;
procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean);
begin
// Avoid AVs in OnDestroy events
if not Assigned(VT) then
Exit;
VT.Tag := RefreshTag;
if ImmediateRepaint then
VT.Repaint
else
VT.Invalidate;
end;
end. end.

View File

@ -1121,7 +1121,7 @@ procedure TMainForm.FormDestroy(Sender: TObject);
var var
filename : String; filename : String;
begin begin
// Destroy editors and dialogs. Must be done before connection gets closed, as some destructors do SQL stuff. // Destroy editors and dialogs. Must be done before connection gets closed, as some destructors do SQL stuff.
FreeAndNil(RoutineEditor); FreeAndNil(RoutineEditor);
FreeAndNil(TableToolsDialog); FreeAndNil(TableToolsDialog);
FreeAndNil(UserManagerForm); FreeAndNil(UserManagerForm);
@ -1135,8 +1135,15 @@ begin
FreeAndNil(CreateDatabaseForm); FreeAndNil(CreateDatabaseForm);
FreeAndNil(SearchReplaceDialog); FreeAndNil(SearchReplaceDialog);
// Clearing query and browse data.
SetLength(DataGridResult.Rows, 0);
SetLength(DataGridResult.Columns, 0);
// Close database connection
DoDisconnect;
// Save various settings
OpenRegistry; OpenRegistry;
// Position of Toolbars
MainReg.WriteInteger(REGNAME_TOOLBAR2LEFT, ToolBarStandard.Left); MainReg.WriteInteger(REGNAME_TOOLBAR2LEFT, ToolBarStandard.Left);
MainReg.WriteInteger(REGNAME_TOOLBAR2TOP, ToolBarStandard.Top); MainReg.WriteInteger(REGNAME_TOOLBAR2TOP, ToolBarStandard.Top);
MainReg.WriteInteger(REGNAME_TOOLBARDATALEFT, ToolBarData.Left); MainReg.WriteInteger(REGNAME_TOOLBARDATALEFT, ToolBarData.Left);
@ -1145,29 +1152,17 @@ begin
MainReg.WriteInteger(REGNAME_TOOLBARQUERYTOP, ToolBarQuery.Top); MainReg.WriteInteger(REGNAME_TOOLBARQUERYTOP, ToolBarQuery.Top);
MainReg.WriteBool(REGNAME_STOPONERRORSINBATCH, actQueryStopOnErrors.Checked); MainReg.WriteBool(REGNAME_STOPONERRORSINBATCH, actQueryStopOnErrors.Checked);
MainReg.WriteBool(REGNAME_BLOBASTEXT, actBlobAsText.Checked); MainReg.WriteBool(REGNAME_BLOBASTEXT, actBlobAsText.Checked);
// Save delimiter
MainReg.WriteString( REGNAME_DELIMITER, Delimiter ); MainReg.WriteString( REGNAME_DELIMITER, Delimiter );
MainReg.WriteInteger( REGNAME_QUERYMEMOHEIGHT, pnlQueryMemo.Height ); MainReg.WriteInteger( REGNAME_QUERYMEMOHEIGHT, pnlQueryMemo.Height );
MainReg.WriteInteger( REGNAME_QUERYHELPERSWIDTH, pnlQueryHelpers.Width ); MainReg.WriteInteger( REGNAME_QUERYHELPERSWIDTH, pnlQueryHelpers.Width );
MainReg.WriteInteger( REGNAME_DBTREEWIDTH, pnlLeft.width ); MainReg.WriteInteger( REGNAME_DBTREEWIDTH, pnlLeft.width );
MainReg.WriteInteger( REGNAME_SQLOUTHEIGHT, SynMemoSQLLog.Height ); MainReg.WriteInteger( REGNAME_SQLOUTHEIGHT, SynMemoSQLLog.Height );
// Filter panel
MainReg.WriteBool(REGNAME_FILTERACTIVE, pnlFilterVT.Tag=Integer(True)); MainReg.WriteBool(REGNAME_FILTERACTIVE, pnlFilterVT.Tag=Integer(True));
// Save width of probably resized columns of all VirtualTrees
SaveListSetup(ListVariables); SaveListSetup(ListVariables);
SaveListSetup(ListStatus); SaveListSetup(ListStatus);
SaveListSetup(ListProcesses); SaveListSetup(ListProcesses);
SaveListSetup(ListCommandStats); SaveListSetup(ListCommandStats);
SaveListSetup(ListTables); SaveListSetup(ListTables);
debug('mem: clearing query and browse data.');
SetLength(DataGridResult.Rows, 0);
SetLength(DataGridResult.Columns, 0);
saveWindowConfig; saveWindowConfig;
filename := GetTempDir+'\'+APPNAME+'-preview.'; filename := GetTempDir+'\'+APPNAME+'-preview.';
@ -1183,10 +1178,6 @@ begin
MainReg.CloseKey; MainReg.CloseKey;
MainReg.Free; MainReg.Free;
end; end;
// Close database connection at the very end, as above stuff can easily
// trigger some database query
DoDisconnect;
end; end;
@ -1815,6 +1806,10 @@ end;
procedure TMainForm.DoDisconnect; procedure TMainForm.DoDisconnect;
begin begin
// Do nothing in case user clicked Cancel on session manager
if (not Assigned(Connection)) or (not Connection.Active) then
Exit;
// Open server-specific registry-folder. // Open server-specific registry-folder.
// relative from already opened folder! // relative from already opened folder!
OpenRegistry(SessionName); OpenRegistry(SessionName);
@ -1835,18 +1830,17 @@ begin
SetLength(DataGridSortColumns, 0); SetLength(DataGridSortColumns, 0);
// Closing connection // Closing connection
if Assigned(Connection) then Connection.Active := False;
FreeAndNil(Connection);
if prefLogToFile then if prefLogToFile then
DeactivateFileLogging; DeactivateFileLogging;
// Invalidate list contents // Invalidate list contents
ListVariables.Tag := VTREE_NOTLOADED; InvalidateVT(ListVariables, VTREE_NOTLOADED, False);
ListStatus.Tag := VTREE_NOTLOADED; InvalidateVT(ListStatus, VTREE_NOTLOADED, False);
ListProcesses.Tag := VTREE_NOTLOADED; InvalidateVT(ListProcesses, VTREE_NOTLOADED, False);
ListCommandstats.Tag := VTREE_NOTLOADED; InvalidateVT(ListCommandstats, VTREE_NOTLOADED, False);
ListTables.Tag := VTREE_NOTLOADED; InvalidateVT(ListTables, VTREE_NOTLOADED, False);
Application.Title := APPNAME; Application.Title := APPNAME;
end; end;
@ -1957,10 +1951,8 @@ begin
ActiveQueryTab.MemoFilename := ''; ActiveQueryTab.MemoFilename := '';
ActiveQueryTab.Memo.Modified := False; ActiveQueryTab.Memo.Modified := False;
end; end;
if m = SynMemoFilter then begin if m = SynMemoFilter then
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end;
end; end;
procedure TMainForm.actTableToolsExecute(Sender: TObject); procedure TMainForm.actTableToolsExecute(Sender: TObject);
@ -2562,8 +2554,8 @@ begin
end; end;
Result := True; Result := True;
if Assigned(Connection) then DoDisconnect;
DoDisconnect; FreeAndNil(Connection);
Connection := ConnectionAttempt; Connection := ConnectionAttempt;
SessionName := Session; SessionName := Session;
end; end;
@ -2767,15 +2759,11 @@ begin
List := ListProcesses List := ListProcesses
else else
List := ListCommandStats; List := ListCommandStats;
List.Tag := VTREE_NOTLOADED; InvalidateVT(List, VTREE_NOTLOADED, True);
List.Repaint; end else if tab1 = tabDatabase then
end else if tab1 = tabDatabase then begin InvalidateVT(ListTables, VTREE_NOTLOADED_PURGECACHE, False)
ListTables.Tag := VTREE_NOTLOADED_PURGECACHE; else if tab1 = tabData then
ListTables.Invalidate; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
end else if tab1 = tabData then begin
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE;
DataGrid.Invalidate;
end;
end; end;
@ -3188,8 +3176,7 @@ begin
FreeAndNil(OldNumbers); FreeAndNil(OldNumbers);
FreeAndNil(Filters); FreeAndNil(Filters);
end; end;
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end; end;
@ -3238,8 +3225,7 @@ end;
procedure TMainForm.actRemoveFilterExecute(Sender: TObject); procedure TMainForm.actRemoveFilterExecute(Sender: TObject);
begin begin
actClearFilterEditor.Execute; actClearFilterEditor.Execute;
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end; end;
@ -3362,8 +3348,7 @@ begin
OldRowCount := DatagridWantedRowCount; OldRowCount := DatagridWantedRowCount;
Inc(DatagridWantedRowCount, prefGridRowcountStep); Inc(DatagridWantedRowCount, prefGridRowcountStep);
DataGridWantedRowCount := Min(DataGridWantedRowCount, prefGridRowcountMax); DataGridWantedRowCount := Min(DataGridWantedRowCount, prefGridRowcountMax);
DataGrid.Tag := VTREE_NOTLOADED; InvalidateVT(DataGrid, VTREE_NOTLOADED, True);
DataGrid.Repaint;
SelectNode(DataGrid, OldRowCount); SelectNode(DataGrid, OldRowCount);
end; end;
@ -3372,8 +3357,7 @@ procedure TMainForm.actDataShowAllExecute(Sender: TObject);
begin begin
// Remove LIMIT clause // Remove LIMIT clause
DatagridWantedRowCount := prefGridRowcountMax; DatagridWantedRowCount := prefGridRowcountMax;
DataGrid.Tag := VTREE_NOTLOADED; InvalidateVT(DataGrid, VTREE_NOTLOADED, True);
DataGrid.Repaint;
end; end;
@ -3434,8 +3418,7 @@ begin
while Assigned(Node) do begin while Assigned(Node) do begin
if not DataGridRowHasFullData(Node) then begin if not DataGridRowHasFullData(Node) then begin
DataGridFullRowMode := True; DataGridFullRowMode := True;
Grid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(Grid, VTREE_NOTLOADED_PURGECACHE, True);
Grid.Repaint;
break; break;
end; end;
if SelectedOnly then if SelectedOnly then
@ -4088,8 +4071,7 @@ begin
on E:Exception do on E:Exception do
MessageDlg(E.Message, mtError, [mbOK], 0); MessageDlg(E.Message, mtError, [mbOK], 0);
end; end;
ListProcesses.Tag := VTREE_NOTLOADED; InvalidateVT(ListProcesses, VTREE_NOTLOADED, True);
ListProcesses.Repaint;
end; end;
TimerRefresh.Enabled := t; // re-enable autorefresh timer TimerRefresh.Enabled := t; // re-enable autorefresh timer
end; end;
@ -6530,8 +6512,7 @@ begin
// tab is a Host or Database tab, switch to showing table columns. // tab is a Host or Database tab, switch to showing table columns.
if (PagecontrolMain.ActivePage = tabHost) or (PagecontrolMain.ActivePage = tabDatabase) then if (PagecontrolMain.ActivePage = tabHost) or (PagecontrolMain.ActivePage = tabDatabase) then
PagecontrolMain.ActivePage := tabEditor; PagecontrolMain.ActivePage := tabEditor;
DataGrid.Tag := VTREE_NOTLOADED; InvalidateVT(DataGrid, VTREE_NOTLOADED, False);
DataGrid.Invalidate;
// When a table is clicked in the tree, and the query // When a table is clicked in the tree, and the query
// tab is active, update the list of columns // tab is active, update the list of columns
if QueryTabActive then if QueryTabActive then
@ -6548,8 +6529,7 @@ begin
tabDatabase.Caption := sstr('Database: ' + newDb, 30); tabDatabase.Caption := sstr('Database: ' + newDb, 30);
ListTables.ClearSelection; ListTables.ClearSelection;
ListTables.FocusedNode := nil; ListTables.FocusedNode := nil;
ListTables.Tag := VTREE_NOTLOADED; InvalidateVT(ListTables, VTREE_NOTLOADED, False);
ListTables.Invalidate;
end; end;
PreviousFocusedNode := DBTree.FocusedNode; PreviousFocusedNode := DBTree.FocusedNode;
FixQueryTabCloseButtons; FixQueryTabCloseButtons;
@ -6584,8 +6564,7 @@ begin
SelectedTableColumns.Clear; SelectedTableColumns.Clear;
SelectedTableKeys.Clear; SelectedTableKeys.Clear;
SelectedTableForeignKeys.Clear; SelectedTableForeignKeys.Clear;
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
try try
case SelectedTable.NodeType of case SelectedTable.NodeType of
lntTable: begin lntTable: begin
@ -6609,10 +6588,8 @@ end;
procedure TMainForm.AfterClearDBObjects(Database: String); procedure TMainForm.AfterClearDBObjects(Database: String);
begin begin
if (Database='') or (ActiveDatabase=Database) then begin if (Database='') or (ActiveDatabase=Database) then
ListTables.Tag := VTREE_NOTLOADED; InvalidateVT(ListTables, VTREE_NOTLOADED, False);
ListTables.Invalidate;
end;
end; end;
@ -6988,8 +6965,7 @@ begin
DataGridSortColumns[i].ColumnName := ColName; DataGridSortColumns[i].ColumnName := ColName;
DataGridSortColumns[i].SortDirection := ORDER_ASC; DataGridSortColumns[i].SortDirection := ORDER_ASC;
end; end;
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end else begin end else begin
frm := TColumnSelectionForm.Create(self); frm := TColumnSelectionForm.Create(self);
// Position new form relative to btn's position // Position new form relative to btn's position
@ -7359,8 +7335,7 @@ begin
Raise Exception.Create('Server failed to insert row.'); Raise Exception.Create('Server failed to insert row.');
Result := True; Result := True;
GridFinalizeEditing(Sender); GridFinalizeEditing(Sender);
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
except except
on E:Exception do begin on E:Exception do begin
MessageDlg(E.Message, mtError, [mbOK], 0); MessageDlg(E.Message, mtError, [mbOK], 0);
@ -7432,8 +7407,7 @@ begin
Sender.EndUpdate; Sender.EndUpdate;
end else begin end else begin
// Should never get called as we block DELETEs on tables without a unique key // Should never get called as we block DELETEs on tables without a unique key
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
msg := 'Warning: Consistency problem detected.' + CRLF + CRLF msg := 'Warning: Consistency problem detected.' + CRLF + CRLF
+ 'The last DELETE query affected ' + FormatNumber(Affected) + ' rows, when it should have touched '+FormatNumber(Sender.SelectedCount)+' row(s)!' + 'The last DELETE query affected ' + FormatNumber(Affected) + ' rows, when it should have touched '+FormatNumber(Sender.SelectedCount)+' row(s)!'
+ CRLF + CRLF + CRLF + CRLF
@ -9271,8 +9245,7 @@ end;
procedure TMainForm.actDataResetSortingExecute(Sender: TObject); procedure TMainForm.actDataResetSortingExecute(Sender: TObject);
begin begin
SetLength(DataGridSortColumns, 0); SetLength(DataGridSortColumns, 0);
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end; end;
@ -9311,8 +9284,7 @@ end;
procedure TMainForm.actBlobAsTextExecute(Sender: TObject); procedure TMainForm.actBlobAsTextExecute(Sender: TObject);
begin begin
// Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts // Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts
DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
DataGrid.Invalidate;
end; end;