@@ -10337,8 +10337,66 @@ procedure TMainForm.DBtreePaintText(Sender: TBaseVirtualTree; const
1033710337procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1033810338var
1033910339 DBNode: PVirtualNode;
10340- OnlyDBNode, Expanded: Boolean;
10340+ OnlyDBNode, Expanded, ObjectFocused, CreatingObject : Boolean;
1034110341 SessNode: PVirtualNode;
10342+ ExpandedNodes: TStringList;
10343+ RefreshedObj: TDBObject;
10344+
10345+ function GroupKey(DBObj: PDBObject): String;
10346+ begin
10347+ Result := DBObj.Database + #9 + IntToStr(Integer(DBObj.GroupType));
10348+ end;
10349+
10350+ procedure StoreExpandedState(DBNode: PVirtualNode);
10351+ var
10352+ GroupNode: PVirtualNode;
10353+ DBObj: PDBObject;
10354+ begin
10355+ // Remember expanded state of a database node and its group nodes, as ResetNode collapses them
10356+ if (not (vsInitialized in DBNode.States)) or (not DBtree.Expanded[DBNode]) then
10357+ Exit;
10358+ DBObj := DBtree.GetNodeData(DBNode);
10359+ ExpandedNodes.Add(DBObj.Database);
10360+ GroupNode := DBtree.GetFirstChildNoInit(DBNode);
10361+ while Assigned(GroupNode) do begin
10362+ if (vsInitialized in GroupNode.States) and DBtree.Expanded[GroupNode] then begin
10363+ DBObj := DBtree.GetNodeData(GroupNode);
10364+ if DBObj.NodeType = lntGroup then
10365+ ExpandedNodes.Add(GroupKey(DBObj));
10366+ end;
10367+ GroupNode := DBtree.GetNextSiblingNoInit(GroupNode);
10368+ end;
10369+ end;
10370+
10371+ procedure RestoreExpandedState(DBNode: PVirtualNode);
10372+ var
10373+ GroupNode: PVirtualNode;
10374+ DBObj: PDBObject;
10375+ begin
10376+ // Node was probably just reset, so its data needs to be initialized again
10377+ DBtree.ValidateNode(DBNode, False);
10378+ DBObj := DBtree.GetNodeData(DBNode);
10379+ if ExpandedNodes.IndexOf(DBObj.Database) = -1 then
10380+ Exit;
10381+ try
10382+ DBtree.Expanded[DBNode] := True;
10383+ if not actGroupObjects.Checked then
10384+ Exit;
10385+ GroupNode := DBtree.GetFirstChild(DBNode);
10386+ while Assigned(GroupNode) do begin
10387+ DBObj := DBtree.GetNodeData(GroupNode);
10388+ if (DBObj.NodeType = lntGroup) and (ExpandedNodes.IndexOf(GroupKey(DBObj)) > -1) then
10389+ DBtree.Expanded[GroupNode] := True;
10390+ GroupNode := DBtree.GetNextSibling(GroupNode);
10391+ end;
10392+ except
10393+ // Expanding reads the objects of that database. Leave the node collapsed if that fails,
10394+ // so the rest of the refresh and the reselection of the focused node still happens.
10395+ on E:EDbError do
10396+ LogSQL('RefreshTree: '+E.Message, lcError);
10397+ end;
10398+ end;
10399+
1034210400begin
1034310401 // This refreshes exactly one session node and all its db and table nodes.
1034410402 // Also, tries to focus the previous focused object, if present.
@@ -10356,27 +10414,60 @@ procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1035610414 // ReInit tree population
1035710415 FTreeRefreshInProgress := True;
1035810416 SelectNode(DBtree, nil);
10417+ ExpandedNodes := TStringList.Create;
10418+ ExpandedNodes.CaseSensitive := True;
1035910419 try
1036010420 if not OnlyDBNode then begin
10421+ SessNode := GetRootNode(DBtree, FocusNewObject.Connection);
10422+ if Assigned(SessNode) then begin
10423+ DBNode := DBtree.GetFirstChildNoInit(SessNode);
10424+ while Assigned(DBNode) do begin
10425+ StoreExpandedState(DBNode);
10426+ DBNode := DBtree.GetNextSiblingNoInit(DBNode);
10427+ end;
10428+ end;
1036110429 FocusNewObject.Connection.ClearAllDbObjects;
1036210430 FocusNewObject.Connection.RefreshAllDatabases;
10363- SessNode := GetRootNode(DBtree, FocusNewObject.Connection);
1036410431 if Assigned(SessNode) then begin
1036510432 Expanded := DBtree.Expanded[SessNode];
1036610433 DBtree.ResetNode(SessNode);
1036710434 DBtree.Expanded[SessNode] := Expanded;
10435+ if Expanded then begin
10436+ DBNode := DBtree.GetFirstChild(SessNode);
10437+ while Assigned(DBNode) do begin
10438+ RestoreExpandedState(DBNode);
10439+ DBNode := DBtree.GetNextSibling(DBNode);
10440+ end;
10441+ end;
1036810442 end;
1036910443 end else begin
10370- FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database);
1037110444 DBNode := FindDbNode(DBtree, FocusNewObject.Connection, FocusNewObject.Database);
1037210445 if Assigned(DBNode) then
10446+ StoreExpandedState(DBNode);
10447+ FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database);
10448+ if Assigned(DBNode) then begin
1037310449 DBtree.ResetNode(DBNode);
10450+ RestoreExpandedState(DBNode);
10451+ end;
1037410452 end;
1037510453
1037610454 // Reselect active or new database if present. Could have been deleted or renamed.
1037710455 try
10378- if FocusNewObject.NodeType in [lntTable..lntEvent] then
10456+ if FocusNewObject.NodeType in [lntTable..lntEvent] then begin
10457+ // A just created object has no schema yet, while the server put it into the default one,
10458+ // e.g. "dbo" or "public". Take over the schema, so the node gets found in the tree.
10459+ if FocusNewObject.Schema.IsEmpty and (not FocusNewObject.Name.IsEmpty) then begin
10460+ for RefreshedObj in FocusNewObject.Connection.GetDBObjects(FocusNewObject.Database) do begin
10461+ if (RefreshedObj.NodeType = FocusNewObject.NodeType)
10462+ and (not RefreshedObj.Schema.IsEmpty)
10463+ and FocusNewObject.Connection.IdentifierEquals(RefreshedObj.Name, FocusNewObject.Name) then begin
10464+ FocusNewObject.Schema := RefreshedObj.Schema;
10465+ Break;
10466+ end;
10467+ end;
10468+ end;
1037910469 ActiveDBObj := FocusNewObject;
10470+ end;
1038010471 if not Assigned(DBtree.FocusedNode) then
1038110472 SetActiveDatabase(FocusNewObject.Database, FocusNewObject.Connection);
1038210473 if not Assigned(DBtree.FocusedNode) then
@@ -10388,6 +10479,22 @@ procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1038810479
1038910480 finally
1039010481 FTreeRefreshInProgress := False;
10482+ ExpandedNodes.Free;
10483+ // Tabs were left untouched during refresh. Hide editor and data tab if the previously focused
10484+ // object is gone, e.g. after it was dropped. Keep the editor of a new, yet unsaved object.
10485+ ObjectFocused := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable..lntEvent, lntColumn]);
10486+ CreatingObject := Assigned(ActiveObjectEditor) and ActiveObjectEditor.DBObject.Name.IsEmpty;
10487+ if (not ObjectFocused) and (not CreatingObject) then begin
10488+ if (PageControlMain.ActivePage = tabEditor) or (PageControlMain.ActivePage = tabData) then begin
10489+ if (FActiveDbObj <> nil) and (FActiveDbObj.NodeType <> lntNone) then begin
10490+ tabDatabase.TabVisible := True;
10491+ SetMainTab(tabDatabase);
10492+ end else
10493+ SetMainTab(tabHost);
10494+ end;
10495+ tabEditor.TabVisible := False;
10496+ tabData.TabVisible := False;
10497+ end;
1039110498 // Tree node filtering needs a hit in special cases, e.g. after a db was dropped
1039210499 if editDatabaseFilter.Text <> '' then
1039310500 editDatabaseFilter.OnChange(editDatabaseFilter);
0 commit comments