@@ -10398,8 +10398,66 @@ procedure TMainForm.DBtreePaintText(Sender: TBaseVirtualTree; const
1039810398procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1039910399var
1040010400 DBNode: PVirtualNode;
10401- OnlyDBNode, Expanded: Boolean;
10401+ OnlyDBNode, Expanded, ObjectFocused, CreatingObject : Boolean;
1040210402 SessNode: PVirtualNode;
10403+ ExpandedNodes: TStringList;
10404+ RefreshedObj: TDBObject;
10405+
10406+ function GroupKey(DBObj: PDBObject): String;
10407+ begin
10408+ Result := DBObj.Database + #9 + IntToStr(Integer(DBObj.GroupType));
10409+ end;
10410+
10411+ procedure StoreExpandedState(DBNode: PVirtualNode);
10412+ var
10413+ GroupNode: PVirtualNode;
10414+ DBObj: PDBObject;
10415+ begin
10416+ // Remember expanded state of a database node and its group nodes, as ResetNode collapses them
10417+ if (not (vsInitialized in DBNode.States)) or (not DBtree.Expanded[DBNode]) then
10418+ Exit;
10419+ DBObj := DBtree.GetNodeData(DBNode);
10420+ ExpandedNodes.Add(DBObj.Database);
10421+ GroupNode := DBtree.GetFirstChildNoInit(DBNode);
10422+ while Assigned(GroupNode) do begin
10423+ if (vsInitialized in GroupNode.States) and DBtree.Expanded[GroupNode] then begin
10424+ DBObj := DBtree.GetNodeData(GroupNode);
10425+ if DBObj.NodeType = lntGroup then
10426+ ExpandedNodes.Add(GroupKey(DBObj));
10427+ end;
10428+ GroupNode := DBtree.GetNextSiblingNoInit(GroupNode);
10429+ end;
10430+ end;
10431+
10432+ procedure RestoreExpandedState(DBNode: PVirtualNode);
10433+ var
10434+ GroupNode: PVirtualNode;
10435+ DBObj: PDBObject;
10436+ begin
10437+ // Node was probably just reset, so its data needs to be initialized again
10438+ DBtree.ValidateNode(DBNode, False);
10439+ DBObj := DBtree.GetNodeData(DBNode);
10440+ if ExpandedNodes.IndexOf(DBObj.Database) = -1 then
10441+ Exit;
10442+ try
10443+ DBtree.Expanded[DBNode] := True;
10444+ if not actGroupObjects.Checked then
10445+ Exit;
10446+ GroupNode := DBtree.GetFirstChild(DBNode);
10447+ while Assigned(GroupNode) do begin
10448+ DBObj := DBtree.GetNodeData(GroupNode);
10449+ if (DBObj.NodeType = lntGroup) and (ExpandedNodes.IndexOf(GroupKey(DBObj)) > -1) then
10450+ DBtree.Expanded[GroupNode] := True;
10451+ GroupNode := DBtree.GetNextSibling(GroupNode);
10452+ end;
10453+ except
10454+ // Expanding reads the objects of that database. Leave the node collapsed if that fails,
10455+ // so the rest of the refresh and the reselection of the focused node still happens.
10456+ on E:EDbError do
10457+ LogSQL('RefreshTree: '+E.Message, lcError);
10458+ end;
10459+ end;
10460+
1040310461begin
1040410462 // This refreshes exactly one session node and all its db and table nodes.
1040510463 // Also, tries to focus the previous focused object, if present.
@@ -10417,27 +10475,60 @@ procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1041710475 // ReInit tree population
1041810476 FTreeRefreshInProgress := True;
1041910477 SelectNode(DBtree, nil);
10478+ ExpandedNodes := TStringList.Create;
10479+ ExpandedNodes.CaseSensitive := True;
1042010480 try
1042110481 if not OnlyDBNode then begin
10482+ SessNode := GetRootNode(DBtree, FocusNewObject.Connection);
10483+ if Assigned(SessNode) then begin
10484+ DBNode := DBtree.GetFirstChildNoInit(SessNode);
10485+ while Assigned(DBNode) do begin
10486+ StoreExpandedState(DBNode);
10487+ DBNode := DBtree.GetNextSiblingNoInit(DBNode);
10488+ end;
10489+ end;
1042210490 FocusNewObject.Connection.ClearAllDbObjects;
1042310491 FocusNewObject.Connection.RefreshAllDatabases;
10424- SessNode := GetRootNode(DBtree, FocusNewObject.Connection);
1042510492 if Assigned(SessNode) then begin
1042610493 Expanded := DBtree.Expanded[SessNode];
1042710494 DBtree.ResetNode(SessNode);
1042810495 DBtree.Expanded[SessNode] := Expanded;
10496+ if Expanded then begin
10497+ DBNode := DBtree.GetFirstChild(SessNode);
10498+ while Assigned(DBNode) do begin
10499+ RestoreExpandedState(DBNode);
10500+ DBNode := DBtree.GetNextSibling(DBNode);
10501+ end;
10502+ end;
1042910503 end;
1043010504 end else begin
10431- FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database);
1043210505 DBNode := FindDbNode(DBtree, FocusNewObject.Connection, FocusNewObject.Database);
1043310506 if Assigned(DBNode) then
10507+ StoreExpandedState(DBNode);
10508+ FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database);
10509+ if Assigned(DBNode) then begin
1043410510 DBtree.ResetNode(DBNode);
10511+ RestoreExpandedState(DBNode);
10512+ end;
1043510513 end;
1043610514
1043710515 // Reselect active or new database if present. Could have been deleted or renamed.
1043810516 try
10439- if FocusNewObject.NodeType in [lntTable..lntEvent] then
10517+ if FocusNewObject.NodeType in [lntTable..lntEvent] then begin
10518+ // A just created object has no schema yet, while the server put it into the default one,
10519+ // e.g. "dbo" or "public". Take over the schema, so the node gets found in the tree.
10520+ if FocusNewObject.Schema.IsEmpty and (not FocusNewObject.Name.IsEmpty) then begin
10521+ for RefreshedObj in FocusNewObject.Connection.GetDBObjects(FocusNewObject.Database) do begin
10522+ if (RefreshedObj.NodeType = FocusNewObject.NodeType)
10523+ and (not RefreshedObj.Schema.IsEmpty)
10524+ and FocusNewObject.Connection.IdentifierEquals(RefreshedObj.Name, FocusNewObject.Name) then begin
10525+ FocusNewObject.Schema := RefreshedObj.Schema;
10526+ Break;
10527+ end;
10528+ end;
10529+ end;
1044010530 ActiveDBObj := FocusNewObject;
10531+ end;
1044110532 if not Assigned(DBtree.FocusedNode) then
1044210533 SetActiveDatabase(FocusNewObject.Database, FocusNewObject.Connection);
1044310534 if not Assigned(DBtree.FocusedNode) then
@@ -10449,6 +10540,22 @@ procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil);
1044910540
1045010541 finally
1045110542 FTreeRefreshInProgress := False;
10543+ ExpandedNodes.Free;
10544+ // Tabs were left untouched during refresh. Hide editor and data tab if the previously focused
10545+ // object is gone, e.g. after it was dropped. Keep the editor of a new, yet unsaved object.
10546+ ObjectFocused := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable..lntEvent, lntColumn]);
10547+ CreatingObject := Assigned(ActiveObjectEditor) and ActiveObjectEditor.DBObject.Name.IsEmpty;
10548+ if (not ObjectFocused) and (not CreatingObject) then begin
10549+ if (PageControlMain.ActivePage = tabEditor) or (PageControlMain.ActivePage = tabData) then begin
10550+ if (FActiveDbObj <> nil) and (FActiveDbObj.NodeType <> lntNone) then begin
10551+ tabDatabase.TabVisible := True;
10552+ SetMainTab(tabDatabase);
10553+ end else
10554+ SetMainTab(tabHost);
10555+ end;
10556+ tabEditor.TabVisible := False;
10557+ tabData.TabVisible := False;
10558+ end;
1045210559 // Tree node filtering needs a hit in special cases, e.g. after a db was dropped
1045310560 if editDatabaseFilter.Text <> '' then
1045410561 editDatabaseFilter.OnChange(editDatabaseFilter);
0 commit comments