From be645ac79bea47eeb38998bd6145928e543e2aa3 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Sun, 21 Mar 2010 10:43:16 +0000 Subject: [PATCH] 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. --- source/column_selection.pas | 3 +- source/data_sorting.pas | 3 +- source/helpers.pas | 14 +++++ source/main.pas | 116 ++++++++++++++---------------------- 4 files changed, 60 insertions(+), 76 deletions(-) diff --git a/source/column_selection.pas b/source/column_selection.pas index 66d3f6c3..001d2c3e 100644 --- a/source/column_selection.pas +++ b/source/column_selection.pas @@ -87,8 +87,7 @@ begin if not chklistColumns.Checked[i] then Mainform.DataGridHiddenColumns.Add(chklistColumns.Items[i]); end; - Mainform.DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - Mainform.DataGrid.Invalidate; + InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); btnCancel.OnClick(Sender); end; diff --git a/source/data_sorting.pas b/source/data_sorting.pas index 09034b9b..b3c0505b 100644 --- a/source/data_sorting.pas +++ b/source/data_sorting.pas @@ -315,8 +315,7 @@ procedure TDataSortingForm.btnOKClick(Sender: TObject); begin // TODO: apply ordering Mainform.DataGridSortColumns := OrderColumns; - Mainform.DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - Mainform.DataGrid.Invalidate; + InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); btnCancel.OnClick(Sender); end; diff --git a/source/helpers.pas b/source/helpers.pas index cc0c0718..8b2f12be 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -249,6 +249,7 @@ type function GetIndexIcon(IndexType: String): Integer; function KeyPressed(Code: Integer): Boolean; function GeneratePassword(Len: Integer): String; + procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean); var MainReg: TRegistry; @@ -3442,6 +3443,19 @@ begin 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. diff --git a/source/main.pas b/source/main.pas index 9d58944e..7f90abc3 100644 --- a/source/main.pas +++ b/source/main.pas @@ -1121,7 +1121,7 @@ procedure TMainForm.FormDestroy(Sender: TObject); var filename : String; 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(TableToolsDialog); FreeAndNil(UserManagerForm); @@ -1135,8 +1135,15 @@ begin FreeAndNil(CreateDatabaseForm); FreeAndNil(SearchReplaceDialog); + // Clearing query and browse data. + SetLength(DataGridResult.Rows, 0); + SetLength(DataGridResult.Columns, 0); + + // Close database connection + DoDisconnect; + + // Save various settings OpenRegistry; - // Position of Toolbars MainReg.WriteInteger(REGNAME_TOOLBAR2LEFT, ToolBarStandard.Left); MainReg.WriteInteger(REGNAME_TOOLBAR2TOP, ToolBarStandard.Top); MainReg.WriteInteger(REGNAME_TOOLBARDATALEFT, ToolBarData.Left); @@ -1145,29 +1152,17 @@ begin MainReg.WriteInteger(REGNAME_TOOLBARQUERYTOP, ToolBarQuery.Top); MainReg.WriteBool(REGNAME_STOPONERRORSINBATCH, actQueryStopOnErrors.Checked); MainReg.WriteBool(REGNAME_BLOBASTEXT, actBlobAsText.Checked); - - // Save delimiter MainReg.WriteString( REGNAME_DELIMITER, Delimiter ); - MainReg.WriteInteger( REGNAME_QUERYMEMOHEIGHT, pnlQueryMemo.Height ); MainReg.WriteInteger( REGNAME_QUERYHELPERSWIDTH, pnlQueryHelpers.Width ); MainReg.WriteInteger( REGNAME_DBTREEWIDTH, pnlLeft.width ); MainReg.WriteInteger( REGNAME_SQLOUTHEIGHT, SynMemoSQLLog.Height ); - - // Filter panel MainReg.WriteBool(REGNAME_FILTERACTIVE, pnlFilterVT.Tag=Integer(True)); - - // Save width of probably resized columns of all VirtualTrees SaveListSetup(ListVariables); SaveListSetup(ListStatus); SaveListSetup(ListProcesses); SaveListSetup(ListCommandStats); SaveListSetup(ListTables); - - debug('mem: clearing query and browse data.'); - SetLength(DataGridResult.Rows, 0); - SetLength(DataGridResult.Columns, 0); - saveWindowConfig; filename := GetTempDir+'\'+APPNAME+'-preview.'; @@ -1183,10 +1178,6 @@ begin MainReg.CloseKey; MainReg.Free; end; - - // Close database connection at the very end, as above stuff can easily - // trigger some database query - DoDisconnect; end; @@ -1815,6 +1806,10 @@ end; procedure TMainForm.DoDisconnect; 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. // relative from already opened folder! OpenRegistry(SessionName); @@ -1835,18 +1830,17 @@ begin SetLength(DataGridSortColumns, 0); // Closing connection - if Assigned(Connection) then - FreeAndNil(Connection); + Connection.Active := False; if prefLogToFile then DeactivateFileLogging; // Invalidate list contents - ListVariables.Tag := VTREE_NOTLOADED; - ListStatus.Tag := VTREE_NOTLOADED; - ListProcesses.Tag := VTREE_NOTLOADED; - ListCommandstats.Tag := VTREE_NOTLOADED; - ListTables.Tag := VTREE_NOTLOADED; + InvalidateVT(ListVariables, VTREE_NOTLOADED, False); + InvalidateVT(ListStatus, VTREE_NOTLOADED, False); + InvalidateVT(ListProcesses, VTREE_NOTLOADED, False); + InvalidateVT(ListCommandstats, VTREE_NOTLOADED, False); + InvalidateVT(ListTables, VTREE_NOTLOADED, False); Application.Title := APPNAME; end; @@ -1957,10 +1951,8 @@ begin ActiveQueryTab.MemoFilename := ''; ActiveQueryTab.Memo.Modified := False; end; - if m = SynMemoFilter then begin - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; - end; + if m = SynMemoFilter then + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end; procedure TMainForm.actTableToolsExecute(Sender: TObject); @@ -2562,8 +2554,8 @@ begin end; Result := True; - if Assigned(Connection) then - DoDisconnect; + DoDisconnect; + FreeAndNil(Connection); Connection := ConnectionAttempt; SessionName := Session; end; @@ -2767,15 +2759,11 @@ begin List := ListProcesses else List := ListCommandStats; - List.Tag := VTREE_NOTLOADED; - List.Repaint; - end else if tab1 = tabDatabase then begin - ListTables.Tag := VTREE_NOTLOADED_PURGECACHE; - ListTables.Invalidate; - end else if tab1 = tabData then begin - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; - end; + InvalidateVT(List, VTREE_NOTLOADED, True); + end else if tab1 = tabDatabase then + InvalidateVT(ListTables, VTREE_NOTLOADED_PURGECACHE, False) + else if tab1 = tabData then + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end; @@ -3188,8 +3176,7 @@ begin FreeAndNil(OldNumbers); FreeAndNil(Filters); end; - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end; @@ -3238,8 +3225,7 @@ end; procedure TMainForm.actRemoveFilterExecute(Sender: TObject); begin actClearFilterEditor.Execute; - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end; @@ -3362,8 +3348,7 @@ begin OldRowCount := DatagridWantedRowCount; Inc(DatagridWantedRowCount, prefGridRowcountStep); DataGridWantedRowCount := Min(DataGridWantedRowCount, prefGridRowcountMax); - DataGrid.Tag := VTREE_NOTLOADED; - DataGrid.Repaint; + InvalidateVT(DataGrid, VTREE_NOTLOADED, True); SelectNode(DataGrid, OldRowCount); end; @@ -3372,8 +3357,7 @@ procedure TMainForm.actDataShowAllExecute(Sender: TObject); begin // Remove LIMIT clause DatagridWantedRowCount := prefGridRowcountMax; - DataGrid.Tag := VTREE_NOTLOADED; - DataGrid.Repaint; + InvalidateVT(DataGrid, VTREE_NOTLOADED, True); end; @@ -3434,8 +3418,7 @@ begin while Assigned(Node) do begin if not DataGridRowHasFullData(Node) then begin DataGridFullRowMode := True; - Grid.Tag := VTREE_NOTLOADED_PURGECACHE; - Grid.Repaint; + InvalidateVT(Grid, VTREE_NOTLOADED_PURGECACHE, True); break; end; if SelectedOnly then @@ -4088,8 +4071,7 @@ begin on E:Exception do MessageDlg(E.Message, mtError, [mbOK], 0); end; - ListProcesses.Tag := VTREE_NOTLOADED; - ListProcesses.Repaint; + InvalidateVT(ListProcesses, VTREE_NOTLOADED, True); end; TimerRefresh.Enabled := t; // re-enable autorefresh timer end; @@ -6530,8 +6512,7 @@ begin // tab is a Host or Database tab, switch to showing table columns. if (PagecontrolMain.ActivePage = tabHost) or (PagecontrolMain.ActivePage = tabDatabase) then PagecontrolMain.ActivePage := tabEditor; - DataGrid.Tag := VTREE_NOTLOADED; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED, False); // When a table is clicked in the tree, and the query // tab is active, update the list of columns if QueryTabActive then @@ -6548,8 +6529,7 @@ begin tabDatabase.Caption := sstr('Database: ' + newDb, 30); ListTables.ClearSelection; ListTables.FocusedNode := nil; - ListTables.Tag := VTREE_NOTLOADED; - ListTables.Invalidate; + InvalidateVT(ListTables, VTREE_NOTLOADED, False); end; PreviousFocusedNode := DBTree.FocusedNode; FixQueryTabCloseButtons; @@ -6584,8 +6564,7 @@ begin SelectedTableColumns.Clear; SelectedTableKeys.Clear; SelectedTableForeignKeys.Clear; - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); try case SelectedTable.NodeType of lntTable: begin @@ -6609,10 +6588,8 @@ end; procedure TMainForm.AfterClearDBObjects(Database: String); begin - if (Database='') or (ActiveDatabase=Database) then begin - ListTables.Tag := VTREE_NOTLOADED; - ListTables.Invalidate; - end; + if (Database='') or (ActiveDatabase=Database) then + InvalidateVT(ListTables, VTREE_NOTLOADED, False); end; @@ -6988,8 +6965,7 @@ begin DataGridSortColumns[i].ColumnName := ColName; DataGridSortColumns[i].SortDirection := ORDER_ASC; end; - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end else begin frm := TColumnSelectionForm.Create(self); // Position new form relative to btn's position @@ -7359,8 +7335,7 @@ begin Raise Exception.Create('Server failed to insert row.'); Result := True; GridFinalizeEditing(Sender); - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); except on E:Exception do begin MessageDlg(E.Message, mtError, [mbOK], 0); @@ -7432,8 +7407,7 @@ begin Sender.EndUpdate; end else begin // Should never get called as we block DELETEs on tables without a unique key - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); 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)!' + CRLF + CRLF @@ -9271,8 +9245,7 @@ end; procedure TMainForm.actDataResetSortingExecute(Sender: TObject); begin SetLength(DataGridSortColumns, 0); - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end; @@ -9311,8 +9284,7 @@ end; procedure TMainForm.actBlobAsTextExecute(Sender: TObject); begin // Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts - DataGrid.Tag := VTREE_NOTLOADED_PURGECACHE; - DataGrid.Invalidate; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); end;