View Issue Details

IDProjectCategoryView StatusLast Update
0031238LazarusFCLpublic2017-11-16 09:01
ReporterValdas JankūnasAssigned ToMichl 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Platformlinux 64 bit; KDE; Kubuntu 16.10OSOS Version
Product Version1.7 (SVN)Product Build53931 
Target VersionFixed in Version1.9 (SVN) 
Summary0031238: [AnchorDocking] Faulty LoadLayoutFromConfig when used second time
Description Try slightly modified (disabled autocreation of secondary forms) "MiniIDE" example from "anchordocking" directory"
 - try to load "01.xml" and then "02.xml" from example folder: you will get error message "ChangeBouds loop detected" (see attached pic "load_01_then_02.jpg");
 - restart example, then load "02.xml" and then "01.xml": you will get destroyed layout (see attached pic "load_02_then_01.jpg"); and you cant open "Src editor 1" nor "Src editor 2" windows from "MiniIDE" menu.
TagsNo tags attached.
Fixed in Revision55921
LazTarget-
Widgetset
Attached Files
  • minide_test.zip (90,725 bytes)
  • load_01_then_02.jpg (388,240 bytes)
  • load_02_then_01.jpg (346,532 bytes)
  • anchordocking-parentsidentical-with-fix.pas.patch (1,897 bytes)
    Index: components/anchordocking/anchordocking.pas
    ===================================================================
    --- components/anchordocking/anchordocking.pas	(revision 55731)
    +++ components/anchordocking/anchordocking.pas	(working copy)
    @@ -1478,13 +1478,39 @@
     var
       i: Integer;
       AControl: TControl;
    +  TreeNodeControl: TAnchorDockLayoutTreeNode;
    +
    +  function ParentsIdentical: Boolean;
    +  var
    +    ParentForm: TCustomForm;
    +    ParentAnchorDockLayoutTreeNode: TAnchorDockLayoutTreeNode;
    +    Parent1, Parent2: String;
    +  begin
    +    ParentForm := GetParentForm(AControl, True);
    +    if Assigned(ParentForm) then
    +      Parent1 := ParentForm.Name
    +    else
    +      Parent1 := '';
    +
    +    Parent2 := '';
    +    ParentAnchorDockLayoutTreeNode := TreeNodeControl;
    +    while Assigned(ParentAnchorDockLayoutTreeNode.Parent) do begin
    +      Parent2 := ParentAnchorDockLayoutTreeNode.Name;
    +      ParentAnchorDockLayoutTreeNode := ParentAnchorDockLayoutTreeNode.Parent;
    +    end;
    +    Result := Parent1 = Parent2;
    +
    +//    DebugLn('TAnchorDockMaster.ParentsIdentical [', Parent1, '] [', Parent2, ']');
    +  end;
    +
     begin
       i:=ControlCount-1;
       while i>=0 do begin
         AControl:=Controls[i];
    +    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
         if DockedControlIsVisible(AControl)
    -    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
    -    and (Application.MainForm<>AControl) then begin
    +    {and (Application.MainForm<>AControl)
    +    and ((TreeNodeControl=nil) or not ParentsIdentical)} then begin
           DisableControlAutoSizing(AControl);
           // AControl is currently on a visible site, but not in the Tree
           // => close site
    @@ -1770,6 +1796,7 @@
       aMonitor: TMonitor;
       aHostSite: TAnchorDockHostSite;
     begin
    +  Site.Align:=alNone;
       if Site is TCustomForm then begin
         if AParent=nil then
           TCustomForm(Site).WindowState:=ANode.WindowState
    
  • anchordocking-add_controllocation.patch (3,821 bytes)
    Index: components/anchordocking/anchordocking.pas
    ===================================================================
    --- components/anchordocking/anchordocking.pas	(revision 55731)
    +++ components/anchordocking/anchordocking.pas	(working copy)
    @@ -524,7 +524,7 @@
     
         function GetControls(Index: integer): TControl;
         function GetLocalizedHeaderHint: string;
    -    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
    +    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
         function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                     DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
         function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
    @@ -1473,18 +1473,21 @@
       OptionsChanged;
     end;
     
    -function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
    +function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
       ): boolean;
     var
       i: Integer;
       AControl: TControl;
    +  TreeNodeControl: TAnchorDockLayoutTreeNode;
     begin
       i:=ControlCount-1;
       while i>=0 do begin
         AControl:=Controls[i];
    +    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
         if DockedControlIsVisible(AControl)
    -    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
    -    and (Application.MainForm<>AControl) then begin
    +    and (Application.MainForm<>AControl)
    +    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
    +    or (TreeNodeControl.ControlLocation=adlclwrongly)) then begin
           DisableControlAutoSizing(AControl);
           // AControl is currently on a visible site, but not in the Tree
           // => close site
    @@ -1770,6 +1773,7 @@
       aMonitor: TMonitor;
       aHostSite: TAnchorDockHostSite;
     begin
    +  Site.Align:=alNone;
       if Site is TCustomForm then begin
         if AParent=nil then
           TCustomForm(Site).WindowState:=ANode.WindowState
    @@ -2159,7 +2163,7 @@
       fTreeNameToDocker:=TADNameToControl.Create;
       try
         // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    @@ -3043,7 +3047,7 @@
         {$ENDIF}
     
         // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    Index: components/anchordocking/anchordockstorage.pas
    ===================================================================
    --- components/anchordocking/anchordockstorage.pas	(revision 55731)
    +++ components/anchordocking/anchordockstorage.pas	(working copy)
    @@ -60,6 +60,11 @@
         adlhpRight,
         adlhpBottom
         );
    +
    +  TADLControlLocation = (
    +    adlclwrongly,
    +    adlclcorrect
    +    );
       TADLHeaderPositions = set of TADLHeaderPosition;
     
       EAnchorDockLayoutError = class(Exception);
    @@ -81,6 +86,7 @@
         FWorkAreaRect: TRect;
         FTabPosition: TTabPosition;
         FWindowState: TWindowState;
    +    FControlLocation: TADLControlLocation;
         function GetAnchors(Site: TAnchorKind): string;
         function GetBottom: integer;
         function GetHeight: integer;
    @@ -156,6 +162,7 @@
         function IsSplitter: boolean;
         function IsRootWindow: boolean;
         property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
    +    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
       end;
     
       TAnchorDockLayoutTree = class;
    @@ -1028,6 +1035,7 @@
     constructor TAnchorDockLayoutTreeNode.Create;
     begin
       FNodes:=TFPList.Create;
    +  FControlLocation:=adlclwrongly;//control located wrongly by default
     end;
     
     destructor TAnchorDockLayoutTreeNode.Destroy;
    
  • anchordocking-add_controllocation_v2.patch (3,855 bytes)
    Index: components/anchordocking/anchordocking.pas
    ===================================================================
    --- components/anchordocking/anchordocking.pas	(revision 55731)
    +++ components/anchordocking/anchordocking.pas	(working copy)
    @@ -524,7 +524,7 @@
     
         function GetControls(Index: integer): TControl;
         function GetLocalizedHeaderHint: string;
    -    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
    +    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
         function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                     DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
         function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
    @@ -1473,18 +1473,22 @@
       OptionsChanged;
     end;
     
    -function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
    +function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
       ): boolean;
     var
       i: Integer;
       AControl: TControl;
    +  TreeNodeControl: TAnchorDockLayoutTreeNode;
     begin
       i:=ControlCount-1;
       while i>=0 do begin
         AControl:=Controls[i];
    +    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
         if DockedControlIsVisible(AControl)
    -    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
    -    and (Application.MainForm<>AControl) then begin
    +    and (Application.MainForm<>AControl)
    +    and (not(AControl is TAnchorDockPanel))
    +    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
    +    or (TreeNodeControl.ControlLocation=adlclwrongly)) then begin
           DisableControlAutoSizing(AControl);
           // AControl is currently on a visible site, but not in the Tree
           // => close site
    @@ -1771,6 +1775,7 @@
       aHostSite: TAnchorDockHostSite;
     begin
       if Site is TCustomForm then begin
    +    Site.Align:=alNone;
         if AParent=nil then
           TCustomForm(Site).WindowState:=ANode.WindowState
         else
    @@ -2159,7 +2164,7 @@
       fTreeNameToDocker:=TADNameToControl.Create;
       try
         // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    @@ -3043,7 +3048,7 @@
         {$ENDIF}
     
         // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    Index: components/anchordocking/anchordockstorage.pas
    ===================================================================
    --- components/anchordocking/anchordockstorage.pas	(revision 55731)
    +++ components/anchordocking/anchordockstorage.pas	(working copy)
    @@ -60,6 +60,11 @@
         adlhpRight,
         adlhpBottom
         );
    +
    +  TADLControlLocation = (
    +    adlclwrongly,
    +    adlclcorrect
    +    );
       TADLHeaderPositions = set of TADLHeaderPosition;
     
       EAnchorDockLayoutError = class(Exception);
    @@ -81,6 +86,7 @@
         FWorkAreaRect: TRect;
         FTabPosition: TTabPosition;
         FWindowState: TWindowState;
    +    FControlLocation: TADLControlLocation;
         function GetAnchors(Site: TAnchorKind): string;
         function GetBottom: integer;
         function GetHeight: integer;
    @@ -156,6 +162,7 @@
         function IsSplitter: boolean;
         function IsRootWindow: boolean;
         property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
    +    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
       end;
     
       TAnchorDockLayoutTree = class;
    @@ -1028,6 +1035,7 @@
     constructor TAnchorDockLayoutTreeNode.Create;
     begin
       FNodes:=TFPList.Create;
    +  FControlLocation:=adlclwrongly;//control located wrongly by default
     end;
     
     destructor TAnchorDockLayoutTreeNode.Destroy;
    
  • anchordocking-add_controllocation_v3.patch (7,841 bytes)
    Index: components/anchordocking/anchordocking.pas
    ===================================================================
    --- components/anchordocking/anchordocking.pas	(revision 55731)
    +++ components/anchordocking/anchordocking.pas	(working copy)
    @@ -524,7 +524,8 @@
     
         function GetControls(Index: integer): TControl;
         function GetLocalizedHeaderHint: string;
    -    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
    +    procedure MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
    +    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
         function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                     DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
         function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
    @@ -1473,18 +1474,126 @@
       OptionsChanged;
     end;
     
    -function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
    +procedure TAnchorDockMaster.MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
    +var
    +  Counter:integer;
    +
    +  function GetRealParent(Node:TAnchorDockLayoutTreeNode):TAnchorDockLayoutTreeNode;
    +  begin
    +    result := Node;
    +    while Assigned(result.Parent) do begin
    +      result := result.Parent;
    +      fTreeNameToDocker[Node.Name];
    +      if result.NodeType in [adltnControl,adltnCustomSite] then exit
    +    end;
    +  end;
    +
    +  function GetDockParent(Control: TControl): TControl;
    +  begin
    +    Control := Control.Parent;
    +    while (Control <> nil) and (Control.Parent <> nil) do
    +    begin
    +      if not (Control is TAnchorDockHostSite) then
    +        Break;
    +      Control := Control.Parent;
    +    end;
    +    Result := Control;
    +  end;
    +
    +  procedure RealChildrenCount(AWinControl:twincontrol;var realsubcontrolcoun:integer);
    +  var
    +    i:integer;
    +    ACountedControl:tcontrol;
    +  begin
    +     for i:=0 to AWinControl.ControlCount-1 do
    +       begin
    +         ACountedControl:=AWinControl.Controls[i];
    +         if not (ACountedControl is TAnchorDockHostSite) then
    +         if not (ACountedControl is TAnchorDockHeader) then
    +         if not (ACountedControl is TAnchorDockPageControl) then
    +         if ACountedControl.IsVisible then
    +           inc(realsubcontrolcoun);
    +         if ACountedControl is TAnchorDockHostSite then
    +         if ACountedControl.IsVisible then
    +           RealChildrenCount(ACountedControl as TWinControl, realsubcontrolcoun);
    +       end;
    +  end;
    +
    +  function CheckNode(Node: TAnchorDockLayoutTreeNode; var ControlsCount: integer):TADLControlLocation;
    +  var
    +    i: Integer;
    +    AControl,AParent: TControl;
    +    SubControlsCount,realsubcontrolcoun: integer;
    +  begin
    +    if Node.IsSplitter then begin
    +      inc(ControlsCount);
    +      exit(adlclCorrect);
    +    end
    +    else if Node=Tree.Root then begin
    +      result:=adlclCorrect;
    +      AControl:=nil;
    +      AParent:=nil;
    +    end
    +    else begin
    +      AControl:=FindControl(Node.Name);
    +      AParent:=FindControl(GetRealParent(Node).Name);
    +      if Node.NodeType=adltnLayout then result:=adlclCorrect
    +      else if AControl is TAnchorDockPanel then result:=adlclCorrect
    +      else if AControl=nil then result:=adlclWrongly
    +      else if GetDockParent(AControl)<>AParent then result:=adlclWrongly
    +      else
    +      begin
    +      end;
    +    end;
    +    if AControl<>nil then
    +    if not (AControl is TAnchorDockHostSite) then
    +     inc(ControlsCount);
    +    if result=adlclWrongly then exit;
    +    if AControl=nil then AControl:=AParent;
    +    SubControlsCount:=0;
    +    for i:=0 to Node.Count-1 do
    +    begin
    +      result:=CheckNode(Node[i],SubControlsCount);
    +      if result=adlclWrongly then exit;
    +    end;
    +    realsubcontrolcoun:=0;
    +    if (AControl is TAnchorDockHostSite)or(AControl is TAnchorDockPanel) then
    +    begin
    +       RealChildrenCount(AControl as TWinControl,realsubcontrolcoun);
    +       if SubControlsCount<>realsubcontrolcoun then Exit(adlclWrongly);
    +    end;
    +    ControlsCount:=ControlsCount+SubControlsCount;
    +    if result=adlclWrongly then exit;
    +    for i:=0 to Node.Count-1 do
    +    begin
    +      Node[i].ControlLocation:=adlclCorrect;
    +    end;
    +  end;
    +
    +begin
    +  //We need compare dock tree and fact controls placement
    +  //and mark controls which location is coincides with tree
    +  //these controls can be not closrd in CloseUnneededAndWronglyLocatedControls
    +  Counter:=0;
    +  Tree.Root.ControlLocation:=CheckNode(Tree.Root,Counter);
    +end;
    +
    +function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
       ): boolean;
     var
       i: Integer;
       AControl: TControl;
    +  TreeNodeControl: TAnchorDockLayoutTreeNode;
     begin
       i:=ControlCount-1;
       while i>=0 do begin
         AControl:=Controls[i];
    +    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
         if DockedControlIsVisible(AControl)
    -    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
    -    and (Application.MainForm<>AControl) then begin
    +    and (Application.MainForm<>AControl)
    +    and (not(AControl is TAnchorDockPanel))
    +    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
    +    or (TreeNodeControl.ControlLocation=adlclWrongly)) then begin
           DisableControlAutoSizing(AControl);
           // AControl is currently on a visible site, but not in the Tree
           // => close site
    @@ -1771,6 +1880,7 @@
       aHostSite: TAnchorDockHostSite;
     begin
       if Site is TCustomForm then begin
    +    Site.Align:=alNone;
         if AParent=nil then
           TCustomForm(Site).WindowState:=ANode.WindowState
         else
    @@ -2158,9 +2268,11 @@
       ControlNames:=TStringList.Create;
       fTreeNameToDocker:=TADNameToControl.Create;
       try
    -    // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
     
    +    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
    +    MarkCorrectlyLocatedControl(Tree);
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
    +
         BeginUpdate;
         try
           // create all needed forms/controls (not helper controls like splitters)
    @@ -3042,8 +3154,9 @@
         DebugWriteChildAnchors(Tree.Root);
         {$ENDIF}
     
    -    // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
    +    MarkCorrectlyLocatedControl(Tree);
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    Index: components/anchordocking/anchordockstorage.pas
    ===================================================================
    --- components/anchordocking/anchordockstorage.pas	(revision 55731)
    +++ components/anchordocking/anchordockstorage.pas	(working copy)
    @@ -60,6 +60,11 @@
         adlhpRight,
         adlhpBottom
         );
    +
    +  TADLControlLocation = (
    +    adlclWrongly,
    +    adlclCorrect
    +    );
       TADLHeaderPositions = set of TADLHeaderPosition;
     
       EAnchorDockLayoutError = class(Exception);
    @@ -81,6 +86,7 @@
         FWorkAreaRect: TRect;
         FTabPosition: TTabPosition;
         FWindowState: TWindowState;
    +    FControlLocation: TADLControlLocation;
         function GetAnchors(Site: TAnchorKind): string;
         function GetBottom: integer;
         function GetHeight: integer;
    @@ -156,6 +162,7 @@
         function IsSplitter: boolean;
         function IsRootWindow: boolean;
         property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
    +    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
       end;
     
       TAnchorDockLayoutTree = class;
    @@ -1028,6 +1035,7 @@
     constructor TAnchorDockLayoutTreeNode.Create;
     begin
       FNodes:=TFPList.Create;
    +  FControlLocation:=adlclwrongly;//control located wrongly by default
     end;
     
     destructor TAnchorDockLayoutTreeNode.Destroy;
    
  • layout01.xml (1,883 bytes)
  • layout02.xml (4,844 bytes)
  • anchordocking-add_controllocation_v4.patch (8,590 bytes)
    Index: components/anchordocking/anchordocking.pas
    ===================================================================
    --- components/anchordocking/anchordocking.pas	(revision 55828)
    +++ components/anchordocking/anchordocking.pas	(working copy)
    @@ -533,7 +533,8 @@
     
         function GetControls(Index: integer): TControl;
         function GetLocalizedHeaderHint: string;
    -    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
    +    procedure MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
    +    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
         function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                     DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
         function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
    @@ -1524,18 +1525,140 @@
       OptionsChanged;
     end;
     
    -function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
    +procedure TAnchorDockMaster.MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
    +var
    +  Counter:integer;
    +
    +  function GetRealParent(Node:TAnchorDockLayoutTreeNode):TAnchorDockLayoutTreeNode;
    +  begin
    +    result := Node;
    +    while Assigned(result.Parent) do begin
    +      result := result.Parent;
    +      fTreeNameToDocker[Node.Name];
    +      if result.NodeType in [adltnControl,adltnCustomSite] then exit
    +    end;
    +  end;
    +
    +  function GetDockParent(Control: TControl): TControl;
    +  begin
    +    Control := Control.Parent;
    +    while (Control <> nil) and (Control.Parent <> nil) do
    +    begin
    +      if not (Control is TAnchorDockHostSite) then
    +        Break;
    +      Control := Control.Parent;
    +    end;
    +    Result := Control;
    +  end;
    +
    +  procedure RealChildrenCount(AWinControl:twincontrol;var realsubcontrolcoun:integer);
    +  var
    +    i:integer;
    +    ACountedControl:tcontrol;
    +  begin
    +     for i:=0 to AWinControl.ControlCount-1 do
    +       begin
    +         ACountedControl:=AWinControl.Controls[i];
    +         if not (ACountedControl is TAnchorDockHostSite) then
    +         if not (ACountedControl is TAnchorDockHeader) then
    +         if not (ACountedControl is TAnchorDockPageControl) then
    +         if ACountedControl.IsVisible then
    +           inc(realsubcontrolcoun);
    +         if ACountedControl is TAnchorDockHostSite then
    +         if ACountedControl.IsVisible then
    +           RealChildrenCount(ACountedControl as TWinControl, realsubcontrolcoun);
    +       end;
    +  end;
    +
    +  function CheckNode(Node: TAnchorDockLayoutTreeNode; var ControlsCount: integer):TADLControlLocation;
    +  var
    +    i: Integer;
    +    AControl,AParent: TControl;
    +    SubControlsCount,realsubcontrolcoun: integer;
    +  begin
    +    if Node.IsSplitter then begin
    +      inc(ControlsCount);
    +      exit(adlclCorrect);
    +    end
    +    else if Node=Tree.Root then begin
    +      result:=adlclCorrect;
    +      AControl:=nil;
    +      AParent:=nil;
    +    end
    +    else begin
    +      AControl:=FindControl(Node.Name);
    +      AParent:=FindControl(GetRealParent(Node).Name);
    +      if Node.NodeType=adltnLayout then result:=adlclCorrect
    +      else if AControl is TAnchorDockPanel then result:=adlclCorrect
    +      else if AControl=nil then result:=adlclWrongly
    +      else if GetDockParent(AControl)<>AParent then result:=adlclWrongly
    +      else
    +      begin
    +      end;
    +    end;
    +    if AControl<>nil then
    +    if not (AControl is TAnchorDockHostSite) then
    +     inc(ControlsCount);
    +    if result=adlclWrongly then exit;
    +    if AControl=nil then AControl:=AParent;
    +    SubControlsCount:=0;
    +    for i:=0 to Node.Count-1 do
    +    begin
    +      result:=CheckNode(Node[i],SubControlsCount);
    +      if result=adlclWrongly then exit;
    +    end;
    +    realsubcontrolcoun:=0;
    +    if (AControl is TAnchorDockHostSite)or(AControl is TAnchorDockPanel) then
    +    begin
    +       RealChildrenCount(AControl as TWinControl,realsubcontrolcoun);
    +       if SubControlsCount<>realsubcontrolcoun then Exit(adlclWrongly);
    +    end;
    +    ControlsCount:=ControlsCount+SubControlsCount;
    +    if result=adlclWrongly then exit;
    +    for i:=0 to Node.Count-1 do
    +    begin
    +      Node[i].ControlLocation:=adlclCorrect;
    +    end;
    +  end;
    +
    +begin
    +  //We need compare dock tree and fact controls placement
    +  //and mark controls which location is coincides with tree
    +  //these controls can be not closrd in CloseUnneededAndWronglyLocatedControls
    +  Counter:=0;
    +  Tree.Root.ControlLocation:=CheckNode(Tree.Root,Counter);
    +end;
    +
    +function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
       ): boolean;
    +
    +  function GetParentAnchorDockPageControl(thisControl: TControl):TAnchorDockPageControl;
    +  begin
    +    while thisControl<>nil do
    +    begin
    +      if thisControl is TAnchorDockPageControl then
    +        exit(thisControl as TAnchorDockPageControl);
    +      thisControl:=thisControl.Parent;
    +    end;
    +    result:=nil;
    +  end;
    +
     var
       i: Integer;
       AControl: TControl;
    +  TreeNodeControl: TAnchorDockLayoutTreeNode;
    +  ParentAnchorDockPageControl:TAnchorDockPageControl;
     begin
       i:=ControlCount-1;
       while i>=0 do begin
         AControl:=Controls[i];
    +    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
         if DockedControlIsVisible(AControl)
    -    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
    -    and (Application.MainForm<>AControl) then begin
    +    and (Application.MainForm<>AControl)
    +    and (not(AControl is TAnchorDockPanel))
    +    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
    +    or (TreeNodeControl.ControlLocation=adlclWrongly)) then begin
    +      ParentAnchorDockPageControl:=GetParentAnchorDockPageControl(AControl);
           DisableControlAutoSizing(AControl);
           // AControl is currently on a visible site, but not in the Tree
           // => close site
    @@ -1561,6 +1684,9 @@
               AControl.Parent:=nil;
             end;
           end;
    +      if ParentAnchorDockPageControl<>nil then
    +        if ParentAnchorDockPageControl.Parent<>nil then
    +          ParentAnchorDockPageControl.Parent.Free;
         end;
         i:=Min(i,ControlCount)-1;
       end;
    @@ -1822,6 +1948,7 @@
       aHostSite: TAnchorDockHostSite;
     begin
       if Site is TCustomForm then begin
    +    Site.Align:=alNone;
         if AParent=nil then
           TCustomForm(Site).WindowState:=ANode.WindowState
         else
    @@ -2209,9 +2336,11 @@
       ControlNames:=TStringList.Create;
       fTreeNameToDocker:=TADNameToControl.Create;
       try
    -    // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
     
    +    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
    +    MarkCorrectlyLocatedControl(Tree);
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
    +
         BeginUpdate;
         try
           // create all needed forms/controls (not helper controls like splitters)
    @@ -3102,8 +3231,9 @@
         DebugWriteChildAnchors(Tree.Root);
         {$ENDIF}
     
    -    // close all unneeded forms/controls (not helper controls like splitters)
    -    if not CloseUnneededControls(Tree) then exit;
    +    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
    +    MarkCorrectlyLocatedControl(Tree);
    +    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
     
         BeginUpdate;
         try
    Index: components/anchordocking/anchordockstorage.pas
    ===================================================================
    --- components/anchordocking/anchordockstorage.pas	(revision 55828)
    +++ components/anchordocking/anchordockstorage.pas	(working copy)
    @@ -60,6 +60,11 @@
         adlhpRight,
         adlhpBottom
         );
    +
    +  TADLControlLocation = (
    +    adlclWrongly,
    +    adlclCorrect
    +    );
       TADLHeaderPositions = set of TADLHeaderPosition;
     
       EAnchorDockLayoutError = class(Exception);
    @@ -81,6 +86,7 @@
         FWorkAreaRect: TRect;
         FTabPosition: TTabPosition;
         FWindowState: TWindowState;
    +    FControlLocation: TADLControlLocation;
         function GetAnchors(Site: TAnchorKind): string;
         function GetBottom: integer;
         function GetHeight: integer;
    @@ -156,6 +162,7 @@
         function IsSplitter: boolean;
         function IsRootWindow: boolean;
         property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
    +    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
       end;
     
       TAnchorDockLayoutTree = class;
    @@ -1028,6 +1035,7 @@
     constructor TAnchorDockLayoutTreeNode.Create;
     begin
       FNodes:=TFPList.Create;
    +  FControlLocation:=adlclwrongly;//control located wrongly by default
     end;
     
     destructor TAnchorDockLayoutTreeNode.Destroy;
    

Relationships

related to 0029200 assignedMattias Gaertner Desktop manager restore incorrect docked layouts when layout has docked pages 
related to 0031834 resolvedMichl r54525 breaks reloading of AnchorDocking layouts 
has duplicate 0026999 closedMattias Gaertner [AnchorDocking] Wrong loading layout after loaded undocking state 
related to 0020845 closedMattias Gaertner "Tools\Load window layout from file" with AnchorDockDsgn is bugy 
related to 0032376 closedJuha Manninen [AnchorDocking] Parasitic changes sites height with TAnchorDockPanel 

Activities

Valdas Jankūnas

2017-01-16 19:01

reporter  

minide_test.zip (90,725 bytes)

Valdas Jankūnas

2017-01-16 19:01

reporter  

load_01_then_02.jpg (388,240 bytes)

Valdas Jankūnas

2017-01-16 19:01

reporter  

load_02_then_01.jpg (346,532 bytes)

Andrey Zubarev

2017-02-28 15:43

reporter   ~0098514

http://bugs.freepascal.org/view.php?id=26999
related?

Michl

2017-04-05 11:14

developer   ~0099381

Part "ChangeBounds loop detected" fixed in trunk revision 54525.

BBaz

2017-05-18 12:11

reporter   ~0100395

r54525 breaks reloading of AnchorDocking layouts in my application,
the function ParentsIdentical is the culprit. If i set the result of this function to true (always) then reloading works again.

Michl

2017-05-25 22:47

developer   ~0100684

Last edited: 2017-05-25 22:51

View 2 revisions

I reverted the workaround from revision 54525, as it breaks other layout loading. See 0031834. So we need a better solution for the "ChangeBounds loop detected" bug.

I reassign me from that issue, as I have not enough test cases for that issue.

Andrey Zubarev

2017-08-22 09:26

reporter  

anchordocking-parentsidentical-with-fix.pas.patch (1,897 bytes)
Index: components/anchordocking/anchordocking.pas
===================================================================
--- components/anchordocking/anchordocking.pas	(revision 55731)
+++ components/anchordocking/anchordocking.pas	(working copy)
@@ -1478,13 +1478,39 @@
 var
   i: Integer;
   AControl: TControl;
+  TreeNodeControl: TAnchorDockLayoutTreeNode;
+
+  function ParentsIdentical: Boolean;
+  var
+    ParentForm: TCustomForm;
+    ParentAnchorDockLayoutTreeNode: TAnchorDockLayoutTreeNode;
+    Parent1, Parent2: String;
+  begin
+    ParentForm := GetParentForm(AControl, True);
+    if Assigned(ParentForm) then
+      Parent1 := ParentForm.Name
+    else
+      Parent1 := '';
+
+    Parent2 := '';
+    ParentAnchorDockLayoutTreeNode := TreeNodeControl;
+    while Assigned(ParentAnchorDockLayoutTreeNode.Parent) do begin
+      Parent2 := ParentAnchorDockLayoutTreeNode.Name;
+      ParentAnchorDockLayoutTreeNode := ParentAnchorDockLayoutTreeNode.Parent;
+    end;
+    Result := Parent1 = Parent2;
+
+//    DebugLn('TAnchorDockMaster.ParentsIdentical [', Parent1, '] [', Parent2, ']');
+  end;
+
 begin
   i:=ControlCount-1;
   while i>=0 do begin
     AControl:=Controls[i];
+    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
     if DockedControlIsVisible(AControl)
-    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
-    and (Application.MainForm<>AControl) then begin
+    {and (Application.MainForm<>AControl)
+    and ((TreeNodeControl=nil) or not ParentsIdentical)} then begin
       DisableControlAutoSizing(AControl);
       // AControl is currently on a visible site, but not in the Tree
       // => close site
@@ -1770,6 +1796,7 @@
   aMonitor: TMonitor;
   aHostSite: TAnchorDockHostSite;
 begin
+  Site.Align:=alNone;
   if Site is TCustomForm then begin
     if AParent=nil then
       TCustomForm(Site).WindowState:=ANode.WindowState

Andrey Zubarev

2017-08-22 09:31

reporter   ~0102303

I added only one line to Michl 54525 patch, and it seems that many of the problems with reuse layouts, at least from this issue. Please review anchordocking-parentsidentical-with-fix.pas.patch

Andrey Zubarev

2017-08-22 09:41

reporter   ~0102304

Last edited: 2017-08-22 09:41

View 2 revisions

But we need to improve ParentsIdentical function. If we close all controls necessary and unnecessary (ParentsIdentical:=false always, and Site.Align:=alNone) Will be eliminated all problems with LoadLayout

Juha Manninen

2017-08-22 10:21

developer   ~0102305

@Andrey, do you mean you have an improved patch coming?
If you test it well I believe it can be applied to trunk. Only then it will get more testing by others.

Andrey Zubarev

2017-08-23 10:29

reporter   ~0102328

@Juha
I did a little differently, please apply anchordocking-add_controllocation.patch.
I have not found problems with this patch, this issue and related now work correctly in windows, need test in other widgesets.

It is not finished, later I will implement TAnchorDockMaster.MarkCorrectlyLocatedControls, but actually, controls which do not close will be very small for complex layout

Andrey Zubarev

2017-08-23 10:29

reporter  

anchordocking-add_controllocation.patch (3,821 bytes)
Index: components/anchordocking/anchordocking.pas
===================================================================
--- components/anchordocking/anchordocking.pas	(revision 55731)
+++ components/anchordocking/anchordocking.pas	(working copy)
@@ -524,7 +524,7 @@
 
     function GetControls(Index: integer): TControl;
     function GetLocalizedHeaderHint: string;
-    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
+    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
     function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                 DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
     function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
@@ -1473,18 +1473,21 @@
   OptionsChanged;
 end;
 
-function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
+function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
   ): boolean;
 var
   i: Integer;
   AControl: TControl;
+  TreeNodeControl: TAnchorDockLayoutTreeNode;
 begin
   i:=ControlCount-1;
   while i>=0 do begin
     AControl:=Controls[i];
+    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
     if DockedControlIsVisible(AControl)
-    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
-    and (Application.MainForm<>AControl) then begin
+    and (Application.MainForm<>AControl)
+    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
+    or (TreeNodeControl.ControlLocation=adlclwrongly)) then begin
       DisableControlAutoSizing(AControl);
       // AControl is currently on a visible site, but not in the Tree
       // => close site
@@ -1770,6 +1773,7 @@
   aMonitor: TMonitor;
   aHostSite: TAnchorDockHostSite;
 begin
+  Site.Align:=alNone;
   if Site is TCustomForm then begin
     if AParent=nil then
       TCustomForm(Site).WindowState:=ANode.WindowState
@@ -2159,7 +2163,7 @@
   fTreeNameToDocker:=TADNameToControl.Create;
   try
     // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
@@ -3043,7 +3047,7 @@
     {$ENDIF}
 
     // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
Index: components/anchordocking/anchordockstorage.pas
===================================================================
--- components/anchordocking/anchordockstorage.pas	(revision 55731)
+++ components/anchordocking/anchordockstorage.pas	(working copy)
@@ -60,6 +60,11 @@
     adlhpRight,
     adlhpBottom
     );
+
+  TADLControlLocation = (
+    adlclwrongly,
+    adlclcorrect
+    );
   TADLHeaderPositions = set of TADLHeaderPosition;
 
   EAnchorDockLayoutError = class(Exception);
@@ -81,6 +86,7 @@
     FWorkAreaRect: TRect;
     FTabPosition: TTabPosition;
     FWindowState: TWindowState;
+    FControlLocation: TADLControlLocation;
     function GetAnchors(Site: TAnchorKind): string;
     function GetBottom: integer;
     function GetHeight: integer;
@@ -156,6 +162,7 @@
     function IsSplitter: boolean;
     function IsRootWindow: boolean;
     property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
+    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
   end;
 
   TAnchorDockLayoutTree = class;
@@ -1028,6 +1035,7 @@
 constructor TAnchorDockLayoutTreeNode.Create;
 begin
   FNodes:=TFPList.Create;
+  FControlLocation:=adlclwrongly;//control located wrongly by default
 end;
 
 destructor TAnchorDockLayoutTreeNode.Destroy;

Andrey Zubarev

2017-08-23 12:31

reporter  

anchordocking-add_controllocation_v2.patch (3,855 bytes)
Index: components/anchordocking/anchordocking.pas
===================================================================
--- components/anchordocking/anchordocking.pas	(revision 55731)
+++ components/anchordocking/anchordocking.pas	(working copy)
@@ -524,7 +524,7 @@
 
     function GetControls(Index: integer): TControl;
     function GetLocalizedHeaderHint: string;
-    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
+    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
     function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                 DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
     function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
@@ -1473,18 +1473,22 @@
   OptionsChanged;
 end;
 
-function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
+function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
   ): boolean;
 var
   i: Integer;
   AControl: TControl;
+  TreeNodeControl: TAnchorDockLayoutTreeNode;
 begin
   i:=ControlCount-1;
   while i>=0 do begin
     AControl:=Controls[i];
+    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
     if DockedControlIsVisible(AControl)
-    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
-    and (Application.MainForm<>AControl) then begin
+    and (Application.MainForm<>AControl)
+    and (not(AControl is TAnchorDockPanel))
+    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
+    or (TreeNodeControl.ControlLocation=adlclwrongly)) then begin
       DisableControlAutoSizing(AControl);
       // AControl is currently on a visible site, but not in the Tree
       // => close site
@@ -1771,6 +1775,7 @@
   aHostSite: TAnchorDockHostSite;
 begin
   if Site is TCustomForm then begin
+    Site.Align:=alNone;
     if AParent=nil then
       TCustomForm(Site).WindowState:=ANode.WindowState
     else
@@ -2159,7 +2164,7 @@
   fTreeNameToDocker:=TADNameToControl.Create;
   try
     // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
@@ -3043,7 +3048,7 @@
     {$ENDIF}
 
     // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
Index: components/anchordocking/anchordockstorage.pas
===================================================================
--- components/anchordocking/anchordockstorage.pas	(revision 55731)
+++ components/anchordocking/anchordockstorage.pas	(working copy)
@@ -60,6 +60,11 @@
     adlhpRight,
     adlhpBottom
     );
+
+  TADLControlLocation = (
+    adlclwrongly,
+    adlclcorrect
+    );
   TADLHeaderPositions = set of TADLHeaderPosition;
 
   EAnchorDockLayoutError = class(Exception);
@@ -81,6 +86,7 @@
     FWorkAreaRect: TRect;
     FTabPosition: TTabPosition;
     FWindowState: TWindowState;
+    FControlLocation: TADLControlLocation;
     function GetAnchors(Site: TAnchorKind): string;
     function GetBottom: integer;
     function GetHeight: integer;
@@ -156,6 +162,7 @@
     function IsSplitter: boolean;
     function IsRootWindow: boolean;
     property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
+    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
   end;
 
   TAnchorDockLayoutTree = class;
@@ -1028,6 +1035,7 @@
 constructor TAnchorDockLayoutTreeNode.Create;
 begin
   FNodes:=TFPList.Create;
+  FControlLocation:=adlclwrongly;//control located wrongly by default
 end;
 
 destructor TAnchorDockLayoutTreeNode.Destroy;

Andrey Zubarev

2017-08-23 12:33

reporter   ~0102334

anchordocking-add_controllocation.patch is out of date.

anchordocking-add_controllocationV2.patch added, it includes smal fix for TAnchorDockPanel

Andrey Zubarev

2017-08-24 02:13

reporter  

anchordocking-add_controllocation_v3.patch (7,841 bytes)
Index: components/anchordocking/anchordocking.pas
===================================================================
--- components/anchordocking/anchordocking.pas	(revision 55731)
+++ components/anchordocking/anchordocking.pas	(working copy)
@@ -524,7 +524,8 @@
 
     function GetControls(Index: integer): TControl;
     function GetLocalizedHeaderHint: string;
-    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
+    procedure MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
+    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
     function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                 DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
     function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
@@ -1473,18 +1474,126 @@
   OptionsChanged;
 end;
 
-function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
+procedure TAnchorDockMaster.MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
+var
+  Counter:integer;
+
+  function GetRealParent(Node:TAnchorDockLayoutTreeNode):TAnchorDockLayoutTreeNode;
+  begin
+    result := Node;
+    while Assigned(result.Parent) do begin
+      result := result.Parent;
+      fTreeNameToDocker[Node.Name];
+      if result.NodeType in [adltnControl,adltnCustomSite] then exit
+    end;
+  end;
+
+  function GetDockParent(Control: TControl): TControl;
+  begin
+    Control := Control.Parent;
+    while (Control <> nil) and (Control.Parent <> nil) do
+    begin
+      if not (Control is TAnchorDockHostSite) then
+        Break;
+      Control := Control.Parent;
+    end;
+    Result := Control;
+  end;
+
+  procedure RealChildrenCount(AWinControl:twincontrol;var realsubcontrolcoun:integer);
+  var
+    i:integer;
+    ACountedControl:tcontrol;
+  begin
+     for i:=0 to AWinControl.ControlCount-1 do
+       begin
+         ACountedControl:=AWinControl.Controls[i];
+         if not (ACountedControl is TAnchorDockHostSite) then
+         if not (ACountedControl is TAnchorDockHeader) then
+         if not (ACountedControl is TAnchorDockPageControl) then
+         if ACountedControl.IsVisible then
+           inc(realsubcontrolcoun);
+         if ACountedControl is TAnchorDockHostSite then
+         if ACountedControl.IsVisible then
+           RealChildrenCount(ACountedControl as TWinControl, realsubcontrolcoun);
+       end;
+  end;
+
+  function CheckNode(Node: TAnchorDockLayoutTreeNode; var ControlsCount: integer):TADLControlLocation;
+  var
+    i: Integer;
+    AControl,AParent: TControl;
+    SubControlsCount,realsubcontrolcoun: integer;
+  begin
+    if Node.IsSplitter then begin
+      inc(ControlsCount);
+      exit(adlclCorrect);
+    end
+    else if Node=Tree.Root then begin
+      result:=adlclCorrect;
+      AControl:=nil;
+      AParent:=nil;
+    end
+    else begin
+      AControl:=FindControl(Node.Name);
+      AParent:=FindControl(GetRealParent(Node).Name);
+      if Node.NodeType=adltnLayout then result:=adlclCorrect
+      else if AControl is TAnchorDockPanel then result:=adlclCorrect
+      else if AControl=nil then result:=adlclWrongly
+      else if GetDockParent(AControl)<>AParent then result:=adlclWrongly
+      else
+      begin
+      end;
+    end;
+    if AControl<>nil then
+    if not (AControl is TAnchorDockHostSite) then
+     inc(ControlsCount);
+    if result=adlclWrongly then exit;
+    if AControl=nil then AControl:=AParent;
+    SubControlsCount:=0;
+    for i:=0 to Node.Count-1 do
+    begin
+      result:=CheckNode(Node[i],SubControlsCount);
+      if result=adlclWrongly then exit;
+    end;
+    realsubcontrolcoun:=0;
+    if (AControl is TAnchorDockHostSite)or(AControl is TAnchorDockPanel) then
+    begin
+       RealChildrenCount(AControl as TWinControl,realsubcontrolcoun);
+       if SubControlsCount<>realsubcontrolcoun then Exit(adlclWrongly);
+    end;
+    ControlsCount:=ControlsCount+SubControlsCount;
+    if result=adlclWrongly then exit;
+    for i:=0 to Node.Count-1 do
+    begin
+      Node[i].ControlLocation:=adlclCorrect;
+    end;
+  end;
+
+begin
+  //We need compare dock tree and fact controls placement
+  //and mark controls which location is coincides with tree
+  //these controls can be not closrd in CloseUnneededAndWronglyLocatedControls
+  Counter:=0;
+  Tree.Root.ControlLocation:=CheckNode(Tree.Root,Counter);
+end;
+
+function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
   ): boolean;
 var
   i: Integer;
   AControl: TControl;
+  TreeNodeControl: TAnchorDockLayoutTreeNode;
 begin
   i:=ControlCount-1;
   while i>=0 do begin
     AControl:=Controls[i];
+    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
     if DockedControlIsVisible(AControl)
-    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
-    and (Application.MainForm<>AControl) then begin
+    and (Application.MainForm<>AControl)
+    and (not(AControl is TAnchorDockPanel))
+    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
+    or (TreeNodeControl.ControlLocation=adlclWrongly)) then begin
       DisableControlAutoSizing(AControl);
       // AControl is currently on a visible site, but not in the Tree
       // => close site
@@ -1771,6 +1880,7 @@
   aHostSite: TAnchorDockHostSite;
 begin
   if Site is TCustomForm then begin
+    Site.Align:=alNone;
     if AParent=nil then
       TCustomForm(Site).WindowState:=ANode.WindowState
     else
@@ -2158,9 +2268,11 @@
   ControlNames:=TStringList.Create;
   fTreeNameToDocker:=TADNameToControl.Create;
   try
-    // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
 
+    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
+    MarkCorrectlyLocatedControl(Tree);
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
+
     BeginUpdate;
     try
       // create all needed forms/controls (not helper controls like splitters)
@@ -3042,8 +3154,9 @@
     DebugWriteChildAnchors(Tree.Root);
     {$ENDIF}
 
-    // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
+    MarkCorrectlyLocatedControl(Tree);
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
Index: components/anchordocking/anchordockstorage.pas
===================================================================
--- components/anchordocking/anchordockstorage.pas	(revision 55731)
+++ components/anchordocking/anchordockstorage.pas	(working copy)
@@ -60,6 +60,11 @@
     adlhpRight,
     adlhpBottom
     );
+
+  TADLControlLocation = (
+    adlclWrongly,
+    adlclCorrect
+    );
   TADLHeaderPositions = set of TADLHeaderPosition;
 
   EAnchorDockLayoutError = class(Exception);
@@ -81,6 +86,7 @@
     FWorkAreaRect: TRect;
     FTabPosition: TTabPosition;
     FWindowState: TWindowState;
+    FControlLocation: TADLControlLocation;
     function GetAnchors(Site: TAnchorKind): string;
     function GetBottom: integer;
     function GetHeight: integer;
@@ -156,6 +162,7 @@
     function IsSplitter: boolean;
     function IsRootWindow: boolean;
     property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
+    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
   end;
 
   TAnchorDockLayoutTree = class;
@@ -1028,6 +1035,7 @@
 constructor TAnchorDockLayoutTreeNode.Create;
 begin
   FNodes:=TFPList.Create;
+  FControlLocation:=adlclwrongly;//control located wrongly by default
 end;
 
 destructor TAnchorDockLayoutTreeNode.Destroy;

Andrey Zubarev

2017-08-24 02:16

reporter   ~0102339

anchordocking-add_controllocationV2.patch is out of date.

anchordocking-add_controllocationV3.patch added, it include tentatively MarkCorrectlyLocatedControl implement

Juha Manninen

2017-08-25 00:48

developer   ~0102355

Unfortunately I don't know this problem scope or AnchorDocking in general very well.
Does it need so much code? Why are the controls wrongly located to start with?

Andrey Zubarev

2017-08-25 01:08

reporter   ~0102356

Last edited: 2017-08-25 01:16

View 3 revisions

The problem is due to the fact that now when re-use is not verified by the actual parent of the controls.

The algorithm simply takes control and set it to new anchors. And at last load layout this control can have a different parent.

One of the variant just take close all the controls, then create them again, and set the correct parent. It mades in anchordocking-add_controllocation.patch and V2.

But you can try to keep some controls that have the correct owner. For this you need to compare two trees (displayed controls tree and loaded from config tree) - so the code quite a lot in V3

Sorry for my english((

Juha Manninen

2017-08-25 11:24

developer   ~0102362

Last edited: 2017-08-25 11:25

View 2 revisions

> But you can try to keep some controls that have the correct owner.
> For this you need to compare two trees (displayed controls tree
> and loaded from config tree) - so the code quite a lot in V3

What is the benefit compared to V2? Is it faster? Does it reduce flickering? Is there a situation where the V2 does not work correctly?
Mattias will be available some time next week. I hope he can comment on the issue.

Andrey Zubarev

2017-08-25 13:46

reporter   ~0102370

Last edited: 2017-08-25 13:56

View 2 revisions

anchordocking-add_controllocation.patch and anchordocking-add_controllocationV2.patch it's the same thing. There are no comparisons, they mark everything as adlclwrongly, and further all of these controls close in CloseUnneededAndWronglyLocatedControls.

anchordocking-add_controllocationV3.patch add MarkCorrectlyLocatedControl trying something to compare, and something mark as adlclcorrect for not close. For example, if you make 2 layouts but only different mainform size and positions of splitters, she believes they are the same and nothing will not be closed, will simply be resized. Of course MarkCorrectlyLocatedControl not perfect, this is just a sample code. Perhaps now V2 more reliable than V3

Of course Matthias know better how to do it right, But related issues hang there for a few years and I decided it was time to try to fix it

Juha Manninen

2017-08-25 14:16

developer   ~0102371

> But related issues hang there for a few years and I decided it was time to try to fix it

Yes, good thinking! Did you look at the related issues? Does your solution fix also them?

Andrey Zubarev

2017-08-25 16:37

reporter   ~0102373

Last edited: 2017-08-25 16:38

View 2 revisions

Yes, I test all related. It solves them too.
But I test only in windows

Pascal Riekenberg

2017-09-06 13:01

reporter   ~0102660

I did a test with my Cobol-IDE. Alternate laoding of two layout.xml destroys the layout.
I will see if i can reproduce this with MiniIDE.

Pascal Riekenberg

2017-09-06 13:09

reporter   ~0102661

Yes, i can reproduce it:
Case 1:
 - load layout01.xml -> okay
 - load layout02.xml -> layout destroyed
case 2:
 - load layout02.xml -> okay
 - load layout01.xml -> okay
 - load layout02.xml -> layout destroyed

The problem arises when layout02.xml is loaded after layout01.xml

Pascal Riekenberg

2017-09-06 13:10

reporter  

layout01.xml (1,883 bytes)

Pascal Riekenberg

2017-09-06 13:10

reporter  

layout02.xml (4,844 bytes)

Andrey Zubarev

2017-09-06 13:19

reporter   ~0102662

Last edited: 2017-09-06 14:15

View 3 revisions

I have not yet considered layout with pages. We need to decide if this is the right direction or not

The old version can do it right?

Pascal Riekenberg

2017-09-06 14:22

reporter   ~0102664

No, it never worked!

Andrey Zubarev

2017-09-07 10:02

reporter   ~0102680

@Pascal
I have a solution, but I can't make patch - in my local copy there are a lot of changes

Juha Manninen

2017-09-07 11:34

developer   ~0102683

@Andrey, use Git. Its local commits and branches help you manage those changes.

Pascal Riekenberg

2017-09-08 08:10

reporter   ~0102713

@Andrey
Just make a new checkout, apply your V3 patch and add the changes.
I have a lazarus_trunk directory for that while i generally use lazarus dir with all my changes.
You also can limit your patch to one directory or file.

Andrey Zubarev

2017-09-09 13:23

reporter  

anchordocking-add_controllocation_v4.patch (8,590 bytes)
Index: components/anchordocking/anchordocking.pas
===================================================================
--- components/anchordocking/anchordocking.pas	(revision 55828)
+++ components/anchordocking/anchordocking.pas	(working copy)
@@ -533,7 +533,8 @@
 
     function GetControls(Index: integer): TControl;
     function GetLocalizedHeaderHint: string;
-    function CloseUnneededControls(Tree: TAnchorDockLayoutTree): boolean;
+    procedure MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
+    function CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree): boolean;
     function CreateNeededControls(Tree: TAnchorDockLayoutTree;
                 DisableAutoSizing: boolean; ControlNames: TStrings): boolean;
     function GetNodeSite(Node: TAnchorDockLayoutTreeNode): TAnchorDockHostSite;
@@ -1524,18 +1525,140 @@
   OptionsChanged;
 end;
 
-function TAnchorDockMaster.CloseUnneededControls(Tree: TAnchorDockLayoutTree
+procedure TAnchorDockMaster.MarkCorrectlyLocatedControl(Tree: TAnchorDockLayoutTree);
+var
+  Counter:integer;
+
+  function GetRealParent(Node:TAnchorDockLayoutTreeNode):TAnchorDockLayoutTreeNode;
+  begin
+    result := Node;
+    while Assigned(result.Parent) do begin
+      result := result.Parent;
+      fTreeNameToDocker[Node.Name];
+      if result.NodeType in [adltnControl,adltnCustomSite] then exit
+    end;
+  end;
+
+  function GetDockParent(Control: TControl): TControl;
+  begin
+    Control := Control.Parent;
+    while (Control <> nil) and (Control.Parent <> nil) do
+    begin
+      if not (Control is TAnchorDockHostSite) then
+        Break;
+      Control := Control.Parent;
+    end;
+    Result := Control;
+  end;
+
+  procedure RealChildrenCount(AWinControl:twincontrol;var realsubcontrolcoun:integer);
+  var
+    i:integer;
+    ACountedControl:tcontrol;
+  begin
+     for i:=0 to AWinControl.ControlCount-1 do
+       begin
+         ACountedControl:=AWinControl.Controls[i];
+         if not (ACountedControl is TAnchorDockHostSite) then
+         if not (ACountedControl is TAnchorDockHeader) then
+         if not (ACountedControl is TAnchorDockPageControl) then
+         if ACountedControl.IsVisible then
+           inc(realsubcontrolcoun);
+         if ACountedControl is TAnchorDockHostSite then
+         if ACountedControl.IsVisible then
+           RealChildrenCount(ACountedControl as TWinControl, realsubcontrolcoun);
+       end;
+  end;
+
+  function CheckNode(Node: TAnchorDockLayoutTreeNode; var ControlsCount: integer):TADLControlLocation;
+  var
+    i: Integer;
+    AControl,AParent: TControl;
+    SubControlsCount,realsubcontrolcoun: integer;
+  begin
+    if Node.IsSplitter then begin
+      inc(ControlsCount);
+      exit(adlclCorrect);
+    end
+    else if Node=Tree.Root then begin
+      result:=adlclCorrect;
+      AControl:=nil;
+      AParent:=nil;
+    end
+    else begin
+      AControl:=FindControl(Node.Name);
+      AParent:=FindControl(GetRealParent(Node).Name);
+      if Node.NodeType=adltnLayout then result:=adlclCorrect
+      else if AControl is TAnchorDockPanel then result:=adlclCorrect
+      else if AControl=nil then result:=adlclWrongly
+      else if GetDockParent(AControl)<>AParent then result:=adlclWrongly
+      else
+      begin
+      end;
+    end;
+    if AControl<>nil then
+    if not (AControl is TAnchorDockHostSite) then
+     inc(ControlsCount);
+    if result=adlclWrongly then exit;
+    if AControl=nil then AControl:=AParent;
+    SubControlsCount:=0;
+    for i:=0 to Node.Count-1 do
+    begin
+      result:=CheckNode(Node[i],SubControlsCount);
+      if result=adlclWrongly then exit;
+    end;
+    realsubcontrolcoun:=0;
+    if (AControl is TAnchorDockHostSite)or(AControl is TAnchorDockPanel) then
+    begin
+       RealChildrenCount(AControl as TWinControl,realsubcontrolcoun);
+       if SubControlsCount<>realsubcontrolcoun then Exit(adlclWrongly);
+    end;
+    ControlsCount:=ControlsCount+SubControlsCount;
+    if result=adlclWrongly then exit;
+    for i:=0 to Node.Count-1 do
+    begin
+      Node[i].ControlLocation:=adlclCorrect;
+    end;
+  end;
+
+begin
+  //We need compare dock tree and fact controls placement
+  //and mark controls which location is coincides with tree
+  //these controls can be not closrd in CloseUnneededAndWronglyLocatedControls
+  Counter:=0;
+  Tree.Root.ControlLocation:=CheckNode(Tree.Root,Counter);
+end;
+
+function TAnchorDockMaster.CloseUnneededAndWronglyLocatedControls(Tree: TAnchorDockLayoutTree
   ): boolean;
+
+  function GetParentAnchorDockPageControl(thisControl: TControl):TAnchorDockPageControl;
+  begin
+    while thisControl<>nil do
+    begin
+      if thisControl is TAnchorDockPageControl then
+        exit(thisControl as TAnchorDockPageControl);
+      thisControl:=thisControl.Parent;
+    end;
+    result:=nil;
+  end;
+
 var
   i: Integer;
   AControl: TControl;
+  TreeNodeControl: TAnchorDockLayoutTreeNode;
+  ParentAnchorDockPageControl:TAnchorDockPageControl;
 begin
   i:=ControlCount-1;
   while i>=0 do begin
     AControl:=Controls[i];
+    TreeNodeControl:=Tree.Root.FindChildNode(AControl.Name,true);
     if DockedControlIsVisible(AControl)
-    and (Tree.Root.FindChildNode(AControl.Name,true)=nil)
-    and (Application.MainForm<>AControl) then begin
+    and (Application.MainForm<>AControl)
+    and (not(AControl is TAnchorDockPanel))
+    and ((Tree.Root.FindChildNode(AControl.Name,true)=nil)
+    or (TreeNodeControl.ControlLocation=adlclWrongly)) then begin
+      ParentAnchorDockPageControl:=GetParentAnchorDockPageControl(AControl);
       DisableControlAutoSizing(AControl);
       // AControl is currently on a visible site, but not in the Tree
       // => close site
@@ -1561,6 +1684,9 @@
           AControl.Parent:=nil;
         end;
       end;
+      if ParentAnchorDockPageControl<>nil then
+        if ParentAnchorDockPageControl.Parent<>nil then
+          ParentAnchorDockPageControl.Parent.Free;
     end;
     i:=Min(i,ControlCount)-1;
   end;
@@ -1822,6 +1948,7 @@
   aHostSite: TAnchorDockHostSite;
 begin
   if Site is TCustomForm then begin
+    Site.Align:=alNone;
     if AParent=nil then
       TCustomForm(Site).WindowState:=ANode.WindowState
     else
@@ -2209,9 +2336,11 @@
   ControlNames:=TStringList.Create;
   fTreeNameToDocker:=TADNameToControl.Create;
   try
-    // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
 
+    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
+    MarkCorrectlyLocatedControl(Tree);
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
+
     BeginUpdate;
     try
       // create all needed forms/controls (not helper controls like splitters)
@@ -3102,8 +3231,9 @@
     DebugWriteChildAnchors(Tree.Root);
     {$ENDIF}
 
-    // close all unneeded forms/controls (not helper controls like splitters)
-    if not CloseUnneededControls(Tree) then exit;
+    // close all unneeded and wrongly allocated forms/controls (not helper controls like splitters)
+    MarkCorrectlyLocatedControl(Tree);
+    if not CloseUnneededAndWronglyLocatedControls(Tree) then exit;
 
     BeginUpdate;
     try
Index: components/anchordocking/anchordockstorage.pas
===================================================================
--- components/anchordocking/anchordockstorage.pas	(revision 55828)
+++ components/anchordocking/anchordockstorage.pas	(working copy)
@@ -60,6 +60,11 @@
     adlhpRight,
     adlhpBottom
     );
+
+  TADLControlLocation = (
+    adlclWrongly,
+    adlclCorrect
+    );
   TADLHeaderPositions = set of TADLHeaderPosition;
 
   EAnchorDockLayoutError = class(Exception);
@@ -81,6 +86,7 @@
     FWorkAreaRect: TRect;
     FTabPosition: TTabPosition;
     FWindowState: TWindowState;
+    FControlLocation: TADLControlLocation;
     function GetAnchors(Site: TAnchorKind): string;
     function GetBottom: integer;
     function GetHeight: integer;
@@ -156,6 +162,7 @@
     function IsSplitter: boolean;
     function IsRootWindow: boolean;
     property Nodes[Index: integer]: TAnchorDockLayoutTreeNode read GetNodes; default;
+    property ControlLocation: TADLControlLocation read FControlLocation write FControlLocation;
   end;
 
   TAnchorDockLayoutTree = class;
@@ -1028,6 +1035,7 @@
 constructor TAnchorDockLayoutTreeNode.Create;
 begin
   FNodes:=TFPList.Create;
+  FControlLocation:=adlclwrongly;//control located wrongly by default
 end;
 
 destructor TAnchorDockLayoutTreeNode.Destroy;

Andrey Zubarev

2017-09-09 13:24

reporter   ~0102737

@Pascal
Please test anchordocking-add_controllocation_v4.patch

Pascal Riekenberg

2017-09-10 21:53

reporter   ~0102762

Great! It's working as expected. Many thanks!

Andrey Zubarev

2017-09-11 20:43

reporter   ~0102782

Mattias, please review

Michl

2017-09-16 21:08

developer   ~0102874

Last edited: 2017-09-16 21:09

View 2 revisions

@BBaz: Can you please test current Lazarus trunk with patch anchordocking-add_controllocation_v4.patch? Is your app further working with it?

Michl

2017-09-25 22:05

developer   ~0103047

@Andrey Zubarev: Thank you for the patch! I commited it in trunk revision 55921 as BBaz gives no feedback and I can't see any problems in my test cases here. Let's test it in the wild ;)

Issue History

Date Modified Username Field Change
2017-01-16 19:01 Valdas Jankūnas New Issue
2017-01-16 19:01 Valdas Jankūnas File Added: minide_test.zip
2017-01-16 19:01 Valdas Jankūnas File Added: load_01_then_02.jpg
2017-01-16 19:01 Valdas Jankūnas File Added: load_02_then_01.jpg
2017-02-28 15:43 Andrey Zubarev Note Added: 0098514
2017-03-24 10:24 Juha Manninen Relationship added related to 0026999
2017-03-28 08:58 Ondrej Pokorny Relationship added related to 0029200
2017-04-05 11:12 Michl Assigned To => Michl
2017-04-05 11:12 Michl Status new => assigned
2017-04-05 11:14 Michl Note Added: 0099381
2017-05-18 12:11 BBaz Note Added: 0100395
2017-05-18 12:50 Michl Relationship added related to 0031384
2017-05-18 12:51 Michl Relationship added related to 0031834
2017-05-18 12:51 Michl Relationship deleted related to 0031384
2017-05-25 22:47 Michl Note Added: 0100684
2017-05-25 22:51 Michl Note Edited: 0100684 View Revisions
2017-05-25 22:51 Michl Assigned To Michl =>
2017-05-25 22:52 Michl LazTarget => -
2017-05-25 22:52 Michl Status assigned => new
2017-08-20 16:00 Juha Manninen Relationship added related to 0020845
2017-08-22 09:26 Andrey Zubarev File Added: anchordocking-parentsidentical-with-fix.pas.patch
2017-08-22 09:31 Andrey Zubarev Note Added: 0102303
2017-08-22 09:41 Andrey Zubarev Note Added: 0102304
2017-08-22 09:41 Andrey Zubarev Note Edited: 0102304 View Revisions
2017-08-22 10:21 Juha Manninen Note Added: 0102305
2017-08-23 10:29 Andrey Zubarev Note Added: 0102328
2017-08-23 10:29 Andrey Zubarev File Added: anchordocking-add_controllocation.patch
2017-08-23 12:31 Andrey Zubarev File Added: anchordocking-add_controllocation_v2.patch
2017-08-23 12:33 Andrey Zubarev Note Added: 0102334
2017-08-24 02:13 Andrey Zubarev File Added: anchordocking-add_controllocation_v3.patch
2017-08-24 02:16 Andrey Zubarev Note Added: 0102339
2017-08-25 00:48 Juha Manninen Note Added: 0102355
2017-08-25 01:08 Andrey Zubarev Note Added: 0102356
2017-08-25 01:14 Andrey Zubarev Note Edited: 0102356 View Revisions
2017-08-25 01:16 Andrey Zubarev Note Edited: 0102356 View Revisions
2017-08-25 11:24 Juha Manninen Note Added: 0102362
2017-08-25 11:25 Juha Manninen Note Edited: 0102362 View Revisions
2017-08-25 13:46 Andrey Zubarev Note Added: 0102370
2017-08-25 13:56 Andrey Zubarev Note Edited: 0102370 View Revisions
2017-08-25 14:16 Juha Manninen Note Added: 0102371
2017-08-25 16:37 Andrey Zubarev Note Added: 0102373
2017-08-25 16:38 Andrey Zubarev Note Edited: 0102373 View Revisions
2017-09-06 13:01 Pascal Riekenberg Note Added: 0102660
2017-09-06 13:09 Pascal Riekenberg Note Added: 0102661
2017-09-06 13:10 Pascal Riekenberg File Added: layout01.xml
2017-09-06 13:10 Pascal Riekenberg File Added: layout02.xml
2017-09-06 13:19 Andrey Zubarev Note Added: 0102662
2017-09-06 13:21 Andrey Zubarev Note Edited: 0102662 View Revisions
2017-09-06 14:15 Andrey Zubarev Note Edited: 0102662 View Revisions
2017-09-06 14:22 Pascal Riekenberg Note Added: 0102664
2017-09-07 10:02 Andrey Zubarev Note Added: 0102680
2017-09-07 11:34 Juha Manninen Note Added: 0102683
2017-09-08 08:10 Pascal Riekenberg Note Added: 0102713
2017-09-09 13:23 Andrey Zubarev File Added: anchordocking-add_controllocation_v4.patch
2017-09-09 13:24 Andrey Zubarev Note Added: 0102737
2017-09-10 21:53 Pascal Riekenberg Note Added: 0102762
2017-09-11 20:43 Andrey Zubarev Note Added: 0102782
2017-09-16 21:08 Michl Note Added: 0102874
2017-09-16 21:08 Michl Assigned To => Michl
2017-09-16 21:08 Michl Status new => feedback
2017-09-16 21:09 Michl Note Edited: 0102874 View Revisions
2017-09-25 22:05 Michl Fixed in Revision => 55921
2017-09-25 22:05 Michl Note Added: 0103047
2017-09-25 22:05 Michl Status feedback => resolved
2017-09-25 22:05 Michl Fixed in Version => 1.9 (SVN)
2017-09-25 22:05 Michl Resolution open => fixed
2017-09-25 22:12 Michl Relationship replaced has duplicate 0026999
2017-09-26 12:10 Juha Manninen Relationship added related to 0032376