dockmanager example: workarounds for HostDockSite mishandling

git-svn-id: trunk@22972 -
This commit is contained in:
dodi 2009-12-05 05:36:54 +00:00
parent 1eb2d6cc7f
commit 82643dcee2
3 changed files with 186 additions and 23 deletions

View File

@ -962,6 +962,8 @@ type
var
ZoneRec: RZone;
ZoneName: string;
const
BookZoneName: string = '*';
procedure TEasyTree.SaveToStream(Stream: TStream);
@ -976,8 +978,18 @@ procedure TEasyTree.SaveToStream(Stream: TStream);
child := Zone.ChildControl;
if child = nil then
ZoneName := ''
else
ZoneName := child.Name;
{$IFDEF new}
else if child is TEasyDockBook then begin
ZoneName := BookZoneName;
ZoneName := TEasyDockBook(child).GetDockCaption(child)
//ZoneName := TWinControlAccess(child).GetDockCaption(child); // BookZoneName
end
{$ELSE}
{$ENDIF}
else begin
//ZoneName := child.Name;
ZoneName := DockSite.GetDockCaption(child); //default to child.Name
end;
ZoneRec.NameLen := Length(ZoneName);
//write descriptor
Stream.Write(ZoneRec, sizeof(ZoneRec));
@ -1005,9 +1017,22 @@ begin
end;
function TEasyTree.ReloadDockedControl(const AName: string): TControl;
{$IFDEF new}
var
nb: TEasyBook;
begin
TWinControlAccess(DockSite).ReloadDockedControl(ZoneName, Result);
if Pos(',', AName) > 0 then begin
nb := NoteBookCreate(FDockSite);
nb.SetDockCaption(AName);
Result := nb;
end else begin
TWinControlAccess(DockSite).ReloadDockedControl(ZoneName???, Result);
end;
{$ELSE}
begin
TWinControlAccess(DockSite).ReloadDockedControl(AName, Result);
end;
{$ENDIF}
procedure TEasyTree.LoadFromStream(Stream: TStream);
@ -1028,6 +1053,17 @@ procedure TEasyTree.LoadFromStream(Stream: TStream);
DebugLn('reload done');
end;
procedure ClearSite;
var
i: integer;
ctl: TControl;
begin
for i := FDockSite.DockClientCount - 1 downto 0 do begin
ctl := FDockSite.DockClients[i];
ctl.ManualDock(nil);
end;
end;
procedure MakeZones;
var
PrevZone, NewZone: TEasyZone;
@ -1046,31 +1082,31 @@ procedure TEasyTree.LoadFromStream(Stream: TStream);
NewCtl := ReloadDockedControl(ZoneName);
//do we need a control in any case?
if NewCtl = nil then begin
//debug: create some control
NewCtl := TPanel.Create(DockSite);
NewCtl.Name := ZoneName;
end;
{$IFDEF old}
try
DebugLn('try rename %s into %s', [NewCtl.Name, ZoneName]);
NewCtl.Name := ZoneName;
if NewCtl is TEasyBook then
//TEasyBook(NewCtl).SetDockCaption(ZoneName)
DebugLn('!!!DockBook!!!')
else
NewCtl.Name := ZoneName;
except
DebugLn('error rename');
end;
NewCtl.Caption := ZoneName;
{$ELSE}
{$ENDIF}
if NewCtl <> nil then begin
{$IFDEF old}
NewCtl.Align := alNone;
NewCtl.Visible := True;
NewCtl.Parent := DockSite;
NewCtl.Width := ZoneRec.BottomRight.x;
NewCtl.Height := ZoneRec.BottomRight.y;
NewZone.ChildControl := NewCtl;
{$ELSE}
NewCtl.Visible := True;
NewZone.ChildControl := NewCtl;
SetReplacingControl(NewCtl);
NewCtl.ManualDock(DockSite);
NewCtl.Width := ZoneRec.BottomRight.x;
NewCtl.Height := ZoneRec.BottomRight.y;
{$ENDIF}
end;
end;
while NewLvl < PrevLvl do begin
@ -1090,6 +1126,8 @@ procedure TEasyTree.LoadFromStream(Stream: TStream);
end;
begin
//remove all docked controls
ClearSite;
//read record
if GetRec > 0 then begin
FTopZone.BR := ZoneRec.BottomRight;

View File

@ -108,6 +108,11 @@ type
function GetControlTab(AControl: TControl): TTabButton;
public
StayDocked: boolean;
destructor Destroy; override;
{$IFDEF new}
procedure SetDockCaption(const AName: string);
{$ELSE}
{$ENDIF}
end;
//procedure Register;
@ -129,6 +134,32 @@ end;
{ TEasyDockBook }
destructor TEasyDockBook.Destroy;
var
i: integer;
ctl: TControl;
begin
(* Problem with undocking?
The DockClients are not properly undocked when we (HostDockSite) are destroyed :-(
This code prevents an error when the DockClients are docked later,
by definitely undocking all clients.
But then the bug will strike back when the notebook is destroyed at the
end of the application.
Fix: check ctl.ComponentState for csDestroying.
*)
for i := DockClientCount - 1 downto 0 do begin
ctl := DockClients[i];
if not (csDestroying in ctl.ComponentState) then
ctl.ManualDock(nil);
DebugLn('Undocked %s P=%p H=%p', [ctl.Name,
pointer(ctl.Parent), pointer(ctl.HostDockSite)]);
end;
inherited Destroy;
end;
procedure TEasyDockBook.FormClose(Sender: TObject;
var CloseAction: TCloseAction);
var
@ -149,9 +180,9 @@ begin
ctl.ManualDock(nil);
DebugLn('Undocked %s P=%p H=%p', [ctl.Name,
pointer(ctl.Parent), pointer(ctl.HostDockSite)]);
if ctl is TCustomForm then begin
//if ctl is TCustomForm then begin
//frm.Close;
end;
//end;
end;
//EndFormUpdate;
{$ELSE}
@ -310,6 +341,28 @@ begin
end;
end;
{$IFDEF new}
procedure TEasyDockBook.SetDockCaption(const AName: string);
var
lst: TStringList;
i: integer;
s: string;
ctl: TControl;
begin
lst := TStringList.Create;
lst.CommaText := AName;
for i := 0 to lst.Count - 1 do begin
s := lst.Strings[i];
ReloadDockedControl(s, ctl);
if ctl <> nil then begin
ctl.Name := s;
ctl.ManualDock(self, nil, alCustom);
end;
end;
end;
{$ELSE}
{$ENDIF}
procedure TEasyDockBook.ToolButton1Click(Sender: TObject);
var
btn: TTabButton absolute Sender;

View File

@ -76,12 +76,14 @@ type
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AddElasticSites(AForm: TCustomForm; Sides: sDockSides);
//function CreateDockable(const AName: string; site: TWinControl; fMultiInst: boolean; fWrap: boolean = True): TWinControl;
function CreateDockable(const AName: string; fMultiInst: boolean; fWrap: boolean = True): TWinControl;
function MakeDockable(AForm: TWinControl; fWrap: boolean = True): TForm;
procedure DumpSites;
//persistence
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
function ReloadDockedControl(const AName: string; Site: TWinControl): TControl;
end;
function TryRename(AComp: TComponent; const NewName: string): boolean;
@ -210,21 +212,38 @@ begin
end;
end;
//function TDockMaster.CreateDockable(const AName: string; site: TWinControl;
function TDockMaster.CreateDockable(const AName: string;
fMultiInst: boolean; fWrap: boolean): TWinControl;
var
nb: TEasyBook;
begin
(* Create a dockable form, based on its name.
Used also to restore a layout.
Not now:
Used also to restore a DockBook (AName contains ",")
(second chance, after LoadFromStream)
Options (to come or to be removed)
fMultiInst allows to auto-create new instances (if True),
otherwise an already existing instance is returned. (really returned?)
*)
//get the form
Result := ReloadForm(AName, fMultiInst);
if Result = nil then
exit;
MakeDockable(Result, fWrap);
{$IFDEF new}
if Pos(',', AName) > 0 then begin
nb := NoteBookCreate(site); //DockSite???
nb.SetDockCaption(AName);
Result := nb;
end else
{$ELSE}
{$ENDIF}
begin
//get the form
Result := ReloadForm(AName, fMultiInst);
if Result = nil then
exit;
MakeDockable(Result, fWrap);
end;
end;
function TDockMaster.MakeDockable(AForm: TWinControl; fWrap: boolean): TForm;
@ -285,6 +304,52 @@ begin
img.BringToFront;
end;
function TDockMaster.ReloadDockedControl(const AName: string;
Site: TWinControl): TControl;
var
i: integer;
lst: TStringList;
nb: TEasyBook absolute Result;
s: string;
ctl: TControl;
//se: TSynEdit;
begin
(* Reload docked controls - forms or NoteBook
NoteBook identified by comma separated names in AName,
FileEditor identified by dot in name.
*)
if Pos(',', AName) > 0 then begin
//restore NoteBook
nb := NoteBookCreate(Site);
lst := TStringList.Create;
try
lst.CommaText := AName;
for i := 0 to lst.Count - 1 do begin
s := lst[i];
if Pos('.', s) > 0 then begin
//restore editor
{ TODO -cdocking : restore editor for file }
end else begin
ctl := ReloadForm(s, True); //try both multi and single instance
if ctl <> nil then
try
ctl.ManualDock(nb);
except
DebugLn('!!!error docking ', s);
{ TODO 1 : There exists a bug in the destruction of fDockBook (TWinControl).
The docked clients retain the HostDockSite - which becomes invalid when destroyed! }
end;
end;
end;
finally
lst.Free;
end;
end else begin
//restore control (form?)
Result := ReloadForm(AName, True);
end;
end;
procedure TDockMaster.FormEndDock(Sender, Target: TObject; X, Y: Integer);
var
ctl: TControl;
@ -880,13 +945,20 @@ end;
function TAppDockManager.ReloadDockedControl(const AName: string): TControl;
begin
(* Special connect to DockManager, and restore NoteBooks.
*)
if False then
Result:=inherited ReloadDockedControl(AName); //asking DockSite (very bad idea)
if assigned(DockMaster) then begin
Result := DockMaster.CreateDockable(AName, True, False);
end else begin
//Result := DockMaster.CreateDockable(AName, FDockSite, True, False);
//Result := DockMaster.CreateDockable(AName, True, False);
Result := DockMaster.ReloadDockedControl(AName, FDockSite);
end else begin //application default - search Application or Screen?
//Owner.FindComponent(AControlName) as TControl;
Result := Application.FindComponent(AName) as TControl;
//Result := Application.FindComponent(AName) as TControl;
Result := Screen.FindForm(AName);
//if Result = nil then Result := 'T' + AName
{ TODO -cdocking : load form by name, or create from typename }
end;
if Result <> nil then
DebugLn('Reloaded %s.%s', [Result.Owner.Name, Result.Name]);