anchordocking: more robust

git-svn-id: trunk@26051 -
This commit is contained in:
mattias 2010-06-12 08:11:25 +00:00
parent 32a0388d47
commit 7e4e55bc52
2 changed files with 51 additions and 36 deletions

View File

@ -345,16 +345,15 @@ type
fSimplifying: boolean; fSimplifying: boolean;
fUpdateCount: integer; fUpdateCount: integer;
fDisabledAutosizing: TFPList; // list of TControl fDisabledAutosizing: TFPList; // list of TControl
fTreeNameToDocker: TADNameToControl;
function GetControls(Index: integer): TControl; function GetControls(Index: integer): TControl;
procedure SetHeaderAlignLeft(const AValue: integer); procedure SetHeaderAlignLeft(const AValue: integer);
procedure SetHeaderAlignTop(const AValue: integer); procedure SetHeaderAlignTop(const AValue: integer);
function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean; function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
function CreateNeededControls(Tree: TAnchorDockLayoutTree; function CreateNeededControls(Tree: TAnchorDockLayoutTree;
DisableAutoSizing: boolean; ControlNames: TStrings): boolean; DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
procedure MapTreeToControls(Tree: TAnchorDockLayoutTree; procedure MapTreeToControls(Tree: TAnchorDockLayoutTree);
TreeNameToDocker: TADNameToControl); function RestoreLayout(Tree: TAnchorDockLayoutTree): boolean;
function RestoreLayout(Tree: TAnchorDockLayoutTree;
TreeNameToDocker: TADNameToControl): boolean;
function DoCreateControl(aName: string; DisableAutoSizing: boolean): TControl; function DoCreateControl(aName: string; DisableAutoSizing: boolean): TControl;
procedure DisableControlAutoSizing(AControl: TControl); procedure DisableControlAutoSizing(AControl: TControl);
procedure EnableAllAutoSizing; procedure EnableAllAutoSizing;
@ -597,8 +596,7 @@ begin
Result:=true; Result:=true;
end; end;
procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree; procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree);
TreeNameToDocker: TADNameToControl);
procedure MapHostDockSites(Node: TAnchorDockLayoutTreeNode); procedure MapHostDockSites(Node: TAnchorDockLayoutTreeNode);
// map in TreeNameToDocker each control name to its HostDockSite or custom dock site // map in TreeNameToDocker each control name to its HostDockSite or custom dock site
@ -610,14 +608,14 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
if (Node.NodeType=adltnControl) then begin if (Node.NodeType=adltnControl) then begin
AControl:=FindControl(Node.Name); AControl:=FindControl(Node.Name);
if (AControl<>nil) and (AControl.HostDockSite is TAnchorDockHostSite) then if (AControl<>nil) and (AControl.HostDockSite is TAnchorDockHostSite) then
TreeNameToDocker[Node.Name]:=AControl.HostDockSite; fTreeNameToDocker[Node.Name]:=AControl.HostDockSite;
// ignore kids // ignore kids
exit; exit;
end; end;
if (Node.NodeType=adltnCustomSite) then begin if (Node.NodeType=adltnCustomSite) then begin
AControl:=FindControl(Node.Name); AControl:=FindControl(Node.Name);
if IsCustomSite(AControl) then if IsCustomSite(AControl) then
TreeNameToDocker[Node.Name]:=AControl; fTreeNameToDocker[Node.Name]:=AControl;
end; end;
for i:=0 to Node.Count-1 do for i:=0 to Node.Count-1 do
MapHostDockSites(Node[i]); // recursive MapHostDockSites(Node[i]); // recursive
@ -637,7 +635,7 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
i: Integer; i: Integer;
begin begin
if ChildNode.NodeType in [adltnControl,adltnCustomSite] then if ChildNode.NodeType in [adltnControl,adltnCustomSite] then
Result:=TCustomForm(TreeNameToDocker[ChildNode.Name]) Result:=TCustomForm(fTreeNameToDocker[ChildNode.Name])
else else
for i:=0 to ChildNode.Count-1 do begin for i:=0 to ChildNode.Count-1 do begin
Result:=FindMappedControl(ChildNode[i]); // search recursive Result:=FindMappedControl(ChildNode[i]); // search recursive
@ -655,7 +653,7 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
if Node.Name='' then exit; if Node.Name='' then exit;
if Node.NodeType=adltnControl then exit; if Node.NodeType=adltnControl then exit;
// Node is a complex site // Node is a complex site
if TreeNameToDocker[Node.Name]<>nil then exit; if fTreeNameToDocker[Node.Name]<>nil then exit;
// and not yet mapped to a site // and not yet mapped to a site
Site:=FindMappedControl(Node); Site:=FindMappedControl(Node);
if Site=nil then exit; if Site=nil then exit;
@ -663,10 +661,10 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
RootSite:=GetParentForm(Site); RootSite:=GetParentForm(Site);
if not (RootSite is TAnchorDockHostSite) then exit; if not (RootSite is TAnchorDockHostSite) then exit;
// and the mapped site has a root site // and the mapped site has a root site
if TreeNameToDocker.ControlToName(RootSite)<>'' then exit; if fTreeNameToDocker.ControlToName(RootSite)<>'' then exit;
// and the root site is not yet mapped // and the root site is not yet mapped
// => map the root node to the root site // => map the root node to the root site
TreeNameToDocker[Node.Name]:=RootSite; fTreeNameToDocker[Node.Name]:=RootSite;
end else end else
for i:=0 to Node.Count-1 do for i:=0 to Node.Count-1 do
MapTopLevelSites(Node[i]); // recursive MapTopLevelSites(Node[i]); // recursive
@ -683,19 +681,19 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
BestSite: TControl; BestSite: TControl;
begin begin
if Node.IsSplitter then exit; if Node.IsSplitter then exit;
BestSite:=TreeNameToDocker[Node.Name]; BestSite:=fTreeNameToDocker[Node.Name];
for i:=0 to Node.Count-1 do begin for i:=0 to Node.Count-1 do begin
MapBottomUp(Node[i]); // recursive MapBottomUp(Node[i]); // recursive
if BestSite=nil then if BestSite=nil then
BestSite:=TreeNameToDocker[Node[i].Name]; BestSite:=fTreeNameToDocker[Node[i].Name];
end; end;
if (TreeNameToDocker[Node.Name]=nil) and (BestSite<>nil) then begin if (fTreeNameToDocker[Node.Name]=nil) and (BestSite<>nil) then begin
// search the parent site of a child site // search the parent site of a child site
repeat repeat
BestSite:=BestSite.Parent; BestSite:=BestSite.Parent;
if BestSite is TAnchorDockHostSite then begin if BestSite is TAnchorDockHostSite then begin
if TreeNameToDocker.ControlToName(BestSite)='' then if fTreeNameToDocker.ControlToName(BestSite)='' then
TreeNameToDocker[Node.Name]:=BestSite; fTreeNameToDocker[Node.Name]:=BestSite;
break; break;
end; end;
until (BestSite=nil); until (BestSite=nil);
@ -722,7 +720,7 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
if Node.Parent=nil then exit; if Node.Parent=nil then exit;
// node is a child node // node is a child node
Site:=TreeNameToDocker[Node.Name]; Site:=fTreeNameToDocker[Node.Name];
if Site=nil then exit; if Site=nil then exit;
// node is mapped to a site // node is mapped to a site
// check each side // check each side
@ -731,14 +729,14 @@ procedure TAnchorDockMaster.MapTreeToControls(Tree: TAnchorDockLayoutTree;
SplitterNode:=Node.Parent.FindChildNode(Node.Anchors[Side],false); SplitterNode:=Node.Parent.FindChildNode(Node.Anchors[Side],false);
if (SplitterNode=nil) then continue; if (SplitterNode=nil) then continue;
// this side of node is anchored to a splitter node // this side of node is anchored to a splitter node
if TreeNameToDocker[SplitterNode.Name]<>nil then continue; if fTreeNameToDocker[SplitterNode.Name]<>nil then continue;
// the splitter node is not yet mapped // the splitter node is not yet mapped
Splitter:=Site.AnchorSide[Side].Control; Splitter:=Site.AnchorSide[Side].Control;
if (not (Splitter is TAnchorDockSplitter)) if (not (Splitter is TAnchorDockSplitter))
or (Splitter.Parent<>Site.Parent) then continue; or (Splitter.Parent<>Site.Parent) then continue;
// there is an unmapped splitter anchored to the Site // there is an unmapped splitter anchored to the Site
// => map the splitter to the splitter node // => map the splitter to the splitter node
TreeNameToDocker[Splitter.Name]:=Splitter; fTreeNameToDocker[Splitter.Name]:=Splitter;
end; end;
end; end;
@ -749,8 +747,7 @@ begin
MapSplitters(Tree.Root); MapSplitters(Tree.Root);
end; end;
function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree; function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree): boolean;
TreeNameToDocker: TADNameToControl): boolean;
procedure SetupSite(Site: TCustomForm; procedure SetupSite(Site: TCustomForm;
Node: TAnchorDockLayoutTreeNode; Parent: TWinControl); Node: TAnchorDockLayoutTreeNode; Parent: TWinControl);
@ -827,10 +824,10 @@ function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree;
end; end;
end else if Node.IsSplitter then begin end else if Node.IsSplitter then begin
// restore splitter // restore splitter
Splitter:=TAnchorDockSplitter(TreeNameToDocker[Node.Name]); Splitter:=TAnchorDockSplitter(fTreeNameToDocker[Node.Name]);
if Splitter=nil then begin if Splitter=nil then begin
Splitter:=CreateSplitter; Splitter:=CreateSplitter;
TreeNameToDocker[Node.Name]:=Splitter; fTreeNameToDocker[Node.Name]:=Splitter;
end; end;
debugln(['Restore Splitter Node.Name=',Node.Name,' ',dbgs(Node.NodeType),' Splitter=',DbgSName(Splitter)]); debugln(['Restore Splitter Node.Name=',Node.Name,' ',dbgs(Node.NodeType),' Splitter=',DbgSName(Splitter)]);
Splitter.Parent:=Parent; Splitter.Parent:=Parent;
@ -842,11 +839,11 @@ function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree;
Result:=Splitter; Result:=Splitter;
end else if Node.NodeType=adltnLayout then begin end else if Node.NodeType=adltnLayout then begin
// restore layout // restore layout
Site:=TAnchorDockHostSite(TreeNameToDocker[Node.Name]); Site:=TAnchorDockHostSite(fTreeNameToDocker[Node.Name]);
if Site=nil then begin if Site=nil then begin
Site:=CreateSite('',true); Site:=CreateSite('',true);
fDisabledAutosizing.Add(Site); fDisabledAutosizing.Add(Site);
TreeNameToDocker[Node.Name]:=Site; fTreeNameToDocker[Node.Name]:=Site;
end; end;
debugln(['Restore Layout Node.Name=',Node.Name,' ChildCount=',Node.Count]); debugln(['Restore Layout Node.Name=',Node.Name,' ChildCount=',Node.Count]);
Site.BeginUpdateLayout; Site.BeginUpdateLayout;
@ -860,7 +857,7 @@ function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree;
// anchor children // anchor children
for i:=0 to Node.Count-1 do begin for i:=0 to Node.Count-1 do begin
ChildNode:=Node[i]; ChildNode:=Node[i];
AControl:=TreeNameToDocker[ChildNode.Name]; AControl:=fTreeNameToDocker[ChildNode.Name];
debugln([' Restore layout child anchors Site=',DbgSName(Site),' ChildNode.Name=',ChildNode.Name,' Control=',DbgSName(AControl)]); debugln([' Restore layout child anchors Site=',DbgSName(Site),' ChildNode.Name=',ChildNode.Name,' Control=',DbgSName(AControl)]);
if AControl=nil then continue; if AControl=nil then continue;
for Side:=Low(TAnchorKind) to high(TAnchorKind) do begin for Side:=Low(TAnchorKind) to high(TAnchorKind) do begin
@ -871,7 +868,7 @@ function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree;
then continue; then continue;
AnchorControl:=nil; AnchorControl:=nil;
if ChildNode.Anchors[Side]<>'' then if ChildNode.Anchors[Side]<>'' then
AnchorControl:=TreeNameToDocker[ChildNode.Anchors[Side]]; AnchorControl:=fTreeNameToDocker[ChildNode.Anchors[Side]];
if AnchorControl<>nil then if AnchorControl<>nil then
AControl.AnchorToNeighbour(Side,0,AnchorControl) AControl.AnchorToNeighbour(Side,0,AnchorControl)
else else
@ -884,11 +881,11 @@ function TAnchorDockMaster.RestoreLayout(Tree: TAnchorDockLayoutTree;
Result:=Site; Result:=Site;
end else if Node.NodeType=adltnPages then begin end else if Node.NodeType=adltnPages then begin
// restore pages // restore pages
Site:=TAnchorDockHostSite(TreeNameToDocker[Node.Name]); Site:=TAnchorDockHostSite(fTreeNameToDocker[Node.Name]);
if Site=nil then begin if Site=nil then begin
Site:=CreateSite('',true); Site:=CreateSite('',true);
fDisabledAutosizing.Add(Site); fDisabledAutosizing.Add(Site);
TreeNameToDocker[Node.Name]:=Site; fTreeNameToDocker[Node.Name]:=Site;
end; end;
Site.BeginUpdateLayout; Site.BeginUpdateLayout;
try try
@ -985,6 +982,7 @@ begin
fNeedSimplify.Remove(AControl); fNeedSimplify.Remove(AControl);
fNeedFree.Remove(AControl); fNeedFree.Remove(AControl);
fDisabledAutosizing.Remove(AControl); fDisabledAutosizing.Remove(AControl);
if fTreeNameToDocker<>nil then fTreeNameToDocker.RemoveControl(AControl);
end; end;
end; end;
end; end;
@ -1012,6 +1010,7 @@ destructor TAnchorDockMaster.Destroy;
var var
AControl: TControl; AControl: TControl;
begin begin
FreeAndNil(fTreeNameToDocker);
if FControls.Count>0 then begin if FControls.Count>0 then begin
while ControlCount>0 do begin while ControlCount>0 do begin
AControl:=Controls[ControlCount-1]; AControl:=Controls[ControlCount-1];
@ -1262,11 +1261,10 @@ function TAnchorDockMaster.LoadLayoutFromConfig(Config: TConfigStorage): Boolean
var var
Tree: TAnchorDockLayoutTree; Tree: TAnchorDockLayoutTree;
ControlNames: TStringList; ControlNames: TStringList;
TreeNameToDocker: TADNameToControl;
begin begin
Result:=false; Result:=false;
ControlNames:=TStringList.Create; ControlNames:=TStringList.Create;
TreeNameToDocker:=TADNameToControl.Create; fTreeNameToDocker:=TADNameToControl.Create;
Tree:=TAnchorDockLayoutTree.Create; Tree:=TAnchorDockLayoutTree.Create;
try try
// load tree // load tree
@ -1292,17 +1290,17 @@ begin
Tree.Root.Simplify(ControlNames); Tree.Root.Simplify(ControlNames);
// reuse existing sites to reduce flickering // reuse existing sites to reduce flickering
MapTreeToControls(Tree,TreeNameToDocker); MapTreeToControls(Tree);
TreeNameToDocker.WriteDebugReport('TAnchorDockMaster.LoadLayoutFromConfig Map'); fTreeNameToDocker.WriteDebugReport('TAnchorDockMaster.LoadLayoutFromConfig Map');
// create sites // create sites
RestoreLayout(Tree,TreeNameToDocker); RestoreLayout(Tree);
finally finally
EndUpdate; EndUpdate;
end; end;
finally finally
// clean up // clean up
TreeNameToDocker.Free; FreeAndNil(fTreeNameToDocker);
ControlNames.Free; ControlNames.Free;
Tree.Free; Tree.Free;
// commit (this can raise an exception) // commit (this can raise an exception)
@ -2770,6 +2768,7 @@ begin
Result:=CloseQuery; Result:=CloseQuery;
if not Result then exit; if not Result then exit;
DisableAutoSizing;
case SiteType of case SiteType of
adhstNone: adhstNone:
Release; Release;
@ -2806,8 +2805,11 @@ begin
Release; Release;
AControl.Visible:=false; AControl.Visible:=false;
end; end;
Visible:=false;
Parent:=nil;
end; end;
end; end;
EnableAutoSizing;
end; end;
procedure TAnchorDockHostSite.RemoveControl(AControl: TControl); procedure TAnchorDockHostSite.RemoveControl(AControl: TControl);

View File

@ -193,6 +193,7 @@ type
destructor Destroy; override; destructor Destroy; override;
function ControlToName(AControl: TControl): string; function ControlToName(AControl: TControl): string;
property Control[const aName: string]: TControl read GetControl write SetControl; default; property Control[const aName: string]: TControl read GetControl write SetControl; default;
procedure RemoveControl(AControl: TControl);
procedure WriteDebugReport(Msg: string); procedure WriteDebugReport(Msg: string);
end; end;
@ -1595,6 +1596,18 @@ begin
Result:=''; Result:='';
end; end;
procedure TADNameToControl.RemoveControl(AControl: TControl);
var
i: Integer;
begin
i:=fItems.Count-1;
while i>=0 do begin
if fItems.Objects[i]=AControl then
fItems.Delete(i);
dec(i);
end;
end;
procedure TADNameToControl.WriteDebugReport(Msg: string); procedure TADNameToControl.WriteDebugReport(Msg: string);
var var
i: Integer; i: Integer;