View Issue Details

IDProjectCategoryView StatusLast Update
0029868LazarusIDEpublic2016-04-17 13:37
ReporterFTurtleAssigned ToJuha Manninen 
PrioritynormalSeverityminorReproducibilityN/A
Status closedResolutionfixed 
Product VersionProduct Build 
Target VersionFixed in Version 
Summary0029868: [Patches] Adding "Change Parent" dialog and generic reusable dialog for choosing string from list
DescriptionThis patch adds:
1. "Change Parent" dialog.
2. Generic reusable dialog for choosing string from list

Thread at forum:
http://forum.lazarus.freepascal.org/index.php/topic,31876.0.html
TagsNo tags attached.
Fixed in Revisionr52193, r52194, r52195
LazTarget-
Widgetset
Attached Files
  • patch.diff (12,614 bytes)
    Index: designer/designer.pp
    ===================================================================
    --- designer/designer.pp	(revision 52005)
    +++ designer/designer.pp	(working copy)
    @@ -100,6 +100,7 @@
     
       TDesigner = class(TComponentEditorDesigner)
       private
    +    FChangeParentCandidatesAsText: string;
         FDesignerPopupMenu: TPopupMenu;
         FDefaultFormBounds: TRect;
         FLastFormBounds: TRect;
    @@ -410,7 +411,7 @@
       DesignerMenuSelectAll: TIDEMenuCommand;
     
       DesignerMenuChangeClass: TIDEMenuCommand;
    -  DesignerMenuChangeParent: TIDEMenuSection;
    +  DesignerMenuChangeParent: TIDEMenuCommand;
       DesignerMenuViewLFM: TIDEMenuCommand;
       DesignerMenuSaveAsXML: TIDEMenuCommand;
       DesignerMenuCenterForm: TIDEMenuCommand;
    @@ -425,6 +426,8 @@
     
     implementation
     
    +uses SelectStringDialog;
    +
     type
       TCustomFormAccess = class(TCustomForm);
       TControlAccess = class(TControl);
    @@ -600,10 +603,8 @@
       DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
         DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                      'Change class',lisDlgChangeClass);
    -    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
    -                                                 'Change parent');
    -    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
    -    DesignerMenuChangeParent.Caption:=lisChangeParent;
    +    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    +                                                 'Change parent',lisChangeParent+'...');
         DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                     'View LFM',lisViewSourceLfm);
         DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    @@ -3265,15 +3266,25 @@
     
     procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
     var
    -  Item: TIDEMenuCommand;
    +  SelectStringDlg: TSelectStringDlg;
       NewParentName: String;
       i: Integer;
       CurControl: TControl;
       NewParent: TWinControl;
     begin
    -  if not (Sender is TIDEMenuCommand) then Exit;
    -  Item := TIDEMenuCommand(Sender);
    -  NewParentName := Item.Caption;
    +  SelectStringDlg := TSelectStringDlg.Create(nil);
    +  try
    +    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
    +    FChangeParentCandidatesAsText := '';
    +    SelectStringDlg.Caption := lisChangeParent;
    +    if SelectStringDlg.ShowModal = mrOK then
    +      NewParentName := SelectStringDlg.SelectedItem
    +    else
    +      Exit;
    +  finally
    +    SelectStringDlg.Free;
    +  end;
    +
       if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
         NewParent := TWinControl(LookupRoot)
       else
    @@ -3886,6 +3897,7 @@
       DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
     
       DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
    +  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
       DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
       DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
       DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
    @@ -3964,23 +3976,29 @@
         Result.Add(LookupRoot);
       end;
     
    +  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
    +  var
    +    sl: TStringList;
    +    i: Integer;
    +  begin
    +    sl := TStringList.Create;
    +    try
    +      for i:=0 to ACandidates.Count-1 do
    +        sl.Append(TWinControl(ACandidates[i]).Name);
    +      Result := sl.Text;
    +    finally
    +      sl.Free;
    +    end;
    +  end;
    +
       procedure UpdateChangeParentMenu;
       var
         Candidates: TFPList;
    -    i: Integer;
    -    Item: TIDEMenuItem;
       begin
    -    Candidates:=GetChangeParentCandidates;
    +    Candidates := GetChangeParentCandidates;
         try
    -      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
    -      DesignerMenuChangeParent.Clear;
    -      for i:=0 to Candidates.Count-1 do
    -      begin
    -        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
    -        DesignerMenuChangeParent.AddLast(Item);
    -        Item.Caption:=TWinControl(Candidates[i]).Name;
    -        Item.OnClick:=@OnChangeParentMenuClick;
    -      end;
    +      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
    +      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
         finally
           Candidates.Free;
         end;
    Index: ide/lazarus.lpi
    ===================================================================
    --- ide/lazarus.lpi	(revision 52005)
    +++ ide/lazarus.lpi	(working copy)
    @@ -66,7 +66,7 @@
             <PackageName Value="SynEdit"/>
           </Item7>
         </RequiredPackages>
    -    <Units Count="241">
    +    <Units Count="242">
           <Unit0>
             <Filename Value="lazarus.pp"/>
             <IsPartOfProject Value="True"/>
    @@ -309,6 +309,7 @@
           <Unit39>
             <Filename Value="../designer/designer.pp"/>
             <IsPartOfProject Value="True"/>
    +        <UnitName Value="Designer"/>
           </Unit39>
           <Unit40>
             <Filename Value="../designer/designerprocs.pas"/>
    @@ -1348,6 +1349,14 @@
             <ResourceBaseClass Value="Form"/>
             <UnitName Value="DefinesGui"/>
           </Unit240>
    +      <Unit241>
    +        <Filename Value="selectstringdialog.pas"/>
    +        <IsPartOfProject Value="True"/>
    +        <ComponentName Value="SelectStringDlg"/>
    +        <HasResources Value="True"/>
    +        <ResourceBaseClass Value="Form"/>
    +        <UnitName Value="SelectStringDialog"/>
    +      </Unit241>
         </Units>
       </ProjectOptions>
       <CompilerOptions>
    Index: ide/selectstringdialog.lfm
    ===================================================================
    --- ide/selectstringdialog.lfm	(revision 0)
    +++ ide/selectstringdialog.lfm	(revision 0)
    @@ -0,0 +1,65 @@
    +object SelectStringDlg: TSelectStringDlg
    +  Left = 550
    +  Height = 390
    +  Top = 217
    +  Width = 290
    +  Caption = 'SelectStringDlg'
    +  ClientHeight = 390
    +  ClientWidth = 290
    +  OnCreate = FormCreate
    +  LCLVersion = '1.7'
    +  object ListFilterEdit: TListFilterEdit
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = Owner
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    Left = 6
    +    Height = 21
    +    Top = 6
    +    Width = 278
    +    OnAfterFilter = ListFilterEditAfterFilter
    +    ButtonWidth = 23
    +    NumGlyphs = 1
    +    Anchors = [akTop, akLeft, akRight]
    +    BorderSpacing.Around = 6
    +    MaxLength = 0
    +    TabOrder = 0
    +  end
    +  object ListBox: TListBox
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = ListFilterEdit
    +    AnchorSideTop.Side = asrBottom
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = ButtonPanel
    +    Left = 6
    +    Height = 319
    +    Top = 33
    +    Width = 278
    +    Anchors = [akTop, akLeft, akRight, akBottom]
    +    BorderSpacing.Around = 6
    +    ItemHeight = 0
    +    OnDblClick = ListBoxDblClick
    +    OnSelectionChange = ListBoxSelectionChange
    +    TabOrder = 1
    +  end
    +  object ButtonPanel: TButtonPanel
    +    Left = 6
    +    Height = 26
    +    Top = 358
    +    Width = 278
    +    OKButton.Name = 'OKButton'
    +    OKButton.DefaultCaption = True
    +    OKButton.OnClick = OKButtonClick
    +    HelpButton.Name = 'HelpButton'
    +    HelpButton.DefaultCaption = True
    +    HelpButton.OnClick = HelpButtonClick
    +    CloseButton.Name = 'CloseButton'
    +    CloseButton.DefaultCaption = True
    +    CancelButton.Name = 'CancelButton'
    +    CancelButton.DefaultCaption = True
    +    TabOrder = 2
    +    ShowButtons = [pbOK, pbCancel, pbHelp]
    +    ShowBevel = False
    +  end
    +end
    Index: ide/selectstringdialog.pas
    ===================================================================
    --- ide/selectstringdialog.pas	(revision 0)
    +++ ide/selectstringdialog.pas	(revision 0)
    @@ -0,0 +1,156 @@
    +{ /***************************************************************************
    +                 SelectStringDialog.pas - Lazarus IDE unit
    +                 -----------------------------------------
    +
    + ***************************************************************************/
    +
    + ***************************************************************************
    + *                                                                         *
    + *   This source is free software; you can redistribute it and/or modify   *
    + *   it under the terms of the GNU General Public License as published by  *
    + *   the Free Software Foundation; either version 2 of the License, or     *
    + *   (at your option) any later version.                                   *
    + *                                                                         *
    + *   This code is distributed in the hope that it will be useful, but      *
    + *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
    + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
    + *   General Public License for more details.                              *
    + *                                                                         *
    + *   A copy of the GNU General Public License is available on the World    *
    + *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
    + *   obtain it by writing to the Free Software Foundation,                 *
    + *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
    + *                                                                         *
    + ***************************************************************************
    +
    +  Author: FTurtle
    +
    +  Abstract:
    +    A generic reusable dialog for choosing string from list.
    +}
    +
    +unit SelectStringDialog;
    +
    +{$mode objfpc}{$H+}
    +
    +interface
    +
    +uses
    +  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
    +  Dialogs, StdCtrls, ButtonPanel;
    +
    +type
    +
    +  { TSelectStringDlg }
    +
    +  TSelectStringDlg = class(TForm)
    +    ButtonPanel: TButtonPanel;
    +    ListBox: TListBox;
    +    ListFilterEdit: TListFilterEdit;
    +    procedure FormCreate(Sender: TObject);
    +    procedure HelpButtonClick(Sender: TObject);
    +    procedure ListBoxDblClick(Sender: TObject);
    +    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
    +    procedure ListFilterEditAfterFilter(Sender: TObject);
    +    procedure OKButtonClick(Sender: TObject);
    +  private
    +    FHelpURL: string;
    +    function GetSelectedItem: string;
    +    procedure SetHelpURL(AValue: string);
    +    procedure SetSelectedItem(AValue: string);
    +    procedure UpdateButtonState;
    +  public
    +    function ShowModal: Integer; override;
    +  public
    +    property HelpURL: string read FHelpURL write SetHelpURL;
    +    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
    +  end;
    +
    +implementation
    +
    +uses LCLIntf;
    +
    +{$R *.lfm}
    +
    +{ TSelectStringDlg }
    +
    +procedure TSelectStringDlg.FormCreate(Sender: TObject);
    +begin
    +  Caption := '';
    +  HelpURL := '';
    +end;
    +
    +procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
    +begin
    +  OpenURL(FHelpURL);
    +end;
    +
    +procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
    +begin
    +  ButtonPanel.OKButton.Click;
    +end;
    +
    +{$HINTS OFF}
    +procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
    +begin
    +  UpdateButtonState;
    +end;
    +{$HINTS ON}
    +
    +procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
    +begin
    +  UpdateButtonState;
    +end;
    +
    +procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
    +begin
    +  if ListBox.ItemIndex < 0 then
    +    ModalResult := mrNone;
    +end;
    +
    +procedure TSelectStringDlg.SetHelpURL(AValue: string);
    +begin
    +  FHelpURL := AValue;
    +  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
    +end;
    +
    +function TSelectStringDlg.GetSelectedItem: string;
    +begin
    +  if ListBox.ItemIndex > -1 then
    +    Result := ListBox.Items[ListBox.ItemIndex]
    +  else
    +    Result := '';
    +end;
    +
    +procedure TSelectStringDlg.SetSelectedItem(AValue: string);
    +var
    +  i: Integer;
    +begin
    +  i := ListBox.Items.IndexOf(AValue);
    +  if i > -1 then
    +    ListBox.ItemIndex := i;
    +end;
    +
    +procedure TSelectStringDlg.UpdateButtonState;
    +begin
    +  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
    +end;
    +
    +function TSelectStringDlg.ShowModal: Integer;
    +const
    +  MinWidth = 250;
    +  MinHeight = 250;
    +begin
    +  Constraints.MinHeight := MinHeight;
    +  if ButtonPanel.HelpButton.Visible then
    +    Constraints.MinWidth := MinWidth
    +  else
    +    Constraints.MinWidth := MinWidth - 75;
    +  ListFilterEdit.FilteredListbox := nil;
    +  ListFilterEdit.FilteredListbox := ListBox;
    +  UpdateButtonState;
    +  Result := inherited ShowModal;
    +end;
    +
    +end.
    +
    
    patch.diff (12,614 bytes)
  • patch_v2.diff (12,644 bytes)
    Index: designer/designer.pp
    ===================================================================
    --- designer/designer.pp	(revision 52005)
    +++ designer/designer.pp	(working copy)
    @@ -100,6 +100,7 @@
     
       TDesigner = class(TComponentEditorDesigner)
       private
    +    FChangeParentCandidatesAsText: string;
         FDesignerPopupMenu: TPopupMenu;
         FDefaultFormBounds: TRect;
         FLastFormBounds: TRect;
    @@ -410,7 +411,7 @@
       DesignerMenuSelectAll: TIDEMenuCommand;
     
       DesignerMenuChangeClass: TIDEMenuCommand;
    -  DesignerMenuChangeParent: TIDEMenuSection;
    +  DesignerMenuChangeParent: TIDEMenuCommand;
       DesignerMenuViewLFM: TIDEMenuCommand;
       DesignerMenuSaveAsXML: TIDEMenuCommand;
       DesignerMenuCenterForm: TIDEMenuCommand;
    @@ -425,6 +426,8 @@
     
     implementation
     
    +uses SelectStringDialog;
    +
     type
       TCustomFormAccess = class(TCustomForm);
       TControlAccess = class(TControl);
    @@ -600,10 +603,8 @@
       DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
         DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                      'Change class',lisDlgChangeClass);
    -    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
    -                                                 'Change parent');
    -    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
    -    DesignerMenuChangeParent.Caption:=lisChangeParent;
    +    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    +                                                 'Change parent',lisChangeParent+'...');
         DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                     'View LFM',lisViewSourceLfm);
         DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    @@ -3265,15 +3266,25 @@
     
     procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
     var
    -  Item: TIDEMenuCommand;
    +  SelectStringDlg: TSelectStringDlg;
       NewParentName: String;
       i: Integer;
       CurControl: TControl;
       NewParent: TWinControl;
     begin
    -  if not (Sender is TIDEMenuCommand) then Exit;
    -  Item := TIDEMenuCommand(Sender);
    -  NewParentName := Item.Caption;
    +  SelectStringDlg := TSelectStringDlg.Create(nil);
    +  try
    +    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
    +    FChangeParentCandidatesAsText := '';
    +    SelectStringDlg.Caption := lisChangeParent;
    +    if SelectStringDlg.ShowModal = mrOK then
    +      NewParentName := SelectStringDlg.SelectedItem
    +    else
    +      Exit;
    +  finally
    +    SelectStringDlg.Free;
    +  end;
    +
       if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
         NewParent := TWinControl(LookupRoot)
       else
    @@ -3886,6 +3897,7 @@
       DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
     
       DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
    +  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
       DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
       DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
       DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
    @@ -3964,23 +3976,29 @@
         Result.Add(LookupRoot);
       end;
     
    +  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
    +  var
    +    sl: TStringList;
    +    i: Integer;
    +  begin
    +    sl := TStringList.Create;
    +    try
    +      for i:=0 to ACandidates.Count-1 do
    +        sl.Append(TWinControl(ACandidates[i]).Name);
    +      Result := sl.Text;
    +    finally
    +      sl.Free;
    +    end;
    +  end;
    +
       procedure UpdateChangeParentMenu;
       var
         Candidates: TFPList;
    -    i: Integer;
    -    Item: TIDEMenuItem;
       begin
    -    Candidates:=GetChangeParentCandidates;
    +    Candidates := GetChangeParentCandidates;
         try
    -      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
    -      DesignerMenuChangeParent.Clear;
    -      for i:=0 to Candidates.Count-1 do
    -      begin
    -        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
    -        DesignerMenuChangeParent.AddLast(Item);
    -        Item.Caption:=TWinControl(Candidates[i]).Name;
    -        Item.OnClick:=@OnChangeParentMenuClick;
    -      end;
    +      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
    +      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
         finally
           Candidates.Free;
         end;
    Index: ide/lazarus.lpi
    ===================================================================
    --- ide/lazarus.lpi	(revision 52005)
    +++ ide/lazarus.lpi	(working copy)
    @@ -66,7 +66,7 @@
             <PackageName Value="SynEdit"/>
           </Item7>
         </RequiredPackages>
    -    <Units Count="241">
    +    <Units Count="242">
           <Unit0>
             <Filename Value="lazarus.pp"/>
             <IsPartOfProject Value="True"/>
    @@ -309,6 +309,7 @@
           <Unit39>
             <Filename Value="../designer/designer.pp"/>
             <IsPartOfProject Value="True"/>
    +        <UnitName Value="Designer"/>
           </Unit39>
           <Unit40>
             <Filename Value="../designer/designerprocs.pas"/>
    @@ -1348,6 +1349,14 @@
             <ResourceBaseClass Value="Form"/>
             <UnitName Value="DefinesGui"/>
           </Unit240>
    +      <Unit241>
    +        <Filename Value="selectstringdialog.pas"/>
    +        <IsPartOfProject Value="True"/>
    +        <ComponentName Value="SelectStringDlg"/>
    +        <HasResources Value="True"/>
    +        <ResourceBaseClass Value="Form"/>
    +        <UnitName Value="SelectStringDialog"/>
    +      </Unit241>
         </Units>
       </ProjectOptions>
       <CompilerOptions>
    Index: ide/selectstringdialog.lfm
    ===================================================================
    --- ide/selectstringdialog.lfm	(revision 0)
    +++ ide/selectstringdialog.lfm	(revision 0)
    @@ -0,0 +1,66 @@
    +object SelectStringDlg: TSelectStringDlg
    +  Left = 550
    +  Height = 390
    +  Top = 217
    +  Width = 290
    +  Caption = 'SelectStringDlg'
    +  ClientHeight = 390
    +  ClientWidth = 290
    +  OnCreate = FormCreate
    +  Position = poScreenCenter
    +  LCLVersion = '1.7'
    +  object ListFilterEdit: TListFilterEdit
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = Owner
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    Left = 6
    +    Height = 21
    +    Top = 6
    +    Width = 278
    +    OnAfterFilter = ListFilterEditAfterFilter
    +    ButtonWidth = 23
    +    NumGlyphs = 1
    +    Anchors = [akTop, akLeft, akRight]
    +    BorderSpacing.Around = 6
    +    MaxLength = 0
    +    TabOrder = 0
    +  end
    +  object ListBox: TListBox
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = ListFilterEdit
    +    AnchorSideTop.Side = asrBottom
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = ButtonPanel
    +    Left = 6
    +    Height = 319
    +    Top = 33
    +    Width = 278
    +    Anchors = [akTop, akLeft, akRight, akBottom]
    +    BorderSpacing.Around = 6
    +    ItemHeight = 0
    +    OnDblClick = ListBoxDblClick
    +    OnSelectionChange = ListBoxSelectionChange
    +    TabOrder = 1
    +  end
    +  object ButtonPanel: TButtonPanel
    +    Left = 6
    +    Height = 26
    +    Top = 358
    +    Width = 278
    +    OKButton.Name = 'OKButton'
    +    OKButton.DefaultCaption = True
    +    OKButton.OnClick = OKButtonClick
    +    HelpButton.Name = 'HelpButton'
    +    HelpButton.DefaultCaption = True
    +    HelpButton.OnClick = HelpButtonClick
    +    CloseButton.Name = 'CloseButton'
    +    CloseButton.DefaultCaption = True
    +    CancelButton.Name = 'CancelButton'
    +    CancelButton.DefaultCaption = True
    +    TabOrder = 2
    +    ShowButtons = [pbOK, pbCancel, pbHelp]
    +    ShowBevel = False
    +  end
    +end
    Index: ide/selectstringdialog.pas
    ===================================================================
    --- ide/selectstringdialog.pas	(revision 0)
    +++ ide/selectstringdialog.pas	(revision 0)
    @@ -0,0 +1,156 @@
    +{ /***************************************************************************
    +                 SelectStringDialog.pas - Lazarus IDE unit
    +                 -----------------------------------------
    +
    + ***************************************************************************/
    +
    + ***************************************************************************
    + *                                                                         *
    + *   This source is free software; you can redistribute it and/or modify   *
    + *   it under the terms of the GNU General Public License as published by  *
    + *   the Free Software Foundation; either version 2 of the License, or     *
    + *   (at your option) any later version.                                   *
    + *                                                                         *
    + *   This code is distributed in the hope that it will be useful, but      *
    + *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
    + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
    + *   General Public License for more details.                              *
    + *                                                                         *
    + *   A copy of the GNU General Public License is available on the World    *
    + *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
    + *   obtain it by writing to the Free Software Foundation,                 *
    + *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
    + *                                                                         *
    + ***************************************************************************
    +
    +  Author: FTurtle
    +
    +  Abstract:
    +    A generic reusable dialog for choosing string from list.
    +}
    +
    +unit SelectStringDialog;
    +
    +{$mode objfpc}{$H+}
    +
    +interface
    +
    +uses
    +  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
    +  Dialogs, StdCtrls, ButtonPanel;
    +
    +type
    +
    +  { TSelectStringDlg }
    +
    +  TSelectStringDlg = class(TForm)
    +    ButtonPanel: TButtonPanel;
    +    ListBox: TListBox;
    +    ListFilterEdit: TListFilterEdit;
    +    procedure FormCreate(Sender: TObject);
    +    procedure HelpButtonClick(Sender: TObject);
    +    procedure ListBoxDblClick(Sender: TObject);
    +    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
    +    procedure ListFilterEditAfterFilter(Sender: TObject);
    +    procedure OKButtonClick(Sender: TObject);
    +  private
    +    FHelpURL: string;
    +    function GetSelectedItem: string;
    +    procedure SetHelpURL(AValue: string);
    +    procedure SetSelectedItem(AValue: string);
    +    procedure UpdateButtonState;
    +  public
    +    function ShowModal: Integer; override;
    +  public
    +    property HelpURL: string read FHelpURL write SetHelpURL;
    +    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
    +  end;
    +
    +implementation
    +
    +uses LCLIntf;
    +
    +{$R *.lfm}
    +
    +{ TSelectStringDlg }
    +
    +procedure TSelectStringDlg.FormCreate(Sender: TObject);
    +begin
    +  Caption := '';
    +  HelpURL := '';
    +end;
    +
    +procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
    +begin
    +  OpenURL(FHelpURL);
    +end;
    +
    +procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
    +begin
    +  ButtonPanel.OKButton.Click;
    +end;
    +
    +{$HINTS OFF}
    +procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
    +begin
    +  UpdateButtonState;
    +end;
    +{$HINTS ON}
    +
    +procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
    +begin
    +  UpdateButtonState;
    +end;
    +
    +procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
    +begin
    +  if ListBox.ItemIndex < 0 then
    +    ModalResult := mrNone;
    +end;
    +
    +procedure TSelectStringDlg.SetHelpURL(AValue: string);
    +begin
    +  FHelpURL := AValue;
    +  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
    +end;
    +
    +function TSelectStringDlg.GetSelectedItem: string;
    +begin
    +  if ListBox.ItemIndex > -1 then
    +    Result := ListBox.Items[ListBox.ItemIndex]
    +  else
    +    Result := '';
    +end;
    +
    +procedure TSelectStringDlg.SetSelectedItem(AValue: string);
    +var
    +  i: Integer;
    +begin
    +  i := ListBox.Items.IndexOf(AValue);
    +  if i > -1 then
    +    ListBox.ItemIndex := i;
    +end;
    +
    +procedure TSelectStringDlg.UpdateButtonState;
    +begin
    +  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
    +end;
    +
    +function TSelectStringDlg.ShowModal: Integer;
    +const
    +  MinWidth = 250;
    +  MinHeight = 250;
    +begin
    +  Constraints.MinHeight := MinHeight;
    +  if ButtonPanel.HelpButton.Visible then
    +    Constraints.MinWidth := MinWidth
    +  else
    +    Constraints.MinWidth := MinWidth - 75;
    +  ListFilterEdit.FilteredListbox := nil;
    +  ListFilterEdit.FilteredListbox := ListBox;
    +  UpdateButtonState;
    +  Result := inherited ShowModal;
    +end;
    +
    +end.
    +
    
    patch_v2.diff (12,644 bytes)
  • patch_v3.diff (12,689 bytes)
    Index: designer/designer.pp
    ===================================================================
    --- designer/designer.pp	(revision 52005)
    +++ designer/designer.pp	(working copy)
    @@ -100,6 +100,7 @@
     
       TDesigner = class(TComponentEditorDesigner)
       private
    +    FChangeParentCandidatesAsText: string;
         FDesignerPopupMenu: TPopupMenu;
         FDefaultFormBounds: TRect;
         FLastFormBounds: TRect;
    @@ -410,7 +411,7 @@
       DesignerMenuSelectAll: TIDEMenuCommand;
     
       DesignerMenuChangeClass: TIDEMenuCommand;
    -  DesignerMenuChangeParent: TIDEMenuSection;
    +  DesignerMenuChangeParent: TIDEMenuCommand;
       DesignerMenuViewLFM: TIDEMenuCommand;
       DesignerMenuSaveAsXML: TIDEMenuCommand;
       DesignerMenuCenterForm: TIDEMenuCommand;
    @@ -425,6 +426,8 @@
     
     implementation
     
    +uses SelectStringDialog;
    +
     type
       TCustomFormAccess = class(TCustomForm);
       TControlAccess = class(TControl);
    @@ -600,10 +603,8 @@
       DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
         DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                      'Change class',lisDlgChangeClass);
    -    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
    -                                                 'Change parent');
    -    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
    -    DesignerMenuChangeParent.Caption:=lisChangeParent;
    +    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    +                                                 'Change parent',lisChangeParent+'...');
         DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                     'View LFM',lisViewSourceLfm);
         DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    @@ -3265,15 +3266,25 @@
     
     procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
     var
    -  Item: TIDEMenuCommand;
    +  SelectStringDlg: TSelectStringDlg;
       NewParentName: String;
       i: Integer;
       CurControl: TControl;
       NewParent: TWinControl;
     begin
    -  if not (Sender is TIDEMenuCommand) then Exit;
    -  Item := TIDEMenuCommand(Sender);
    -  NewParentName := Item.Caption;
    +  SelectStringDlg := TSelectStringDlg.Create(nil);
    +  try
    +    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
    +    FChangeParentCandidatesAsText := '';
    +    SelectStringDlg.Caption := lisChangeParent;
    +    if SelectStringDlg.ShowModal = mrOK then
    +      NewParentName := SelectStringDlg.SelectedItem
    +    else
    +      Exit;
    +  finally
    +    SelectStringDlg.Free;
    +  end;
    +
       if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
         NewParent := TWinControl(LookupRoot)
       else
    @@ -3886,6 +3897,7 @@
       DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
     
       DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
    +  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
       DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
       DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
       DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
    @@ -3964,23 +3976,29 @@
         Result.Add(LookupRoot);
       end;
     
    +  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
    +  var
    +    sl: TStringList;
    +    i: Integer;
    +  begin
    +    sl := TStringList.Create;
    +    try
    +      for i:=0 to ACandidates.Count-1 do
    +        sl.Append(TWinControl(ACandidates[i]).Name);
    +      Result := sl.Text;
    +    finally
    +      sl.Free;
    +    end;
    +  end;
    +
       procedure UpdateChangeParentMenu;
       var
         Candidates: TFPList;
    -    i: Integer;
    -    Item: TIDEMenuItem;
       begin
    -    Candidates:=GetChangeParentCandidates;
    +    Candidates := GetChangeParentCandidates;
         try
    -      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
    -      DesignerMenuChangeParent.Clear;
    -      for i:=0 to Candidates.Count-1 do
    -      begin
    -        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
    -        DesignerMenuChangeParent.AddLast(Item);
    -        Item.Caption:=TWinControl(Candidates[i]).Name;
    -        Item.OnClick:=@OnChangeParentMenuClick;
    -      end;
    +      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
    +      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
         finally
           Candidates.Free;
         end;
    Index: ide/lazarus.lpi
    ===================================================================
    --- ide/lazarus.lpi	(revision 52005)
    +++ ide/lazarus.lpi	(working copy)
    @@ -66,7 +66,7 @@
             <PackageName Value="SynEdit"/>
           </Item7>
         </RequiredPackages>
    -    <Units Count="241">
    +    <Units Count="242">
           <Unit0>
             <Filename Value="lazarus.pp"/>
             <IsPartOfProject Value="True"/>
    @@ -309,6 +309,7 @@
           <Unit39>
             <Filename Value="../designer/designer.pp"/>
             <IsPartOfProject Value="True"/>
    +        <UnitName Value="Designer"/>
           </Unit39>
           <Unit40>
             <Filename Value="../designer/designerprocs.pas"/>
    @@ -1348,6 +1349,14 @@
             <ResourceBaseClass Value="Form"/>
             <UnitName Value="DefinesGui"/>
           </Unit240>
    +      <Unit241>
    +        <Filename Value="selectstringdialog.pas"/>
    +        <IsPartOfProject Value="True"/>
    +        <ComponentName Value="SelectStringDlg"/>
    +        <HasResources Value="True"/>
    +        <ResourceBaseClass Value="Form"/>
    +        <UnitName Value="SelectStringDialog"/>
    +      </Unit241>
         </Units>
       </ProjectOptions>
       <CompilerOptions>
    Index: ide/selectstringdialog.lfm
    ===================================================================
    --- ide/selectstringdialog.lfm	(revision 0)
    +++ ide/selectstringdialog.lfm	(revision 0)
    @@ -0,0 +1,67 @@
    +object SelectStringDlg: TSelectStringDlg
    +  Left = 550
    +  Height = 390
    +  Top = 217
    +  Width = 290
    +  BorderIcons = [biSystemMenu, biMaximize]
    +  Caption = 'SelectStringDlg'
    +  ClientHeight = 390
    +  ClientWidth = 290
    +  OnCreate = FormCreate
    +  Position = poScreenCenter
    +  LCLVersion = '1.7'
    +  object ListFilterEdit: TListFilterEdit
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = Owner
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    Left = 6
    +    Height = 21
    +    Top = 6
    +    Width = 278
    +    OnAfterFilter = ListFilterEditAfterFilter
    +    ButtonWidth = 23
    +    NumGlyphs = 1
    +    Anchors = [akTop, akLeft, akRight]
    +    BorderSpacing.Around = 6
    +    MaxLength = 0
    +    TabOrder = 0
    +  end
    +  object ListBox: TListBox
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = ListFilterEdit
    +    AnchorSideTop.Side = asrBottom
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = ButtonPanel
    +    Left = 6
    +    Height = 319
    +    Top = 33
    +    Width = 278
    +    Anchors = [akTop, akLeft, akRight, akBottom]
    +    BorderSpacing.Around = 6
    +    ItemHeight = 0
    +    OnDblClick = ListBoxDblClick
    +    OnSelectionChange = ListBoxSelectionChange
    +    TabOrder = 1
    +  end
    +  object ButtonPanel: TButtonPanel
    +    Left = 6
    +    Height = 26
    +    Top = 358
    +    Width = 278
    +    OKButton.Name = 'OKButton'
    +    OKButton.DefaultCaption = True
    +    OKButton.OnClick = OKButtonClick
    +    HelpButton.Name = 'HelpButton'
    +    HelpButton.DefaultCaption = True
    +    HelpButton.OnClick = HelpButtonClick
    +    CloseButton.Name = 'CloseButton'
    +    CloseButton.DefaultCaption = True
    +    CancelButton.Name = 'CancelButton'
    +    CancelButton.DefaultCaption = True
    +    TabOrder = 2
    +    ShowButtons = [pbOK, pbCancel, pbHelp]
    +    ShowBevel = False
    +  end
    +end
    Index: ide/selectstringdialog.pas
    ===================================================================
    --- ide/selectstringdialog.pas	(revision 0)
    +++ ide/selectstringdialog.pas	(revision 0)
    @@ -0,0 +1,156 @@
    +{ /***************************************************************************
    +                 SelectStringDialog.pas - Lazarus IDE unit
    +                 -----------------------------------------
    +
    + ***************************************************************************/
    +
    + ***************************************************************************
    + *                                                                         *
    + *   This source is free software; you can redistribute it and/or modify   *
    + *   it under the terms of the GNU General Public License as published by  *
    + *   the Free Software Foundation; either version 2 of the License, or     *
    + *   (at your option) any later version.                                   *
    + *                                                                         *
    + *   This code is distributed in the hope that it will be useful, but      *
    + *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
    + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
    + *   General Public License for more details.                              *
    + *                                                                         *
    + *   A copy of the GNU General Public License is available on the World    *
    + *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
    + *   obtain it by writing to the Free Software Foundation,                 *
    + *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
    + *                                                                         *
    + ***************************************************************************
    +
    +  Author: FTurtle
    +
    +  Abstract:
    +    A generic reusable dialog for choosing string from list.
    +}
    +
    +unit SelectStringDialog;
    +
    +{$mode objfpc}{$H+}
    +
    +interface
    +
    +uses
    +  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
    +  Dialogs, StdCtrls, ButtonPanel;
    +
    +type
    +
    +  { TSelectStringDlg }
    +
    +  TSelectStringDlg = class(TForm)
    +    ButtonPanel: TButtonPanel;
    +    ListBox: TListBox;
    +    ListFilterEdit: TListFilterEdit;
    +    procedure FormCreate(Sender: TObject);
    +    procedure HelpButtonClick(Sender: TObject);
    +    procedure ListBoxDblClick(Sender: TObject);
    +    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
    +    procedure ListFilterEditAfterFilter(Sender: TObject);
    +    procedure OKButtonClick(Sender: TObject);
    +  private
    +    FHelpURL: string;
    +    function GetSelectedItem: string;
    +    procedure SetHelpURL(AValue: string);
    +    procedure SetSelectedItem(AValue: string);
    +    procedure UpdateButtonState;
    +  public
    +    function ShowModal: Integer; override;
    +  public
    +    property HelpURL: string read FHelpURL write SetHelpURL;
    +    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
    +  end;
    +
    +implementation
    +
    +uses LCLIntf;
    +
    +{$R *.lfm}
    +
    +{ TSelectStringDlg }
    +
    +procedure TSelectStringDlg.FormCreate(Sender: TObject);
    +begin
    +  Caption := '';
    +  HelpURL := '';
    +end;
    +
    +procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
    +begin
    +  OpenURL(FHelpURL);
    +end;
    +
    +procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
    +begin
    +  ButtonPanel.OKButton.Click;
    +end;
    +
    +{$HINTS OFF}
    +procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
    +begin
    +  UpdateButtonState;
    +end;
    +{$HINTS ON}
    +
    +procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
    +begin
    +  UpdateButtonState;
    +end;
    +
    +procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
    +begin
    +  if ListBox.ItemIndex < 0 then
    +    ModalResult := mrNone;
    +end;
    +
    +procedure TSelectStringDlg.SetHelpURL(AValue: string);
    +begin
    +  FHelpURL := AValue;
    +  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
    +end;
    +
    +function TSelectStringDlg.GetSelectedItem: string;
    +begin
    +  if ListBox.ItemIndex > -1 then
    +    Result := ListBox.Items[ListBox.ItemIndex]
    +  else
    +    Result := '';
    +end;
    +
    +procedure TSelectStringDlg.SetSelectedItem(AValue: string);
    +var
    +  i: Integer;
    +begin
    +  i := ListBox.Items.IndexOf(AValue);
    +  if i > -1 then
    +    ListBox.ItemIndex := i;
    +end;
    +
    +procedure TSelectStringDlg.UpdateButtonState;
    +begin
    +  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
    +end;
    +
    +function TSelectStringDlg.ShowModal: Integer;
    +const
    +  MinWidth = 250;
    +  MinHeight = 250;
    +begin
    +  Constraints.MinHeight := MinHeight;
    +  if ButtonPanel.HelpButton.Visible then
    +    Constraints.MinWidth := MinWidth
    +  else
    +    Constraints.MinWidth := MinWidth - 75;
    +  ListFilterEdit.FilteredListbox := nil;
    +  ListFilterEdit.FilteredListbox := ListBox;
    +  UpdateButtonState;
    +  Result := inherited ShowModal;
    +end;
    +
    +end.
    +
    
    patch_v3.diff (12,689 bytes)
  • patch_v4.diff (26,443 bytes)
    Index: components/ideintf/changeparentdlg.lfm
    ===================================================================
    --- components/ideintf/changeparentdlg.lfm	(revision 0)
    +++ components/ideintf/changeparentdlg.lfm	(revision 0)
    @@ -0,0 +1,110 @@
    +object ChangeParentDlg: TChangeParentDlg
    +  Left = 550
    +  Height = 386
    +  Top = 217
    +  Width = 248
    +  BorderIcons = [biSystemMenu, biMaximize]
    +  Caption = 'ChangeParentDlg'
    +  ClientHeight = 386
    +  ClientWidth = 248
    +  OnClose = FormClose
    +  OnCreate = FormCreate
    +  Position = poScreenCenter
    +  LCLVersion = '1.7'
    +  object ListFilterEdit: TListFilterEdit
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = Owner
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    Left = 6
    +    Height = 21
    +    Top = 6
    +    Width = 236
    +    OnAfterFilter = ListFilterEditAfterFilter
    +    ButtonWidth = 23
    +    NumGlyphs = 1
    +    Anchors = [akTop, akLeft, akRight]
    +    BorderSpacing.Around = 6
    +    MaxLength = 0
    +    TabOrder = 0
    +  end
    +  object ListBox: TListBox
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = ListFilterEdit
    +    AnchorSideTop.Side = asrBottom
    +    AnchorSideRight.Control = Owner
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = chShowClasses
    +    Left = 6
    +    Height = 260
    +    Top = 33
    +    Width = 236
    +    Anchors = [akTop, akLeft, akRight, akBottom]
    +    BorderSpacing.Around = 6
    +    ItemHeight = 0
    +    OnDblClick = ListBoxDblClick
    +    OnSelectionChange = ListBoxSelectionChange
    +    TabOrder = 1
    +  end
    +  object ButtonPanel: TButtonPanel
    +    Left = 6
    +    Height = 26
    +    Top = 354
    +    Width = 236
    +    OKButton.Name = 'OKButton'
    +    OKButton.DefaultCaption = True
    +    OKButton.OnClick = OKButtonClick
    +    HelpButton.Name = 'HelpButton'
    +    HelpButton.DefaultCaption = True
    +    CloseButton.Name = 'CloseButton'
    +    CloseButton.DefaultCaption = True
    +    CancelButton.Name = 'CancelButton'
    +    CancelButton.DefaultCaption = True
    +    TabOrder = 2
    +    ShowButtons = [pbOK, pbCancel]
    +    ShowBevel = False
    +  end
    +  object lblSelectedControls: TLabel
    +    AnchorSideLeft.Control = ListBox
    +    AnchorSideRight.Control = ListBox
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = lblCurentParents
    +    Left = 6
    +    Height = 13
    +    Top = 319
    +    Width = 236
    +    Anchors = [akLeft, akRight, akBottom]
    +    BorderSpacing.Bottom = 3
    +    Caption = 'lblSelectedControls'
    +    ParentColor = False
    +    ParentFont = False
    +    WordWrap = True
    +  end
    +  object lblCurentParents: TLabel
    +    AnchorSideLeft.Control = ListBox
    +    AnchorSideRight.Control = ListBox
    +    AnchorSideRight.Side = asrBottom
    +    AnchorSideBottom.Control = ButtonPanel
    +    Left = 6
    +    Height = 13
    +    Top = 335
    +    Width = 236
    +    Anchors = [akLeft, akRight, akBottom]
    +    Caption = 'lblCurentParents'
    +    ParentColor = False
    +    WordWrap = True
    +  end
    +  object chShowClasses: TCheckBox
    +    AnchorSideLeft.Control = ListBox
    +    AnchorSideBottom.Control = lblSelectedControls
    +    Left = 6
    +    Height = 17
    +    Top = 299
    +    Width = 91
    +    Anchors = [akLeft, akBottom]
    +    BorderSpacing.Bottom = 3
    +    Caption = 'chShowClasses'
    +    OnClick = chShowClassesClick
    +    TabOrder = 3
    +  end
    +end
    Index: components/ideintf/changeparentdlg.pas
    ===================================================================
    --- components/ideintf/changeparentdlg.pas	(revision 0)
    +++ components/ideintf/changeparentdlg.pas	(revision 0)
    @@ -0,0 +1,269 @@
    +{
    + *****************************************************************************
    +  See the file COPYING.modifiedLGPL.txt, included in this distribution,
    +  for details about the license.
    + *****************************************************************************
    +
    +  Author: FTurtle
    +
    +  Abstract:
    +    Dialog for choosing new parent name.
    +}
    +
    +unit ChangeParentDlg;
    +
    +{$mode objfpc}{$H+}
    +
    +interface
    +
    +uses
    +  Classes, SysUtils, strutils, FileUtil, ListFilterEdit, PropEditUtils, Forms,
    +  Controls, Graphics, Dialogs, StdCtrls, ButtonPanel;
    +
    +type
    +
    +  { TChangeParentDlg }
    +
    +  TChangeParentDlg = class(TForm)
    +    ButtonPanel: TButtonPanel;
    +    chShowClasses: TCheckBox;
    +    lblSelectedControls: TLabel;
    +    lblCurentParents: TLabel;
    +    ListBox: TListBox;
    +    ListFilterEdit: TListFilterEdit;
    +    procedure chShowClassesClick(Sender: TObject);
    +    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    +    procedure FormCreate(Sender: TObject);
    +    procedure ListBoxDblClick(Sender: TObject);
    +    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
    +    procedure ListFilterEditAfterFilter(Sender: TObject);
    +    procedure OKButtonClick(Sender: TObject);
    +  private
    +    class var
    +      FSavedWidth: Integer;
    +      FSavedHeight: Integer;
    +      FSavedShowClasses: Boolean;
    +  private
    +    FCandidates: TFPList;
    +    FIgnoredCandidateName: string;
    +    function GetSelectedItem: string;
    +    procedure RefreshList;
    +    procedure SetSelection(ASelection: TPersistentSelectionList);
    +    procedure UpdateOKButtonState;
    +  public
    +    function ShowModal: Integer; override;
    +  public
    +    property SelectedItem: string read GetSelectedItem;
    +    property Selection: TPersistentSelectionList write SetSelection;
    +    property Candidates: TFPList write FCandidates;
    +  end;
    +
    +function ShowChangeParentDlg(var ANewParentName: string;
    +  ASelection: TPersistentSelectionList; ACandidates: TFPList): Boolean;
    +
    +
    +implementation
    +
    +uses LCLIntf, ObjInspStrConsts;
    +
    +{$R *.lfm}
    +
    +{ TChangeParentDlg }
    +
    +const
    +  colon = ': ';
    +
    +function ShowChangeParentDlg(var ANewParentName: string;
    +  ASelection: TPersistentSelectionList; ACandidates: TFPList): Boolean;
    +begin
    +  if not Assigned(ASelection) or not Assigned(ACandidates) then
    +    Exit(False);
    +
    +  with TChangeParentDlg.Create(nil) do
    +  try
    +    Selection := ASelection;
    +    Candidates := ACandidates;
    +    Result := (ShowModal = mrOK);
    +    if Result then
    +      ANewParentName := SelectedItem;
    +  finally
    +    Free;
    +  end;
    +end;
    +
    +
    +procedure TChangeParentDlg.FormCreate(Sender: TObject);
    +begin
    +  Constraints.MinHeight := 250;
    +  Constraints.MinWidth := 175;
    +
    +  Height := FSavedHeight;  // see "initialization"
    +  Width := FSavedWidth;
    +  chShowClasses.Checked := FSavedShowClasses;
    +
    +  Caption := oisChangeParent;
    +  chShowClasses.Caption := oisShowClasses;
    +end;
    +
    +{$HINTS OFF}
    +procedure TChangeParentDlg.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    +begin
    +  FSavedHeight := Height;
    +  FSavedWidth := Width;
    +  FSavedShowClasses := chShowClasses.Checked;
    +end;
    +{$HINTS ON}
    +
    +procedure TChangeParentDlg.chShowClassesClick(Sender: TObject);
    +begin
    +  if Assigned(FCandidates) then
    +    RefreshList;
    +end;
    +
    +procedure TChangeParentDlg.ListBoxDblClick(Sender: TObject);
    +begin
    +  ButtonPanel.OKButton.Click;
    +end;
    +
    +{$HINTS OFF}
    +procedure TChangeParentDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
    +begin
    +  UpdateOKButtonState;
    +end;
    +{$HINTS ON}
    +
    +procedure TChangeParentDlg.ListFilterEditAfterFilter(Sender: TObject);
    +begin
    +  UpdateOKButtonState;
    +end;
    +
    +procedure TChangeParentDlg.OKButtonClick(Sender: TObject);
    +begin
    +  if ListBox.ItemIndex < 0 then
    +    ModalResult := mrNone;
    +end;
    +
    +function TChangeParentDlg.GetSelectedItem: string;
    +var
    +  n: Integer;
    +begin
    +  if ListBox.ItemIndex < 0 then
    +    Exit('');
    +  Result := ListBox.Items[ListBox.ItemIndex];
    +  n := Pos(colon, Result);
    +  if n>0 then
    +    SetLength(Result, n-1);
    +end;
    +
    +procedure TChangeParentDlg.RefreshList;
    +var
    +  i: Integer;
    +  OldIndex: Integer;
    +
    +  function MakeItem(ACandidate: TWinControl): string;
    +  begin
    +    if chShowClasses.Checked then
    +      Result := ACandidate.Name + colon + ACandidate.ClassName
    +    else
    +      Result := ACandidate.Name;
    +  end;
    +
    +  function IsIgnoredName: Boolean;
    +  begin
    +    Result := (TWinControl(FCandidates.Items[i]).Name = FIgnoredCandidateName);
    +  end;
    +
    +begin
    +  OldIndex := ListBox.ItemIndex;
    +  ListFilterEdit.FilteredListbox := nil;
    +  ListBox.Items.Clear;
    +  for i:=0 to FCandidates.Count-1 do
    +    if not IsIgnoredName then
    +      ListBox.Items.Add(MakeItem(TWinControl(FCandidates.Items[i])));
    +  ListBox.ItemIndex := OldIndex;  // if list was filtered it may select other item
    +  ListFilterEdit.FilteredListbox := ListBox;
    +  ListFilterEdit.Text := '';
    +  UpdateOKButtonState;
    +end;
    +
    +procedure TChangeParentDlg.SetSelection(ASelection: TPersistentSelectionList);
    +var
    +  i, ControlsCount: Integer;
    +  sControls, sParents: string;
    +  CurParentNameList: TStringList;
    +
    +  procedure AddControlName(AControlName: string);
    +  begin
    +    Inc(ControlsCount);
    +    if ControlsCount = 1 then
    +      sControls := AControlName
    +    else
    +      sControls := sControls + ', ' + AControlName;
    +  end;
    +
    +  procedure TryAddParentName(AParentName: string);
    +  begin
    +    if CurParentNameList.IndexOf(AParentName) < 0 then
    +      CurParentNameList.Append(AParentName);
    +  end;
    +
    +  procedure SetIgnoredCandidateName;
    +  var
    +    j: Integer;
    +  begin
    +    FIgnoredCandidateName := CurParentNameList[0];
    +    for j:=1 to CurParentNameList.Count-1 do
    +      if FIgnoredCandidateName <> CurParentNameList[j] then
    +      begin
    +        FIgnoredCandidateName := '';
    +        Break;
    +      end;
    +  end;
    +
    +begin
    +  ControlsCount := 0;
    +  CurParentNameList := TStringList.Create;
    +
    +  for i:=0 to ASelection.Count-1 do
    +    if ASelection.Items[i] is TControl then
    +      begin
    +        AddControlName(TControl(ASelection.Items[i]).Name);
    +        TryAddParentName(TControl(ASelection.Items[i]).Parent.Name);
    +      end;
    +
    +  sControls := IfThen(ControlsCount > 1, oisSelectedControls, oisSelectedControl) +
    +    ': ' + sControls;
    +
    +  if CurParentNameList.Count > 0 then
    +  begin
    +    sParents := IfThen(CurParentNameList.Count > 1, oisCurrentParents, oisCurrentParent) +
    +      ': ' + CurParentNameList[0];
    +    for i:=1 to CurParentNameList.Count-1 do
    +      sParents := sParents + ', ' + CurParentNameList[i];
    +    SetIgnoredCandidateName;
    +  end;
    +
    +  lblSelectedControls.Caption := sControls;
    +  lblCurentParents.Caption := sParents;
    +
    +  CurParentNameList.Free;
    +end;
    +
    +procedure TChangeParentDlg.UpdateOKButtonState;
    +begin
    +  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
    +end;
    +
    +function TChangeParentDlg.ShowModal: Integer;
    +begin
    +  RefreshList;
    +  Result := inherited ShowModal;
    +end;
    +
    +initialization
    +  TChangeParentDlg.FSavedWidth := 250;
    +  TChangeParentDlg.FSavedHeight := 390;
    +  TChangeParentDlg.FSavedShowClasses := False;
    +
    +end.
    +
    Index: components/ideintf/ideintf.lpk
    ===================================================================
    --- components/ideintf/ideintf.lpk	(revision 52108)
    +++ components/ideintf/ideintf.lpk	(working copy)
    @@ -20,7 +20,7 @@
         <Description Value="IDEIntf - the interface units for the Lazarus IDE"/>
         <License Value="Modified LPGL2"/>
         <Version Major="1"/>
    -    <Files Count="78">
    +    <Files Count="80">
           <Item1>
             <Filename Value="actionseditor.pas"/>
             <UnitName Value="ActionsEditor"/>
    @@ -334,6 +334,14 @@
             <Filename Value="toolbarintf.pas"/>
             <UnitName Value="ToolBarIntf"/>
           </Item78>
    +      <Item79>
    +        <Filename Value="changeparentdlg.pas"/>
    +        <UnitName Value="ChangeParentDlg"/>
    +      </Item79>
    +      <Item80>
    +        <Filename Value="changeparentdlg.lfm"/>
    +        <Type Value="LFM"/>
    +      </Item80>
         </Files>
         <LazDoc Paths="docs"/>
         <i18n>
    Index: components/ideintf/ideintf.pas
    ===================================================================
    --- components/ideintf/ideintf.pas	(revision 52108)
    +++ components/ideintf/ideintf.pas	(working copy)
    @@ -21,7 +21,7 @@
       PackageIntf, ProjectIntf, ProjectResourcesIntf, PropEdits, PropEditUtils, 
       SrcEditorIntf, StatusBarPropEdit, StringsPropEditDlg, TextTools, 
       TreeViewPropEdit, UnitResources, ProjPackIntf, DBGridColumnsPropEditForm, 
    -  ToolBarIntf, LazarusPackageIntf;
    +  ToolBarIntf, ChangeParentDlg, LazarusPackageIntf;
     
     implementation
     
    Index: components/ideintf/objectinspector.pp
    ===================================================================
    --- components/ideintf/objectinspector.pp	(revision 52108)
    +++ components/ideintf/objectinspector.pp	(working copy)
    @@ -712,7 +712,7 @@
         FOnNodeGetImageIndex: TOnOINodeGetImageEvent;
         procedure CreateTopSplitter;
         procedure CreateBottomSplitter;
    -    function GetChangeParentCandidates: TFPList;
    +    function GetParentCandidates: TFPList;
         function GetGridControl(Page: TObjectInspectorPage): TOICustomPropertyGrid;
         procedure SetComponentEditor(const AValue: TBaseComponentEditor);
         procedure SetFavorites(const AValue: TOIFavoriteProperties);
    @@ -776,6 +776,8 @@
         function GetActivePropertyGrid: TOICustomPropertyGrid;
         function GetActivePropertyRow: TOIPropertyGridRow;
         function GetCurRowDefaultValue(var DefaultStr: string): Boolean;
    +    function GetHasParentCandidates: Boolean;
    +    procedure ChangeParent;
         procedure HookRefreshPropertyValues;
         procedure ActivateGrid(Grid: TOICustomPropertyGrid);
         procedure FocusGrid(Grid: TOICustomPropertyGrid = nil);
    @@ -841,7 +843,7 @@
     {$R images\ideintf_images.res}
     
     uses
    -  math;
    +  math, ChangeParentDlg;
     
     const
       DefaultOIPageNames: array[TObjectInspectorPage] of shortstring = (
    @@ -4108,9 +4110,9 @@
       AddPopupMenuItem(ChangeClassPopupMenuItem,nil,'ChangeClassPopupMenuItem',
          oisChangeClass,'Change Class of component', '',
          @OnChangeClassPopupmenuItemClick,false,true,true);
    -  AddPopupMenuItem(ChangeParentPopupMenuItem,nil,'ChangeParentPopupMenuItem',
    -     oisChangeParent,'Change Parent of component', '',
    -     Nil,false,true,true);
    +  AddPopupMenuItem(ChangeParentPopupMenuItem, nil, 'ChangeParentPopupMenuItem',
    +     oisChangeParent+' ...', 'Change Parent of component', '',
    +     @DoChangeParentItemClick, False, True, True);
       OptionsSeparatorMenuItem3 := AddSeparatorMenuItem(nil, 'OptionsSeparatorMenuItem3', true);
     
       AddPopupMenuItem(ShowComponentTreePopupMenuItem,nil
    @@ -4500,6 +4502,89 @@
       end;
     end;
     
    +function TObjectInspectorDlg.GetHasParentCandidates: Boolean;
    +var
    +  Candidates: TFPList=nil;
    +begin
    +  try
    +    Candidates := GetParentCandidates;
    +    Result := (Candidates.Count>1);  // single candidate is current parent
    +  finally
    +    Candidates.Free;
    +  end;
    +end;
    +
    +procedure TObjectInspectorDlg.ChangeParent;
    +var
    +  i: Integer;
    +  Control: TControl;
    +  NewParentName: String;
    +  NewParent: TPersistent;
    +  NewSelection: TPersistentSelectionList;
    +  Candidates: TFPList = nil;
    +
    +begin
    +  if (Selection.Count < 1) then Exit;
    +
    +  try
    +    Candidates := GetParentCandidates;
    +    if not ShowChangeParentDlg(NewParentName, Selection, Candidates) then
    +      Exit;
    +  finally
    +    Candidates.Free;
    +  end;
    +
    +  if NewParentName = TWinControl(FPropertyEditorHook.LookupRoot).Name then
    +    NewParent := FPropertyEditorHook.LookupRoot
    +  else
    +    NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName);
    +
    +  if not (NewParent is TWinControl) then Exit;
    +
    +  for i := 0 to Selection.Count-1 do
    +  begin
    +    if not (Selection[i] is TControl) then Continue;
    +    Control := TControl(Selection[i]);
    +    if Control.Parent = nil then Continue;
    +    Control.Parent := TWinControl(NewParent);
    +  end;
    +
    +  // Following code taken from DoZOrderItemClick();
    +  // Ensure the order of controls in the OI now reflects the new ZOrder
    +  //NewSelection := TPersistentSelectionList.Create;
    +  //try
    +  //  NewSelection.ForceUpdate:=True;
    +  //  NewSelection.Add(Control.Parent);
    +  //  SetSelection(NewSelection);
    +  //
    +  //  NewSelection.Clear;
    +  //  NewSelection.ForceUpdate:=True;
    +  //  NewSelection.Add(Control);
    +  //  SetSelection(NewSelection);
    +  //finally
    +  //  NewSelection.Free;
    +  //end;
    +
    +  // Ensure the order of controls in the OI now reflects the new ZOrder
    +  // (this code based on commented above)
    +  NewSelection := TPersistentSelectionList.Create;
    +  try
    +    NewSelection.ForceUpdate:=True;
    +    NewSelection.Add(NewParent);
    +    for i:=0 to Selection.Count-1 do
    +      NewSelection.Add(Selection.Items[i]);
    +    SetSelection(NewSelection);
    +
    +    NewSelection.ForceUpdate:=True;
    +    NewSelection.Delete(0);
    +    SetSelection(NewSelection);
    +  finally
    +    NewSelection.Free;
    +  end;
    +
    +  DoModified(Self);
    +end;
    +
     procedure TObjectInspectorDlg.SetSelection(const ASelection: TPersistentSelectionList);
     var
       OldInSelection: Boolean;
    @@ -5316,7 +5401,7 @@
     end;
     // ---
     
    -function TObjectInspectorDlg.GetChangeParentCandidates: TFPList;
    +function TObjectInspectorDlg.GetParentCandidates: TFPList;
     var
       i, j: Integer;
       CurSelected: TPersistent;
    @@ -5482,27 +5567,6 @@
         MainPopupMenu.Items.Insert(ZItem.MenuIndex + 1, Item);
       end;
     
    -  function AddChangeParentMenuItems: Boolean;
    -  var
    -    Item: TMenuItem;
    -    Candidates: TFPList;
    -    i: Integer;
    -  begin
    -    Candidates := GetChangeParentCandidates;
    -    try
    -      Result := Candidates.Count>0;
    -      ChangeParentPopupmenuItem.Clear;
    -      for i := 0 to Candidates.Count-1 do
    -      begin
    -        Item := NewItem(TWinControl(Candidates[i]).Name, 0, False, True,
    -                        @DoChangeParentItemClick, 0, '');
    -        ChangeParentPopupmenuItem.Add(Item);
    -      end;
    -    finally
    -      Candidates.Free;
    -    end;
    -  end;
    -
     var
       b, AtLeastOneComp, CanChangeClass, HasParentCandidates: Boolean;
       CurRow: TOIPropertyGridRow;
    @@ -5540,9 +5604,9 @@
         // add Z-Order menu
         if (Selection.Count = 1) and (Selection[0] is TControl) then
           AddZOrderMenuItems;
    -    // add Change Parent menu
    +    // check existing of Change Parent candidates
         if AtLeastOneComp then
    -      HasParentCandidates := AddChangeParentMenuItems;
    +      HasParentCandidates := GetHasParentCandidates;
       end;
       CutPopupMenuItem.Visible := AtLeastOneComp;
       CopyPopupMenuItem.Visible := AtLeastOneComp;
    @@ -5606,45 +5670,9 @@
     end;
     
     procedure TObjectInspectorDlg.DoChangeParentItemClick(Sender: TObject);
    -var
    -  i: Integer;
    -  Control: TControl;
    -  NewParent: TPersistent;
    -  NewSelection: TPersistentSelectionList;
     begin
    -  if not (Sender is TMenuItem) or (Selection.Count < 1) then Exit;
    -  if TMenuItem(Sender).Caption = TWinControl(FPropertyEditorHook.LookupRoot).Name then
    -    NewParent := FPropertyEditorHook.LookupRoot
    -  else
    -    NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(TMenuItem(Sender).Caption);
    -
    -  if not (NewParent is TWinControl) then Exit;
    -
    -  for i := 0 to Selection.Count-1 do
    -  begin
    -    if not (Selection[i] is TControl) then Continue;
    -    Control := TControl(Selection[i]);
    -    if Control.Parent = nil then Continue;
    -    Control.Parent := TWinControl(NewParent);
    -  end;
    -
    -  // Following code taken from DoZOrderItemClick();
    -  // Ensure the order of controls in the OI now reflects the new ZOrder
    -  NewSelection := TPersistentSelectionList.Create;
    -  try
    -    NewSelection.ForceUpdate:=True;
    -    NewSelection.Add(Control.Parent);
    -    SetSelection(NewSelection);
    -
    -    NewSelection.Clear;
    -    NewSelection.ForceUpdate:=True;
    -    NewSelection.Add(Control);
    -    SetSelection(NewSelection);
    -  finally
    -    NewSelection.Free;
    -  end;
    -
    -  DoModified(Self);
    +  if Selection.Count > 0 then
    +    ChangeParent;
     end;
     
     procedure TObjectInspectorDlg.DoComponentEditorVerbMenuItemClick(Sender: TObject);
    Index: components/ideintf/objinspstrconsts.pas
    ===================================================================
    --- components/ideintf/objinspstrconsts.pas	(revision 52108)
    +++ components/ideintf/objinspstrconsts.pas	(working copy)
    @@ -441,6 +441,13 @@
       oisChangeParent = 'Change Parent';
       lisUnableToFindParserForTool = 'Unable to find parser for tool "%s"';
     
    +  // TChangeParentDlg
    +  oisShowClasses = 'Show classes';
    +  oisSelectedControl = 'Selected control';
    +  oisSelectedControls = 'Selected controls';
    +  oisCurrentParent = 'Current parent';
    +  oisCurrentParents = 'Current parents';
    +
       // Dbgrid Columns editor
       dceAddFields = 'Add Fields';
       dceDeleteAll  = 'Delete All';
    Index: designer/designer.pp
    ===================================================================
    --- designer/designer.pp	(revision 52108)
    +++ designer/designer.pp	(working copy)
    @@ -410,7 +410,7 @@
       DesignerMenuSelectAll: TIDEMenuCommand;
     
       DesignerMenuChangeClass: TIDEMenuCommand;
    -  DesignerMenuChangeParent: TIDEMenuSection;
    +  DesignerMenuChangeParent: TIDEMenuCommand;
       DesignerMenuViewLFM: TIDEMenuCommand;
       DesignerMenuSaveAsXML: TIDEMenuCommand;
       DesignerMenuCenterForm: TIDEMenuCommand;
    @@ -425,6 +425,8 @@
     
     implementation
     
    +uses MainIntf;
    +
     type
       TCustomFormAccess = class(TCustomForm);
       TControlAccess = class(TControl);
    @@ -600,10 +602,8 @@
       DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
         DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                      'Change class',lisDlgChangeClass);
    -    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
    -                                                 'Change parent');
    -    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
    -    DesignerMenuChangeParent.Caption:=lisChangeParent;
    +    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    +                                                 'Change parent',lisChangeParent+' ...');
         DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                     'View LFM',lisViewSourceLfm);
         DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
    @@ -3264,43 +3264,9 @@
     end;
     
     procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
    -var
    -  Item: TIDEMenuCommand;
    -  NewParentName: String;
    -  i: Integer;
    -  CurControl: TControl;
    -  NewParent: TWinControl;
     begin
    -  if not (Sender is TIDEMenuCommand) then Exit;
    -  Item := TIDEMenuCommand(Sender);
    -  NewParentName := Item.Caption;
    -  if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
    -    NewParent := TWinControl(LookupRoot)
    -  else
    -    NewParent := TWinControl(LookupRoot.FindComponent(NewParentName));
    -  if (NewParent=nil) or (not (NewParent is TWinControl)) then Exit;
    -
    -  Form.DisableAlign;
    -  try
    -    i := ControlSelection.Count - 1;
    -    while (i >= 0) do 
    -    begin
    -      if i < ControlSelection.Count then 
    -      begin
    -        if ControlSelection[i].IsTControl then
    -        begin
    -          CurControl := TControl(ControlSelection[i].Persistent);
    -          if CurControl.Owner = LookupRoot then
    -            CurControl.Parent := NewParent;
    -        end;
    -      end;
    -      dec(i);
    -    end;
    -  finally
    -    if Form <> nil then
    -      Form.EnableAlign;
    -    ControlSelection.DoChange(True); // request updates since control hierarchi change
    -  end;
    +  if Assigned(ObjectInspector1) then
    +    ObjectInspector1.ChangeParent;
     end;
     
     procedure TDesigner.OnSnapToGridOptionMenuClick(Sender: TObject);
    @@ -3886,6 +3852,7 @@
       DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
     
       DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
    +  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
       DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
       DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
       DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
    @@ -3909,81 +3876,12 @@
       SrcFile: TLazProjectFile;
       UnitIsVirtual, DesignerCanCopy: Boolean;
     
    -  function GetChangeParentCandidates: TFPList;
    -  var
    -    i,j: Integer;
    -    CurSelected: TSelectedControl;
    -    Candidate: TWinControl;
    -  begin
    -    Result:=TFPList.Create;
    -    if ControlSelection.Count=0 then exit;
    -    if LookupRootIsSelected then
    -      exit; // if the LookupRoot is selected, do not show "change parent"
    -    if not (LookupRoot is TWinControl) then
    -      exit; // only LCL controls are supported at the moment
    -
    -    // check if any selected control can be moved
    -    i:=ControlSelection.Count-1;
    -    while i>=0 do
    -    begin
    -      CurSelected:=ControlSelection[i];
    -      if CurSelected.IsTControl
    -      and (TControl(CurSelected.Persistent).Owner=LookupRoot)
    -      then
    -        // this one can be moved
    -        break;
    -      dec(i);
    -    end;
    -    if i<0 then exit;
    -
    -    // find possible new parents
    -    for i := 0 to LookupRoot.ComponentCount - 1 do
    -    begin
    -      Candidate:=TWinControl(LookupRoot.Components[i]);
    -      if not (Candidate is TWinControl) then continue;
    -
    -      j:=ControlSelection.Count-1;
    -      while j>=0 do
    -      begin
    -        CurSelected:=ControlSelection[j];
    -        if CurSelected.IsTControl then begin
    -          if CurSelected.Persistent=Candidate then break;
    -          if CurSelected.IsTWinControl and
    -             TWinControl(CurSelected.Persistent).IsParentOf(Candidate) then
    -            break;
    -          if not ControlAcceptsStreamableChildComponent(Candidate,
    -                            TComponentClass(CurSelected.ClassType),LookupRoot)
    -          then
    -            break;
    -        end;
    -        dec(j);
    -      end;
    -      if j<0 then
    -        Result.Add(Candidate);
    -    end;
    -    Result.Add(LookupRoot);
    -  end;
    -
       procedure UpdateChangeParentMenu;
    -  var
    -    Candidates: TFPList;
    -    i: Integer;
    -    Item: TIDEMenuItem;
       begin
    -    Candidates:=GetChangeParentCandidates;
    -    try
    -      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
    -      DesignerMenuChangeParent.Clear;
    -      for i:=0 to Candidates.Count-1 do
    -      begin
    -        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
    -        DesignerMenuChangeParent.AddLast(Item);
    -        Item.Caption:=TWinControl(Candidates[i]).Name;
    -        Item.OnClick:=@OnChangeParentMenuClick;
    -      end;
    -    finally
    -      Candidates.Free;
    -    end;
    +    if ObjectInspector1=nil then
    +      DesignerMenuChangeParent.Enabled := False
    +    else
    +      DesignerMenuChangeParent.Enabled := ObjectInspector1.GetHasParentCandidates;
       end;
       
     begin
    
    patch_v4.diff (26,443 bytes)

Activities

FTurtle

2016-03-21 05:03

reporter  

patch.diff (12,614 bytes)
Index: designer/designer.pp
===================================================================
--- designer/designer.pp	(revision 52005)
+++ designer/designer.pp	(working copy)
@@ -100,6 +100,7 @@
 
   TDesigner = class(TComponentEditorDesigner)
   private
+    FChangeParentCandidatesAsText: string;
     FDesignerPopupMenu: TPopupMenu;
     FDefaultFormBounds: TRect;
     FLastFormBounds: TRect;
@@ -410,7 +411,7 @@
   DesignerMenuSelectAll: TIDEMenuCommand;
 
   DesignerMenuChangeClass: TIDEMenuCommand;
-  DesignerMenuChangeParent: TIDEMenuSection;
+  DesignerMenuChangeParent: TIDEMenuCommand;
   DesignerMenuViewLFM: TIDEMenuCommand;
   DesignerMenuSaveAsXML: TIDEMenuCommand;
   DesignerMenuCenterForm: TIDEMenuCommand;
@@ -425,6 +426,8 @@
 
 implementation
 
+uses SelectStringDialog;
+
 type
   TCustomFormAccess = class(TCustomForm);
   TControlAccess = class(TControl);
@@ -600,10 +603,8 @@
   DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
     DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                  'Change class',lisDlgChangeClass);
-    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
-                                                 'Change parent');
-    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
-    DesignerMenuChangeParent.Caption:=lisChangeParent;
+    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
+                                                 'Change parent',lisChangeParent+'...');
     DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                 'View LFM',lisViewSourceLfm);
     DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
@@ -3265,15 +3266,25 @@
 
 procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
 var
-  Item: TIDEMenuCommand;
+  SelectStringDlg: TSelectStringDlg;
   NewParentName: String;
   i: Integer;
   CurControl: TControl;
   NewParent: TWinControl;
 begin
-  if not (Sender is TIDEMenuCommand) then Exit;
-  Item := TIDEMenuCommand(Sender);
-  NewParentName := Item.Caption;
+  SelectStringDlg := TSelectStringDlg.Create(nil);
+  try
+    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
+    FChangeParentCandidatesAsText := '';
+    SelectStringDlg.Caption := lisChangeParent;
+    if SelectStringDlg.ShowModal = mrOK then
+      NewParentName := SelectStringDlg.SelectedItem
+    else
+      Exit;
+  finally
+    SelectStringDlg.Free;
+  end;
+
   if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
     NewParent := TWinControl(LookupRoot)
   else
@@ -3886,6 +3897,7 @@
   DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
 
   DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
+  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
   DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
   DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
   DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
@@ -3964,23 +3976,29 @@
     Result.Add(LookupRoot);
   end;
 
+  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
+  var
+    sl: TStringList;
+    i: Integer;
+  begin
+    sl := TStringList.Create;
+    try
+      for i:=0 to ACandidates.Count-1 do
+        sl.Append(TWinControl(ACandidates[i]).Name);
+      Result := sl.Text;
+    finally
+      sl.Free;
+    end;
+  end;
+
   procedure UpdateChangeParentMenu;
   var
     Candidates: TFPList;
-    i: Integer;
-    Item: TIDEMenuItem;
   begin
-    Candidates:=GetChangeParentCandidates;
+    Candidates := GetChangeParentCandidates;
     try
-      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
-      DesignerMenuChangeParent.Clear;
-      for i:=0 to Candidates.Count-1 do
-      begin
-        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
-        DesignerMenuChangeParent.AddLast(Item);
-        Item.Caption:=TWinControl(Candidates[i]).Name;
-        Item.OnClick:=@OnChangeParentMenuClick;
-      end;
+      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
+      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
     finally
       Candidates.Free;
     end;
Index: ide/lazarus.lpi
===================================================================
--- ide/lazarus.lpi	(revision 52005)
+++ ide/lazarus.lpi	(working copy)
@@ -66,7 +66,7 @@
         <PackageName Value="SynEdit"/>
       </Item7>
     </RequiredPackages>
-    <Units Count="241">
+    <Units Count="242">
       <Unit0>
         <Filename Value="lazarus.pp"/>
         <IsPartOfProject Value="True"/>
@@ -309,6 +309,7 @@
       <Unit39>
         <Filename Value="../designer/designer.pp"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="Designer"/>
       </Unit39>
       <Unit40>
         <Filename Value="../designer/designerprocs.pas"/>
@@ -1348,6 +1349,14 @@
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="DefinesGui"/>
       </Unit240>
+      <Unit241>
+        <Filename Value="selectstringdialog.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="SelectStringDlg"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="SelectStringDialog"/>
+      </Unit241>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
Index: ide/selectstringdialog.lfm
===================================================================
--- ide/selectstringdialog.lfm	(revision 0)
+++ ide/selectstringdialog.lfm	(revision 0)
@@ -0,0 +1,65 @@
+object SelectStringDlg: TSelectStringDlg
+  Left = 550
+  Height = 390
+  Top = 217
+  Width = 290
+  Caption = 'SelectStringDlg'
+  ClientHeight = 390
+  ClientWidth = 290
+  OnCreate = FormCreate
+  LCLVersion = '1.7'
+  object ListFilterEdit: TListFilterEdit
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = Owner
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    Left = 6
+    Height = 21
+    Top = 6
+    Width = 278
+    OnAfterFilter = ListFilterEditAfterFilter
+    ButtonWidth = 23
+    NumGlyphs = 1
+    Anchors = [akTop, akLeft, akRight]
+    BorderSpacing.Around = 6
+    MaxLength = 0
+    TabOrder = 0
+  end
+  object ListBox: TListBox
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = ListFilterEdit
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = ButtonPanel
+    Left = 6
+    Height = 319
+    Top = 33
+    Width = 278
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    BorderSpacing.Around = 6
+    ItemHeight = 0
+    OnDblClick = ListBoxDblClick
+    OnSelectionChange = ListBoxSelectionChange
+    TabOrder = 1
+  end
+  object ButtonPanel: TButtonPanel
+    Left = 6
+    Height = 26
+    Top = 358
+    Width = 278
+    OKButton.Name = 'OKButton'
+    OKButton.DefaultCaption = True
+    OKButton.OnClick = OKButtonClick
+    HelpButton.Name = 'HelpButton'
+    HelpButton.DefaultCaption = True
+    HelpButton.OnClick = HelpButtonClick
+    CloseButton.Name = 'CloseButton'
+    CloseButton.DefaultCaption = True
+    CancelButton.Name = 'CancelButton'
+    CancelButton.DefaultCaption = True
+    TabOrder = 2
+    ShowButtons = [pbOK, pbCancel, pbHelp]
+    ShowBevel = False
+  end
+end
Index: ide/selectstringdialog.pas
===================================================================
--- ide/selectstringdialog.pas	(revision 0)
+++ ide/selectstringdialog.pas	(revision 0)
@@ -0,0 +1,156 @@
+{ /***************************************************************************
+                 SelectStringDialog.pas - Lazarus IDE unit
+                 -----------------------------------------
+
+ ***************************************************************************/
+
+ ***************************************************************************
+ *                                                                         *
+ *   This source is free software; you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This code is distributed in the hope that it will be useful, but      *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   A copy of the GNU General Public License is available on the World    *
+ *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
+ *   obtain it by writing to the Free Software Foundation,                 *
+ *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
+ *                                                                         *
+ ***************************************************************************
+
+  Author: FTurtle
+
+  Abstract:
+    A generic reusable dialog for choosing string from list.
+}
+
+unit SelectStringDialog;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
+  Dialogs, StdCtrls, ButtonPanel;
+
+type
+
+  { TSelectStringDlg }
+
+  TSelectStringDlg = class(TForm)
+    ButtonPanel: TButtonPanel;
+    ListBox: TListBox;
+    ListFilterEdit: TListFilterEdit;
+    procedure FormCreate(Sender: TObject);
+    procedure HelpButtonClick(Sender: TObject);
+    procedure ListBoxDblClick(Sender: TObject);
+    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
+    procedure ListFilterEditAfterFilter(Sender: TObject);
+    procedure OKButtonClick(Sender: TObject);
+  private
+    FHelpURL: string;
+    function GetSelectedItem: string;
+    procedure SetHelpURL(AValue: string);
+    procedure SetSelectedItem(AValue: string);
+    procedure UpdateButtonState;
+  public
+    function ShowModal: Integer; override;
+  public
+    property HelpURL: string read FHelpURL write SetHelpURL;
+    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
+  end;
+
+implementation
+
+uses LCLIntf;
+
+{$R *.lfm}
+
+{ TSelectStringDlg }
+
+procedure TSelectStringDlg.FormCreate(Sender: TObject);
+begin
+  Caption := '';
+  HelpURL := '';
+end;
+
+procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
+begin
+  OpenURL(FHelpURL);
+end;
+
+procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
+begin
+  ButtonPanel.OKButton.Click;
+end;
+
+{$HINTS OFF}
+procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
+begin
+  UpdateButtonState;
+end;
+{$HINTS ON}
+
+procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
+begin
+  UpdateButtonState;
+end;
+
+procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
+begin
+  if ListBox.ItemIndex < 0 then
+    ModalResult := mrNone;
+end;
+
+procedure TSelectStringDlg.SetHelpURL(AValue: string);
+begin
+  FHelpURL := AValue;
+  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
+end;
+
+function TSelectStringDlg.GetSelectedItem: string;
+begin
+  if ListBox.ItemIndex > -1 then
+    Result := ListBox.Items[ListBox.ItemIndex]
+  else
+    Result := '';
+end;
+
+procedure TSelectStringDlg.SetSelectedItem(AValue: string);
+var
+  i: Integer;
+begin
+  i := ListBox.Items.IndexOf(AValue);
+  if i > -1 then
+    ListBox.ItemIndex := i;
+end;
+
+procedure TSelectStringDlg.UpdateButtonState;
+begin
+  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
+end;
+
+function TSelectStringDlg.ShowModal: Integer;
+const
+  MinWidth = 250;
+  MinHeight = 250;
+begin
+  Constraints.MinHeight := MinHeight;
+  if ButtonPanel.HelpButton.Visible then
+    Constraints.MinWidth := MinWidth
+  else
+    Constraints.MinWidth := MinWidth - 75;
+  ListFilterEdit.FilteredListbox := nil;
+  ListFilterEdit.FilteredListbox := ListBox;
+  UpdateButtonState;
+  Result := inherited ShowModal;
+end;
+
+end.
+
patch.diff (12,614 bytes)

FTurtle

2016-03-21 05:21

reporter  

patch_v2.diff (12,644 bytes)
Index: designer/designer.pp
===================================================================
--- designer/designer.pp	(revision 52005)
+++ designer/designer.pp	(working copy)
@@ -100,6 +100,7 @@
 
   TDesigner = class(TComponentEditorDesigner)
   private
+    FChangeParentCandidatesAsText: string;
     FDesignerPopupMenu: TPopupMenu;
     FDefaultFormBounds: TRect;
     FLastFormBounds: TRect;
@@ -410,7 +411,7 @@
   DesignerMenuSelectAll: TIDEMenuCommand;
 
   DesignerMenuChangeClass: TIDEMenuCommand;
-  DesignerMenuChangeParent: TIDEMenuSection;
+  DesignerMenuChangeParent: TIDEMenuCommand;
   DesignerMenuViewLFM: TIDEMenuCommand;
   DesignerMenuSaveAsXML: TIDEMenuCommand;
   DesignerMenuCenterForm: TIDEMenuCommand;
@@ -425,6 +426,8 @@
 
 implementation
 
+uses SelectStringDialog;
+
 type
   TCustomFormAccess = class(TCustomForm);
   TControlAccess = class(TControl);
@@ -600,10 +603,8 @@
   DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
     DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                  'Change class',lisDlgChangeClass);
-    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
-                                                 'Change parent');
-    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
-    DesignerMenuChangeParent.Caption:=lisChangeParent;
+    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
+                                                 'Change parent',lisChangeParent+'...');
     DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                 'View LFM',lisViewSourceLfm);
     DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
@@ -3265,15 +3266,25 @@
 
 procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
 var
-  Item: TIDEMenuCommand;
+  SelectStringDlg: TSelectStringDlg;
   NewParentName: String;
   i: Integer;
   CurControl: TControl;
   NewParent: TWinControl;
 begin
-  if not (Sender is TIDEMenuCommand) then Exit;
-  Item := TIDEMenuCommand(Sender);
-  NewParentName := Item.Caption;
+  SelectStringDlg := TSelectStringDlg.Create(nil);
+  try
+    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
+    FChangeParentCandidatesAsText := '';
+    SelectStringDlg.Caption := lisChangeParent;
+    if SelectStringDlg.ShowModal = mrOK then
+      NewParentName := SelectStringDlg.SelectedItem
+    else
+      Exit;
+  finally
+    SelectStringDlg.Free;
+  end;
+
   if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
     NewParent := TWinControl(LookupRoot)
   else
@@ -3886,6 +3897,7 @@
   DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
 
   DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
+  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
   DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
   DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
   DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
@@ -3964,23 +3976,29 @@
     Result.Add(LookupRoot);
   end;
 
+  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
+  var
+    sl: TStringList;
+    i: Integer;
+  begin
+    sl := TStringList.Create;
+    try
+      for i:=0 to ACandidates.Count-1 do
+        sl.Append(TWinControl(ACandidates[i]).Name);
+      Result := sl.Text;
+    finally
+      sl.Free;
+    end;
+  end;
+
   procedure UpdateChangeParentMenu;
   var
     Candidates: TFPList;
-    i: Integer;
-    Item: TIDEMenuItem;
   begin
-    Candidates:=GetChangeParentCandidates;
+    Candidates := GetChangeParentCandidates;
     try
-      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
-      DesignerMenuChangeParent.Clear;
-      for i:=0 to Candidates.Count-1 do
-      begin
-        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
-        DesignerMenuChangeParent.AddLast(Item);
-        Item.Caption:=TWinControl(Candidates[i]).Name;
-        Item.OnClick:=@OnChangeParentMenuClick;
-      end;
+      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
+      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
     finally
       Candidates.Free;
     end;
Index: ide/lazarus.lpi
===================================================================
--- ide/lazarus.lpi	(revision 52005)
+++ ide/lazarus.lpi	(working copy)
@@ -66,7 +66,7 @@
         <PackageName Value="SynEdit"/>
       </Item7>
     </RequiredPackages>
-    <Units Count="241">
+    <Units Count="242">
       <Unit0>
         <Filename Value="lazarus.pp"/>
         <IsPartOfProject Value="True"/>
@@ -309,6 +309,7 @@
       <Unit39>
         <Filename Value="../designer/designer.pp"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="Designer"/>
       </Unit39>
       <Unit40>
         <Filename Value="../designer/designerprocs.pas"/>
@@ -1348,6 +1349,14 @@
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="DefinesGui"/>
       </Unit240>
+      <Unit241>
+        <Filename Value="selectstringdialog.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="SelectStringDlg"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="SelectStringDialog"/>
+      </Unit241>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
Index: ide/selectstringdialog.lfm
===================================================================
--- ide/selectstringdialog.lfm	(revision 0)
+++ ide/selectstringdialog.lfm	(revision 0)
@@ -0,0 +1,66 @@
+object SelectStringDlg: TSelectStringDlg
+  Left = 550
+  Height = 390
+  Top = 217
+  Width = 290
+  Caption = 'SelectStringDlg'
+  ClientHeight = 390
+  ClientWidth = 290
+  OnCreate = FormCreate
+  Position = poScreenCenter
+  LCLVersion = '1.7'
+  object ListFilterEdit: TListFilterEdit
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = Owner
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    Left = 6
+    Height = 21
+    Top = 6
+    Width = 278
+    OnAfterFilter = ListFilterEditAfterFilter
+    ButtonWidth = 23
+    NumGlyphs = 1
+    Anchors = [akTop, akLeft, akRight]
+    BorderSpacing.Around = 6
+    MaxLength = 0
+    TabOrder = 0
+  end
+  object ListBox: TListBox
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = ListFilterEdit
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = ButtonPanel
+    Left = 6
+    Height = 319
+    Top = 33
+    Width = 278
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    BorderSpacing.Around = 6
+    ItemHeight = 0
+    OnDblClick = ListBoxDblClick
+    OnSelectionChange = ListBoxSelectionChange
+    TabOrder = 1
+  end
+  object ButtonPanel: TButtonPanel
+    Left = 6
+    Height = 26
+    Top = 358
+    Width = 278
+    OKButton.Name = 'OKButton'
+    OKButton.DefaultCaption = True
+    OKButton.OnClick = OKButtonClick
+    HelpButton.Name = 'HelpButton'
+    HelpButton.DefaultCaption = True
+    HelpButton.OnClick = HelpButtonClick
+    CloseButton.Name = 'CloseButton'
+    CloseButton.DefaultCaption = True
+    CancelButton.Name = 'CancelButton'
+    CancelButton.DefaultCaption = True
+    TabOrder = 2
+    ShowButtons = [pbOK, pbCancel, pbHelp]
+    ShowBevel = False
+  end
+end
Index: ide/selectstringdialog.pas
===================================================================
--- ide/selectstringdialog.pas	(revision 0)
+++ ide/selectstringdialog.pas	(revision 0)
@@ -0,0 +1,156 @@
+{ /***************************************************************************
+                 SelectStringDialog.pas - Lazarus IDE unit
+                 -----------------------------------------
+
+ ***************************************************************************/
+
+ ***************************************************************************
+ *                                                                         *
+ *   This source is free software; you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This code is distributed in the hope that it will be useful, but      *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   A copy of the GNU General Public License is available on the World    *
+ *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
+ *   obtain it by writing to the Free Software Foundation,                 *
+ *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
+ *                                                                         *
+ ***************************************************************************
+
+  Author: FTurtle
+
+  Abstract:
+    A generic reusable dialog for choosing string from list.
+}
+
+unit SelectStringDialog;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
+  Dialogs, StdCtrls, ButtonPanel;
+
+type
+
+  { TSelectStringDlg }
+
+  TSelectStringDlg = class(TForm)
+    ButtonPanel: TButtonPanel;
+    ListBox: TListBox;
+    ListFilterEdit: TListFilterEdit;
+    procedure FormCreate(Sender: TObject);
+    procedure HelpButtonClick(Sender: TObject);
+    procedure ListBoxDblClick(Sender: TObject);
+    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
+    procedure ListFilterEditAfterFilter(Sender: TObject);
+    procedure OKButtonClick(Sender: TObject);
+  private
+    FHelpURL: string;
+    function GetSelectedItem: string;
+    procedure SetHelpURL(AValue: string);
+    procedure SetSelectedItem(AValue: string);
+    procedure UpdateButtonState;
+  public
+    function ShowModal: Integer; override;
+  public
+    property HelpURL: string read FHelpURL write SetHelpURL;
+    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
+  end;
+
+implementation
+
+uses LCLIntf;
+
+{$R *.lfm}
+
+{ TSelectStringDlg }
+
+procedure TSelectStringDlg.FormCreate(Sender: TObject);
+begin
+  Caption := '';
+  HelpURL := '';
+end;
+
+procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
+begin
+  OpenURL(FHelpURL);
+end;
+
+procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
+begin
+  ButtonPanel.OKButton.Click;
+end;
+
+{$HINTS OFF}
+procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
+begin
+  UpdateButtonState;
+end;
+{$HINTS ON}
+
+procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
+begin
+  UpdateButtonState;
+end;
+
+procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
+begin
+  if ListBox.ItemIndex < 0 then
+    ModalResult := mrNone;
+end;
+
+procedure TSelectStringDlg.SetHelpURL(AValue: string);
+begin
+  FHelpURL := AValue;
+  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
+end;
+
+function TSelectStringDlg.GetSelectedItem: string;
+begin
+  if ListBox.ItemIndex > -1 then
+    Result := ListBox.Items[ListBox.ItemIndex]
+  else
+    Result := '';
+end;
+
+procedure TSelectStringDlg.SetSelectedItem(AValue: string);
+var
+  i: Integer;
+begin
+  i := ListBox.Items.IndexOf(AValue);
+  if i > -1 then
+    ListBox.ItemIndex := i;
+end;
+
+procedure TSelectStringDlg.UpdateButtonState;
+begin
+  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
+end;
+
+function TSelectStringDlg.ShowModal: Integer;
+const
+  MinWidth = 250;
+  MinHeight = 250;
+begin
+  Constraints.MinHeight := MinHeight;
+  if ButtonPanel.HelpButton.Visible then
+    Constraints.MinWidth := MinWidth
+  else
+    Constraints.MinWidth := MinWidth - 75;
+  ListFilterEdit.FilteredListbox := nil;
+  ListFilterEdit.FilteredListbox := ListBox;
+  UpdateButtonState;
+  Result := inherited ShowModal;
+end;
+
+end.
+
patch_v2.diff (12,644 bytes)

FTurtle

2016-03-21 05:22

reporter   ~0091246

Forgot "Position = poScreenCenter"

Attached corrected patch: patch_v2.diff

FTurtle

2016-03-21 07:42

reporter  

patch_v3.diff (12,689 bytes)
Index: designer/designer.pp
===================================================================
--- designer/designer.pp	(revision 52005)
+++ designer/designer.pp	(working copy)
@@ -100,6 +100,7 @@
 
   TDesigner = class(TComponentEditorDesigner)
   private
+    FChangeParentCandidatesAsText: string;
     FDesignerPopupMenu: TPopupMenu;
     FDefaultFormBounds: TRect;
     FLastFormBounds: TRect;
@@ -410,7 +411,7 @@
   DesignerMenuSelectAll: TIDEMenuCommand;
 
   DesignerMenuChangeClass: TIDEMenuCommand;
-  DesignerMenuChangeParent: TIDEMenuSection;
+  DesignerMenuChangeParent: TIDEMenuCommand;
   DesignerMenuViewLFM: TIDEMenuCommand;
   DesignerMenuSaveAsXML: TIDEMenuCommand;
   DesignerMenuCenterForm: TIDEMenuCommand;
@@ -425,6 +426,8 @@
 
 implementation
 
+uses SelectStringDialog;
+
 type
   TCustomFormAccess = class(TCustomForm);
   TControlAccess = class(TControl);
@@ -600,10 +603,8 @@
   DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
     DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                  'Change class',lisDlgChangeClass);
-    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
-                                                 'Change parent');
-    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
-    DesignerMenuChangeParent.Caption:=lisChangeParent;
+    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
+                                                 'Change parent',lisChangeParent+'...');
     DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                 'View LFM',lisViewSourceLfm);
     DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
@@ -3265,15 +3266,25 @@
 
 procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
 var
-  Item: TIDEMenuCommand;
+  SelectStringDlg: TSelectStringDlg;
   NewParentName: String;
   i: Integer;
   CurControl: TControl;
   NewParent: TWinControl;
 begin
-  if not (Sender is TIDEMenuCommand) then Exit;
-  Item := TIDEMenuCommand(Sender);
-  NewParentName := Item.Caption;
+  SelectStringDlg := TSelectStringDlg.Create(nil);
+  try
+    SelectStringDlg.ListBox.Items.Text := FChangeParentCandidatesAsText;
+    FChangeParentCandidatesAsText := '';
+    SelectStringDlg.Caption := lisChangeParent;
+    if SelectStringDlg.ShowModal = mrOK then
+      NewParentName := SelectStringDlg.SelectedItem
+    else
+      Exit;
+  finally
+    SelectStringDlg.Free;
+  end;
+
   if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
     NewParent := TWinControl(LookupRoot)
   else
@@ -3886,6 +3897,7 @@
   DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
 
   DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
+  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
   DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
   DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
   DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
@@ -3964,23 +3976,29 @@
     Result.Add(LookupRoot);
   end;
 
+  function ChangeParentCandidatesToText(ACandidates: TFPList): string;
+  var
+    sl: TStringList;
+    i: Integer;
+  begin
+    sl := TStringList.Create;
+    try
+      for i:=0 to ACandidates.Count-1 do
+        sl.Append(TWinControl(ACandidates[i]).Name);
+      Result := sl.Text;
+    finally
+      sl.Free;
+    end;
+  end;
+
   procedure UpdateChangeParentMenu;
   var
     Candidates: TFPList;
-    i: Integer;
-    Item: TIDEMenuItem;
   begin
-    Candidates:=GetChangeParentCandidates;
+    Candidates := GetChangeParentCandidates;
     try
-      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
-      DesignerMenuChangeParent.Clear;
-      for i:=0 to Candidates.Count-1 do
-      begin
-        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
-        DesignerMenuChangeParent.AddLast(Item);
-        Item.Caption:=TWinControl(Candidates[i]).Name;
-        Item.OnClick:=@OnChangeParentMenuClick;
-      end;
+      DesignerMenuChangeParent.Enabled := (Candidates.Count>1);
+      FChangeParentCandidatesAsText := ChangeParentCandidatesToText(Candidates);
     finally
       Candidates.Free;
     end;
Index: ide/lazarus.lpi
===================================================================
--- ide/lazarus.lpi	(revision 52005)
+++ ide/lazarus.lpi	(working copy)
@@ -66,7 +66,7 @@
         <PackageName Value="SynEdit"/>
       </Item7>
     </RequiredPackages>
-    <Units Count="241">
+    <Units Count="242">
       <Unit0>
         <Filename Value="lazarus.pp"/>
         <IsPartOfProject Value="True"/>
@@ -309,6 +309,7 @@
       <Unit39>
         <Filename Value="../designer/designer.pp"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="Designer"/>
       </Unit39>
       <Unit40>
         <Filename Value="../designer/designerprocs.pas"/>
@@ -1348,6 +1349,14 @@
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="DefinesGui"/>
       </Unit240>
+      <Unit241>
+        <Filename Value="selectstringdialog.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="SelectStringDlg"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="SelectStringDialog"/>
+      </Unit241>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
Index: ide/selectstringdialog.lfm
===================================================================
--- ide/selectstringdialog.lfm	(revision 0)
+++ ide/selectstringdialog.lfm	(revision 0)
@@ -0,0 +1,67 @@
+object SelectStringDlg: TSelectStringDlg
+  Left = 550
+  Height = 390
+  Top = 217
+  Width = 290
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'SelectStringDlg'
+  ClientHeight = 390
+  ClientWidth = 290
+  OnCreate = FormCreate
+  Position = poScreenCenter
+  LCLVersion = '1.7'
+  object ListFilterEdit: TListFilterEdit
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = Owner
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    Left = 6
+    Height = 21
+    Top = 6
+    Width = 278
+    OnAfterFilter = ListFilterEditAfterFilter
+    ButtonWidth = 23
+    NumGlyphs = 1
+    Anchors = [akTop, akLeft, akRight]
+    BorderSpacing.Around = 6
+    MaxLength = 0
+    TabOrder = 0
+  end
+  object ListBox: TListBox
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = ListFilterEdit
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = ButtonPanel
+    Left = 6
+    Height = 319
+    Top = 33
+    Width = 278
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    BorderSpacing.Around = 6
+    ItemHeight = 0
+    OnDblClick = ListBoxDblClick
+    OnSelectionChange = ListBoxSelectionChange
+    TabOrder = 1
+  end
+  object ButtonPanel: TButtonPanel
+    Left = 6
+    Height = 26
+    Top = 358
+    Width = 278
+    OKButton.Name = 'OKButton'
+    OKButton.DefaultCaption = True
+    OKButton.OnClick = OKButtonClick
+    HelpButton.Name = 'HelpButton'
+    HelpButton.DefaultCaption = True
+    HelpButton.OnClick = HelpButtonClick
+    CloseButton.Name = 'CloseButton'
+    CloseButton.DefaultCaption = True
+    CancelButton.Name = 'CancelButton'
+    CancelButton.DefaultCaption = True
+    TabOrder = 2
+    ShowButtons = [pbOK, pbCancel, pbHelp]
+    ShowBevel = False
+  end
+end
Index: ide/selectstringdialog.pas
===================================================================
--- ide/selectstringdialog.pas	(revision 0)
+++ ide/selectstringdialog.pas	(revision 0)
@@ -0,0 +1,156 @@
+{ /***************************************************************************
+                 SelectStringDialog.pas - Lazarus IDE unit
+                 -----------------------------------------
+
+ ***************************************************************************/
+
+ ***************************************************************************
+ *                                                                         *
+ *   This source is free software; you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This code is distributed in the hope that it will be useful, but      *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   General Public License for more details.                              *
+ *                                                                         *
+ *   A copy of the GNU General Public License is available on the World    *
+ *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
+ *   obtain it by writing to the Free Software Foundation,                 *
+ *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
+ *                                                                         *
+ ***************************************************************************
+
+  Author: FTurtle
+
+  Abstract:
+    A generic reusable dialog for choosing string from list.
+}
+
+unit SelectStringDialog;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, ListFilterEdit, Forms, Controls, Graphics,
+  Dialogs, StdCtrls, ButtonPanel;
+
+type
+
+  { TSelectStringDlg }
+
+  TSelectStringDlg = class(TForm)
+    ButtonPanel: TButtonPanel;
+    ListBox: TListBox;
+    ListFilterEdit: TListFilterEdit;
+    procedure FormCreate(Sender: TObject);
+    procedure HelpButtonClick(Sender: TObject);
+    procedure ListBoxDblClick(Sender: TObject);
+    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
+    procedure ListFilterEditAfterFilter(Sender: TObject);
+    procedure OKButtonClick(Sender: TObject);
+  private
+    FHelpURL: string;
+    function GetSelectedItem: string;
+    procedure SetHelpURL(AValue: string);
+    procedure SetSelectedItem(AValue: string);
+    procedure UpdateButtonState;
+  public
+    function ShowModal: Integer; override;
+  public
+    property HelpURL: string read FHelpURL write SetHelpURL;
+    property SelectedItem: string read GetSelectedItem write SetSelectedItem;
+  end;
+
+implementation
+
+uses LCLIntf;
+
+{$R *.lfm}
+
+{ TSelectStringDlg }
+
+procedure TSelectStringDlg.FormCreate(Sender: TObject);
+begin
+  Caption := '';
+  HelpURL := '';
+end;
+
+procedure TSelectStringDlg.HelpButtonClick(Sender: TObject);
+begin
+  OpenURL(FHelpURL);
+end;
+
+procedure TSelectStringDlg.ListBoxDblClick(Sender: TObject);
+begin
+  ButtonPanel.OKButton.Click;
+end;
+
+{$HINTS OFF}
+procedure TSelectStringDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
+begin
+  UpdateButtonState;
+end;
+{$HINTS ON}
+
+procedure TSelectStringDlg.ListFilterEditAfterFilter(Sender: TObject);
+begin
+  UpdateButtonState;
+end;
+
+procedure TSelectStringDlg.OKButtonClick(Sender: TObject);
+begin
+  if ListBox.ItemIndex < 0 then
+    ModalResult := mrNone;
+end;
+
+procedure TSelectStringDlg.SetHelpURL(AValue: string);
+begin
+  FHelpURL := AValue;
+  ButtonPanel.HelpButton.Visible := (Length(FHelpURL)>0);
+end;
+
+function TSelectStringDlg.GetSelectedItem: string;
+begin
+  if ListBox.ItemIndex > -1 then
+    Result := ListBox.Items[ListBox.ItemIndex]
+  else
+    Result := '';
+end;
+
+procedure TSelectStringDlg.SetSelectedItem(AValue: string);
+var
+  i: Integer;
+begin
+  i := ListBox.Items.IndexOf(AValue);
+  if i > -1 then
+    ListBox.ItemIndex := i;
+end;
+
+procedure TSelectStringDlg.UpdateButtonState;
+begin
+  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
+end;
+
+function TSelectStringDlg.ShowModal: Integer;
+const
+  MinWidth = 250;
+  MinHeight = 250;
+begin
+  Constraints.MinHeight := MinHeight;
+  if ButtonPanel.HelpButton.Visible then
+    Constraints.MinWidth := MinWidth
+  else
+    Constraints.MinWidth := MinWidth - 75;
+  ListFilterEdit.FilteredListbox := nil;
+  ListFilterEdit.FilteredListbox := ListBox;
+  UpdateButtonState;
+  Result := inherited ShowModal;
+end;
+
+end.
+
patch_v3.diff (12,689 bytes)

FTurtle

2016-03-21 07:43

reporter   ~0091247

Excluded biMinimize.

Corrected patch: patch_v3.diff

Juha Manninen

2016-03-23 14:41

developer   ~0091292

Last edited: 2016-03-25 11:45

View 6 revisions

The current parent is in the selection list and there is no indication which one is the current parent. Yes I know it was like that also in the sub-menu but now we are supposed to improve things. Let's make it properly.
There are 2 choices:
1. Show the current parent in a label in SelectStringDlg and leave it out from the list.
2. Show it as disabled in the list. Requires custom drawing.

You get the parent candidates in DesignerPopupMenuPopup because it is needed there for the enabled state. Good.
However there is no need to convert the candidate list to/from joined text variable.
Update a private candidate list in GetChangeParentCandidates and preferably make it a proper method. There are too many sub-functions anyway.

Nowadays the Change Parent feature is also in Object Inspector's popup menu. You forgot to update that.
I remember there could be more shared code between those designer and OI menus. If you find a way to refactor it, good.

[Edit]
Clarification for the Object Inspector's popup menu: OI belongs to IDEIntf package, thus reusing code needs extra attention.
IDEIntf cannot use code from IDE, but IDE can use code from IDEIntf.

FTurtle

2016-03-23 16:02

reporter   ~0091296

Thank you for the response.
I will try to correct the flaws that you mentioned.

FTurtle

2016-04-12 04:11

reporter  

patch_v4.diff (26,443 bytes)
Index: components/ideintf/changeparentdlg.lfm
===================================================================
--- components/ideintf/changeparentdlg.lfm	(revision 0)
+++ components/ideintf/changeparentdlg.lfm	(revision 0)
@@ -0,0 +1,110 @@
+object ChangeParentDlg: TChangeParentDlg
+  Left = 550
+  Height = 386
+  Top = 217
+  Width = 248
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'ChangeParentDlg'
+  ClientHeight = 386
+  ClientWidth = 248
+  OnClose = FormClose
+  OnCreate = FormCreate
+  Position = poScreenCenter
+  LCLVersion = '1.7'
+  object ListFilterEdit: TListFilterEdit
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = Owner
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    Left = 6
+    Height = 21
+    Top = 6
+    Width = 236
+    OnAfterFilter = ListFilterEditAfterFilter
+    ButtonWidth = 23
+    NumGlyphs = 1
+    Anchors = [akTop, akLeft, akRight]
+    BorderSpacing.Around = 6
+    MaxLength = 0
+    TabOrder = 0
+  end
+  object ListBox: TListBox
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = ListFilterEdit
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = chShowClasses
+    Left = 6
+    Height = 260
+    Top = 33
+    Width = 236
+    Anchors = [akTop, akLeft, akRight, akBottom]
+    BorderSpacing.Around = 6
+    ItemHeight = 0
+    OnDblClick = ListBoxDblClick
+    OnSelectionChange = ListBoxSelectionChange
+    TabOrder = 1
+  end
+  object ButtonPanel: TButtonPanel
+    Left = 6
+    Height = 26
+    Top = 354
+    Width = 236
+    OKButton.Name = 'OKButton'
+    OKButton.DefaultCaption = True
+    OKButton.OnClick = OKButtonClick
+    HelpButton.Name = 'HelpButton'
+    HelpButton.DefaultCaption = True
+    CloseButton.Name = 'CloseButton'
+    CloseButton.DefaultCaption = True
+    CancelButton.Name = 'CancelButton'
+    CancelButton.DefaultCaption = True
+    TabOrder = 2
+    ShowButtons = [pbOK, pbCancel]
+    ShowBevel = False
+  end
+  object lblSelectedControls: TLabel
+    AnchorSideLeft.Control = ListBox
+    AnchorSideRight.Control = ListBox
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = lblCurentParents
+    Left = 6
+    Height = 13
+    Top = 319
+    Width = 236
+    Anchors = [akLeft, akRight, akBottom]
+    BorderSpacing.Bottom = 3
+    Caption = 'lblSelectedControls'
+    ParentColor = False
+    ParentFont = False
+    WordWrap = True
+  end
+  object lblCurentParents: TLabel
+    AnchorSideLeft.Control = ListBox
+    AnchorSideRight.Control = ListBox
+    AnchorSideRight.Side = asrBottom
+    AnchorSideBottom.Control = ButtonPanel
+    Left = 6
+    Height = 13
+    Top = 335
+    Width = 236
+    Anchors = [akLeft, akRight, akBottom]
+    Caption = 'lblCurentParents'
+    ParentColor = False
+    WordWrap = True
+  end
+  object chShowClasses: TCheckBox
+    AnchorSideLeft.Control = ListBox
+    AnchorSideBottom.Control = lblSelectedControls
+    Left = 6
+    Height = 17
+    Top = 299
+    Width = 91
+    Anchors = [akLeft, akBottom]
+    BorderSpacing.Bottom = 3
+    Caption = 'chShowClasses'
+    OnClick = chShowClassesClick
+    TabOrder = 3
+  end
+end
Index: components/ideintf/changeparentdlg.pas
===================================================================
--- components/ideintf/changeparentdlg.pas	(revision 0)
+++ components/ideintf/changeparentdlg.pas	(revision 0)
@@ -0,0 +1,269 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+  Author: FTurtle
+
+  Abstract:
+    Dialog for choosing new parent name.
+}
+
+unit ChangeParentDlg;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, strutils, FileUtil, ListFilterEdit, PropEditUtils, Forms,
+  Controls, Graphics, Dialogs, StdCtrls, ButtonPanel;
+
+type
+
+  { TChangeParentDlg }
+
+  TChangeParentDlg = class(TForm)
+    ButtonPanel: TButtonPanel;
+    chShowClasses: TCheckBox;
+    lblSelectedControls: TLabel;
+    lblCurentParents: TLabel;
+    ListBox: TListBox;
+    ListFilterEdit: TListFilterEdit;
+    procedure chShowClassesClick(Sender: TObject);
+    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
+    procedure FormCreate(Sender: TObject);
+    procedure ListBoxDblClick(Sender: TObject);
+    procedure ListBoxSelectionChange(Sender: TObject; User: boolean);
+    procedure ListFilterEditAfterFilter(Sender: TObject);
+    procedure OKButtonClick(Sender: TObject);
+  private
+    class var
+      FSavedWidth: Integer;
+      FSavedHeight: Integer;
+      FSavedShowClasses: Boolean;
+  private
+    FCandidates: TFPList;
+    FIgnoredCandidateName: string;
+    function GetSelectedItem: string;
+    procedure RefreshList;
+    procedure SetSelection(ASelection: TPersistentSelectionList);
+    procedure UpdateOKButtonState;
+  public
+    function ShowModal: Integer; override;
+  public
+    property SelectedItem: string read GetSelectedItem;
+    property Selection: TPersistentSelectionList write SetSelection;
+    property Candidates: TFPList write FCandidates;
+  end;
+
+function ShowChangeParentDlg(var ANewParentName: string;
+  ASelection: TPersistentSelectionList; ACandidates: TFPList): Boolean;
+
+
+implementation
+
+uses LCLIntf, ObjInspStrConsts;
+
+{$R *.lfm}
+
+{ TChangeParentDlg }
+
+const
+  colon = ': ';
+
+function ShowChangeParentDlg(var ANewParentName: string;
+  ASelection: TPersistentSelectionList; ACandidates: TFPList): Boolean;
+begin
+  if not Assigned(ASelection) or not Assigned(ACandidates) then
+    Exit(False);
+
+  with TChangeParentDlg.Create(nil) do
+  try
+    Selection := ASelection;
+    Candidates := ACandidates;
+    Result := (ShowModal = mrOK);
+    if Result then
+      ANewParentName := SelectedItem;
+  finally
+    Free;
+  end;
+end;
+
+
+procedure TChangeParentDlg.FormCreate(Sender: TObject);
+begin
+  Constraints.MinHeight := 250;
+  Constraints.MinWidth := 175;
+
+  Height := FSavedHeight;  // see "initialization"
+  Width := FSavedWidth;
+  chShowClasses.Checked := FSavedShowClasses;
+
+  Caption := oisChangeParent;
+  chShowClasses.Caption := oisShowClasses;
+end;
+
+{$HINTS OFF}
+procedure TChangeParentDlg.FormClose(Sender: TObject; var CloseAction: TCloseAction);
+begin
+  FSavedHeight := Height;
+  FSavedWidth := Width;
+  FSavedShowClasses := chShowClasses.Checked;
+end;
+{$HINTS ON}
+
+procedure TChangeParentDlg.chShowClassesClick(Sender: TObject);
+begin
+  if Assigned(FCandidates) then
+    RefreshList;
+end;
+
+procedure TChangeParentDlg.ListBoxDblClick(Sender: TObject);
+begin
+  ButtonPanel.OKButton.Click;
+end;
+
+{$HINTS OFF}
+procedure TChangeParentDlg.ListBoxSelectionChange(Sender: TObject; User: boolean);
+begin
+  UpdateOKButtonState;
+end;
+{$HINTS ON}
+
+procedure TChangeParentDlg.ListFilterEditAfterFilter(Sender: TObject);
+begin
+  UpdateOKButtonState;
+end;
+
+procedure TChangeParentDlg.OKButtonClick(Sender: TObject);
+begin
+  if ListBox.ItemIndex < 0 then
+    ModalResult := mrNone;
+end;
+
+function TChangeParentDlg.GetSelectedItem: string;
+var
+  n: Integer;
+begin
+  if ListBox.ItemIndex < 0 then
+    Exit('');
+  Result := ListBox.Items[ListBox.ItemIndex];
+  n := Pos(colon, Result);
+  if n>0 then
+    SetLength(Result, n-1);
+end;
+
+procedure TChangeParentDlg.RefreshList;
+var
+  i: Integer;
+  OldIndex: Integer;
+
+  function MakeItem(ACandidate: TWinControl): string;
+  begin
+    if chShowClasses.Checked then
+      Result := ACandidate.Name + colon + ACandidate.ClassName
+    else
+      Result := ACandidate.Name;
+  end;
+
+  function IsIgnoredName: Boolean;
+  begin
+    Result := (TWinControl(FCandidates.Items[i]).Name = FIgnoredCandidateName);
+  end;
+
+begin
+  OldIndex := ListBox.ItemIndex;
+  ListFilterEdit.FilteredListbox := nil;
+  ListBox.Items.Clear;
+  for i:=0 to FCandidates.Count-1 do
+    if not IsIgnoredName then
+      ListBox.Items.Add(MakeItem(TWinControl(FCandidates.Items[i])));
+  ListBox.ItemIndex := OldIndex;  // if list was filtered it may select other item
+  ListFilterEdit.FilteredListbox := ListBox;
+  ListFilterEdit.Text := '';
+  UpdateOKButtonState;
+end;
+
+procedure TChangeParentDlg.SetSelection(ASelection: TPersistentSelectionList);
+var
+  i, ControlsCount: Integer;
+  sControls, sParents: string;
+  CurParentNameList: TStringList;
+
+  procedure AddControlName(AControlName: string);
+  begin
+    Inc(ControlsCount);
+    if ControlsCount = 1 then
+      sControls := AControlName
+    else
+      sControls := sControls + ', ' + AControlName;
+  end;
+
+  procedure TryAddParentName(AParentName: string);
+  begin
+    if CurParentNameList.IndexOf(AParentName) < 0 then
+      CurParentNameList.Append(AParentName);
+  end;
+
+  procedure SetIgnoredCandidateName;
+  var
+    j: Integer;
+  begin
+    FIgnoredCandidateName := CurParentNameList[0];
+    for j:=1 to CurParentNameList.Count-1 do
+      if FIgnoredCandidateName <> CurParentNameList[j] then
+      begin
+        FIgnoredCandidateName := '';
+        Break;
+      end;
+  end;
+
+begin
+  ControlsCount := 0;
+  CurParentNameList := TStringList.Create;
+
+  for i:=0 to ASelection.Count-1 do
+    if ASelection.Items[i] is TControl then
+      begin
+        AddControlName(TControl(ASelection.Items[i]).Name);
+        TryAddParentName(TControl(ASelection.Items[i]).Parent.Name);
+      end;
+
+  sControls := IfThen(ControlsCount > 1, oisSelectedControls, oisSelectedControl) +
+    ': ' + sControls;
+
+  if CurParentNameList.Count > 0 then
+  begin
+    sParents := IfThen(CurParentNameList.Count > 1, oisCurrentParents, oisCurrentParent) +
+      ': ' + CurParentNameList[0];
+    for i:=1 to CurParentNameList.Count-1 do
+      sParents := sParents + ', ' + CurParentNameList[i];
+    SetIgnoredCandidateName;
+  end;
+
+  lblSelectedControls.Caption := sControls;
+  lblCurentParents.Caption := sParents;
+
+  CurParentNameList.Free;
+end;
+
+procedure TChangeParentDlg.UpdateOKButtonState;
+begin
+  ButtonPanel.OKButton.Enabled := (ListBox.ItemIndex > -1);
+end;
+
+function TChangeParentDlg.ShowModal: Integer;
+begin
+  RefreshList;
+  Result := inherited ShowModal;
+end;
+
+initialization
+  TChangeParentDlg.FSavedWidth := 250;
+  TChangeParentDlg.FSavedHeight := 390;
+  TChangeParentDlg.FSavedShowClasses := False;
+
+end.
+
Index: components/ideintf/ideintf.lpk
===================================================================
--- components/ideintf/ideintf.lpk	(revision 52108)
+++ components/ideintf/ideintf.lpk	(working copy)
@@ -20,7 +20,7 @@
     <Description Value="IDEIntf - the interface units for the Lazarus IDE"/>
     <License Value="Modified LPGL2"/>
     <Version Major="1"/>
-    <Files Count="78">
+    <Files Count="80">
       <Item1>
         <Filename Value="actionseditor.pas"/>
         <UnitName Value="ActionsEditor"/>
@@ -334,6 +334,14 @@
         <Filename Value="toolbarintf.pas"/>
         <UnitName Value="ToolBarIntf"/>
       </Item78>
+      <Item79>
+        <Filename Value="changeparentdlg.pas"/>
+        <UnitName Value="ChangeParentDlg"/>
+      </Item79>
+      <Item80>
+        <Filename Value="changeparentdlg.lfm"/>
+        <Type Value="LFM"/>
+      </Item80>
     </Files>
     <LazDoc Paths="docs"/>
     <i18n>
Index: components/ideintf/ideintf.pas
===================================================================
--- components/ideintf/ideintf.pas	(revision 52108)
+++ components/ideintf/ideintf.pas	(working copy)
@@ -21,7 +21,7 @@
   PackageIntf, ProjectIntf, ProjectResourcesIntf, PropEdits, PropEditUtils, 
   SrcEditorIntf, StatusBarPropEdit, StringsPropEditDlg, TextTools, 
   TreeViewPropEdit, UnitResources, ProjPackIntf, DBGridColumnsPropEditForm, 
-  ToolBarIntf, LazarusPackageIntf;
+  ToolBarIntf, ChangeParentDlg, LazarusPackageIntf;
 
 implementation
 
Index: components/ideintf/objectinspector.pp
===================================================================
--- components/ideintf/objectinspector.pp	(revision 52108)
+++ components/ideintf/objectinspector.pp	(working copy)
@@ -712,7 +712,7 @@
     FOnNodeGetImageIndex: TOnOINodeGetImageEvent;
     procedure CreateTopSplitter;
     procedure CreateBottomSplitter;
-    function GetChangeParentCandidates: TFPList;
+    function GetParentCandidates: TFPList;
     function GetGridControl(Page: TObjectInspectorPage): TOICustomPropertyGrid;
     procedure SetComponentEditor(const AValue: TBaseComponentEditor);
     procedure SetFavorites(const AValue: TOIFavoriteProperties);
@@ -776,6 +776,8 @@
     function GetActivePropertyGrid: TOICustomPropertyGrid;
     function GetActivePropertyRow: TOIPropertyGridRow;
     function GetCurRowDefaultValue(var DefaultStr: string): Boolean;
+    function GetHasParentCandidates: Boolean;
+    procedure ChangeParent;
     procedure HookRefreshPropertyValues;
     procedure ActivateGrid(Grid: TOICustomPropertyGrid);
     procedure FocusGrid(Grid: TOICustomPropertyGrid = nil);
@@ -841,7 +843,7 @@
 {$R images\ideintf_images.res}
 
 uses
-  math;
+  math, ChangeParentDlg;
 
 const
   DefaultOIPageNames: array[TObjectInspectorPage] of shortstring = (
@@ -4108,9 +4110,9 @@
   AddPopupMenuItem(ChangeClassPopupMenuItem,nil,'ChangeClassPopupMenuItem',
      oisChangeClass,'Change Class of component', '',
      @OnChangeClassPopupmenuItemClick,false,true,true);
-  AddPopupMenuItem(ChangeParentPopupMenuItem,nil,'ChangeParentPopupMenuItem',
-     oisChangeParent,'Change Parent of component', '',
-     Nil,false,true,true);
+  AddPopupMenuItem(ChangeParentPopupMenuItem, nil, 'ChangeParentPopupMenuItem',
+     oisChangeParent+' ...', 'Change Parent of component', '',
+     @DoChangeParentItemClick, False, True, True);
   OptionsSeparatorMenuItem3 := AddSeparatorMenuItem(nil, 'OptionsSeparatorMenuItem3', true);
 
   AddPopupMenuItem(ShowComponentTreePopupMenuItem,nil
@@ -4500,6 +4502,89 @@
   end;
 end;
 
+function TObjectInspectorDlg.GetHasParentCandidates: Boolean;
+var
+  Candidates: TFPList=nil;
+begin
+  try
+    Candidates := GetParentCandidates;
+    Result := (Candidates.Count>1);  // single candidate is current parent
+  finally
+    Candidates.Free;
+  end;
+end;
+
+procedure TObjectInspectorDlg.ChangeParent;
+var
+  i: Integer;
+  Control: TControl;
+  NewParentName: String;
+  NewParent: TPersistent;
+  NewSelection: TPersistentSelectionList;
+  Candidates: TFPList = nil;
+
+begin
+  if (Selection.Count < 1) then Exit;
+
+  try
+    Candidates := GetParentCandidates;
+    if not ShowChangeParentDlg(NewParentName, Selection, Candidates) then
+      Exit;
+  finally
+    Candidates.Free;
+  end;
+
+  if NewParentName = TWinControl(FPropertyEditorHook.LookupRoot).Name then
+    NewParent := FPropertyEditorHook.LookupRoot
+  else
+    NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName);
+
+  if not (NewParent is TWinControl) then Exit;
+
+  for i := 0 to Selection.Count-1 do
+  begin
+    if not (Selection[i] is TControl) then Continue;
+    Control := TControl(Selection[i]);
+    if Control.Parent = nil then Continue;
+    Control.Parent := TWinControl(NewParent);
+  end;
+
+  // Following code taken from DoZOrderItemClick();
+  // Ensure the order of controls in the OI now reflects the new ZOrder
+  //NewSelection := TPersistentSelectionList.Create;
+  //try
+  //  NewSelection.ForceUpdate:=True;
+  //  NewSelection.Add(Control.Parent);
+  //  SetSelection(NewSelection);
+  //
+  //  NewSelection.Clear;
+  //  NewSelection.ForceUpdate:=True;
+  //  NewSelection.Add(Control);
+  //  SetSelection(NewSelection);
+  //finally
+  //  NewSelection.Free;
+  //end;
+
+  // Ensure the order of controls in the OI now reflects the new ZOrder
+  // (this code based on commented above)
+  NewSelection := TPersistentSelectionList.Create;
+  try
+    NewSelection.ForceUpdate:=True;
+    NewSelection.Add(NewParent);
+    for i:=0 to Selection.Count-1 do
+      NewSelection.Add(Selection.Items[i]);
+    SetSelection(NewSelection);
+
+    NewSelection.ForceUpdate:=True;
+    NewSelection.Delete(0);
+    SetSelection(NewSelection);
+  finally
+    NewSelection.Free;
+  end;
+
+  DoModified(Self);
+end;
+
 procedure TObjectInspectorDlg.SetSelection(const ASelection: TPersistentSelectionList);
 var
   OldInSelection: Boolean;
@@ -5316,7 +5401,7 @@
 end;
 // ---
 
-function TObjectInspectorDlg.GetChangeParentCandidates: TFPList;
+function TObjectInspectorDlg.GetParentCandidates: TFPList;
 var
   i, j: Integer;
   CurSelected: TPersistent;
@@ -5482,27 +5567,6 @@
     MainPopupMenu.Items.Insert(ZItem.MenuIndex + 1, Item);
   end;
 
-  function AddChangeParentMenuItems: Boolean;
-  var
-    Item: TMenuItem;
-    Candidates: TFPList;
-    i: Integer;
-  begin
-    Candidates := GetChangeParentCandidates;
-    try
-      Result := Candidates.Count>0;
-      ChangeParentPopupmenuItem.Clear;
-      for i := 0 to Candidates.Count-1 do
-      begin
-        Item := NewItem(TWinControl(Candidates[i]).Name, 0, False, True,
-                        @DoChangeParentItemClick, 0, '');
-        ChangeParentPopupmenuItem.Add(Item);
-      end;
-    finally
-      Candidates.Free;
-    end;
-  end;
-
 var
   b, AtLeastOneComp, CanChangeClass, HasParentCandidates: Boolean;
   CurRow: TOIPropertyGridRow;
@@ -5540,9 +5604,9 @@
     // add Z-Order menu
     if (Selection.Count = 1) and (Selection[0] is TControl) then
       AddZOrderMenuItems;
-    // add Change Parent menu
+    // check existing of Change Parent candidates
     if AtLeastOneComp then
-      HasParentCandidates := AddChangeParentMenuItems;
+      HasParentCandidates := GetHasParentCandidates;
   end;
   CutPopupMenuItem.Visible := AtLeastOneComp;
   CopyPopupMenuItem.Visible := AtLeastOneComp;
@@ -5606,45 +5670,9 @@
 end;
 
 procedure TObjectInspectorDlg.DoChangeParentItemClick(Sender: TObject);
-var
-  i: Integer;
-  Control: TControl;
-  NewParent: TPersistent;
-  NewSelection: TPersistentSelectionList;
 begin
-  if not (Sender is TMenuItem) or (Selection.Count < 1) then Exit;
-  if TMenuItem(Sender).Caption = TWinControl(FPropertyEditorHook.LookupRoot).Name then
-    NewParent := FPropertyEditorHook.LookupRoot
-  else
-    NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(TMenuItem(Sender).Caption);
-
-  if not (NewParent is TWinControl) then Exit;
-
-  for i := 0 to Selection.Count-1 do
-  begin
-    if not (Selection[i] is TControl) then Continue;
-    Control := TControl(Selection[i]);
-    if Control.Parent = nil then Continue;
-    Control.Parent := TWinControl(NewParent);
-  end;
-
-  // Following code taken from DoZOrderItemClick();
-  // Ensure the order of controls in the OI now reflects the new ZOrder
-  NewSelection := TPersistentSelectionList.Create;
-  try
-    NewSelection.ForceUpdate:=True;
-    NewSelection.Add(Control.Parent);
-    SetSelection(NewSelection);
-
-    NewSelection.Clear;
-    NewSelection.ForceUpdate:=True;
-    NewSelection.Add(Control);
-    SetSelection(NewSelection);
-  finally
-    NewSelection.Free;
-  end;
-
-  DoModified(Self);
+  if Selection.Count > 0 then
+    ChangeParent;
 end;
 
 procedure TObjectInspectorDlg.DoComponentEditorVerbMenuItemClick(Sender: TObject);
Index: components/ideintf/objinspstrconsts.pas
===================================================================
--- components/ideintf/objinspstrconsts.pas	(revision 52108)
+++ components/ideintf/objinspstrconsts.pas	(working copy)
@@ -441,6 +441,13 @@
   oisChangeParent = 'Change Parent';
   lisUnableToFindParserForTool = 'Unable to find parser for tool "%s"';
 
+  // TChangeParentDlg
+  oisShowClasses = 'Show classes';
+  oisSelectedControl = 'Selected control';
+  oisSelectedControls = 'Selected controls';
+  oisCurrentParent = 'Current parent';
+  oisCurrentParents = 'Current parents';
+
   // Dbgrid Columns editor
   dceAddFields = 'Add Fields';
   dceDeleteAll  = 'Delete All';
Index: designer/designer.pp
===================================================================
--- designer/designer.pp	(revision 52108)
+++ designer/designer.pp	(working copy)
@@ -410,7 +410,7 @@
   DesignerMenuSelectAll: TIDEMenuCommand;
 
   DesignerMenuChangeClass: TIDEMenuCommand;
-  DesignerMenuChangeParent: TIDEMenuSection;
+  DesignerMenuChangeParent: TIDEMenuCommand;
   DesignerMenuViewLFM: TIDEMenuCommand;
   DesignerMenuSaveAsXML: TIDEMenuCommand;
   DesignerMenuCenterForm: TIDEMenuCommand;
@@ -425,6 +425,8 @@
 
 implementation
 
+uses MainIntf;
+
 type
   TCustomFormAccess = class(TCustomForm);
   TControlAccess = class(TControl);
@@ -600,10 +602,8 @@
   DesignerMenuSectionMisc:=RegisterIDEMenuSection(DesignerMenuRoot,'Miscellaneous section');
     DesignerMenuChangeClass:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                  'Change class',lisDlgChangeClass);
-    DesignerMenuChangeParent:=RegisterIDEMenuSection(DesignerMenuSectionMisc,
-                                                 'Change parent');
-    DesignerMenuChangeParent.ChildrenAsSubMenu:=true;
-    DesignerMenuChangeParent.Caption:=lisChangeParent;
+    DesignerMenuChangeParent:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
+                                                 'Change parent',lisChangeParent+' ...');
     DesignerMenuViewLFM:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
                                                 'View LFM',lisViewSourceLfm);
     DesignerMenuSaveAsXML:=RegisterIDEMenuCommand(DesignerMenuSectionMisc,
@@ -3264,43 +3264,9 @@
 end;
 
 procedure TDesigner.OnChangeParentMenuClick(Sender: TObject);
-var
-  Item: TIDEMenuCommand;
-  NewParentName: String;
-  i: Integer;
-  CurControl: TControl;
-  NewParent: TWinControl;
 begin
-  if not (Sender is TIDEMenuCommand) then Exit;
-  Item := TIDEMenuCommand(Sender);
-  NewParentName := Item.Caption;
-  if SysUtils.CompareText(LookupRoot.Name, NewParentName) = 0 then
-    NewParent := TWinControl(LookupRoot)
-  else
-    NewParent := TWinControl(LookupRoot.FindComponent(NewParentName));
-  if (NewParent=nil) or (not (NewParent is TWinControl)) then Exit;
-
-  Form.DisableAlign;
-  try
-    i := ControlSelection.Count - 1;
-    while (i >= 0) do 
-    begin
-      if i < ControlSelection.Count then 
-      begin
-        if ControlSelection[i].IsTControl then
-        begin
-          CurControl := TControl(ControlSelection[i].Persistent);
-          if CurControl.Owner = LookupRoot then
-            CurControl.Parent := NewParent;
-        end;
-      end;
-      dec(i);
-    end;
-  finally
-    if Form <> nil then
-      Form.EnableAlign;
-    ControlSelection.DoChange(True); // request updates since control hierarchi change
-  end;
+  if Assigned(ObjectInspector1) then
+    ObjectInspector1.ChangeParent;
 end;
 
 procedure TDesigner.OnSnapToGridOptionMenuClick(Sender: TObject);
@@ -3886,6 +3852,7 @@
   DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
 
   DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
+  DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
   DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
   DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
   DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
@@ -3909,81 +3876,12 @@
   SrcFile: TLazProjectFile;
   UnitIsVirtual, DesignerCanCopy: Boolean;
 
-  function GetChangeParentCandidates: TFPList;
-  var
-    i,j: Integer;
-    CurSelected: TSelectedControl;
-    Candidate: TWinControl;
-  begin
-    Result:=TFPList.Create;
-    if ControlSelection.Count=0 then exit;
-    if LookupRootIsSelected then
-      exit; // if the LookupRoot is selected, do not show "change parent"
-    if not (LookupRoot is TWinControl) then
-      exit; // only LCL controls are supported at the moment
-
-    // check if any selected control can be moved
-    i:=ControlSelection.Count-1;
-    while i>=0 do
-    begin
-      CurSelected:=ControlSelection[i];
-      if CurSelected.IsTControl
-      and (TControl(CurSelected.Persistent).Owner=LookupRoot)
-      then
-        // this one can be moved
-        break;
-      dec(i);
-    end;
-    if i<0 then exit;
-
-    // find possible new parents
-    for i := 0 to LookupRoot.ComponentCount - 1 do
-    begin
-      Candidate:=TWinControl(LookupRoot.Components[i]);
-      if not (Candidate is TWinControl) then continue;
-
-      j:=ControlSelection.Count-1;
-      while j>=0 do
-      begin
-        CurSelected:=ControlSelection[j];
-        if CurSelected.IsTControl then begin
-          if CurSelected.Persistent=Candidate then break;
-          if CurSelected.IsTWinControl and
-             TWinControl(CurSelected.Persistent).IsParentOf(Candidate) then
-            break;
-          if not ControlAcceptsStreamableChildComponent(Candidate,
-                            TComponentClass(CurSelected.ClassType),LookupRoot)
-          then
-            break;
-        end;
-        dec(j);
-      end;
-      if j<0 then
-        Result.Add(Candidate);
-    end;
-    Result.Add(LookupRoot);
-  end;
-
   procedure UpdateChangeParentMenu;
-  var
-    Candidates: TFPList;
-    i: Integer;
-    Item: TIDEMenuItem;
   begin
-    Candidates:=GetChangeParentCandidates;
-    try
-      DesignerMenuChangeParent.Visible:=Candidates.Count>0;
-      DesignerMenuChangeParent.Clear;
-      for i:=0 to Candidates.Count-1 do
-      begin
-        Item:=TIDEMenuCommand.Create(DesignerMenuChangeParent.Name+'_'+IntToStr(i));
-        DesignerMenuChangeParent.AddLast(Item);
-        Item.Caption:=TWinControl(Candidates[i]).Name;
-        Item.OnClick:=@OnChangeParentMenuClick;
-      end;
-    finally
-      Candidates.Free;
-    end;
+    if ObjectInspector1=nil then
+      DesignerMenuChangeParent.Enabled := False
+    else
+      DesignerMenuChangeParent.Enabled := ObjectInspector1.GetHasParentCandidates;
   end;
   
 begin
patch_v4.diff (26,443 bytes)

FTurtle

2016-04-12 04:13

reporter   ~0091963

Last edited: 2016-04-12 04:25

View 3 revisions

New patch attached: patch_v4.diff

In this patch I used specialized dialog.
Reusable dialog I will make in other patch with new issue.

Juha Manninen

2016-04-12 15:51

developer   ~0091975

The new patch looks promising.
I will apply it after my (hopefully) temporary problems with SVN server are solved. Now the server does not respond to "svn commit" altough "svn up" works.

Juha Manninen

2016-04-14 12:32

developer   ~0092036

I applied the patch and then removed the explicit OI dependency by using events.
Actually this feature in Designer still depends on OI.
In a rare case when OI is not visible at all, it does not work. Yes, it is a rare case.
The best would be to have a common interface for OI and Designer, then this code would depend on interface only.
Now we don't have such interface.

FTurtle

2016-04-17 13:37

reporter   ~0092059

Closed

Issue History

Date Modified Username Field Change
2016-03-21 05:03 FTurtle New Issue
2016-03-21 05:03 FTurtle File Added: patch.diff
2016-03-21 05:21 FTurtle File Added: patch_v2.diff
2016-03-21 05:22 FTurtle Note Added: 0091246
2016-03-21 07:42 FTurtle File Added: patch_v3.diff
2016-03-21 07:43 FTurtle Note Added: 0091247
2016-03-21 10:12 Juha Manninen Assigned To => Juha Manninen
2016-03-21 10:12 Juha Manninen Status new => assigned
2016-03-23 14:41 Juha Manninen Note Added: 0091292
2016-03-23 14:42 Juha Manninen Note Edited: 0091292 View Revisions
2016-03-23 14:45 Juha Manninen Note Edited: 0091292 View Revisions
2016-03-23 14:46 Juha Manninen Note Edited: 0091292 View Revisions
2016-03-23 14:47 Juha Manninen Note Edited: 0091292 View Revisions
2016-03-23 16:02 FTurtle Note Added: 0091296
2016-03-25 11:45 Juha Manninen Note Edited: 0091292 View Revisions
2016-04-12 04:11 FTurtle File Added: patch_v4.diff
2016-04-12 04:13 FTurtle Note Added: 0091963
2016-04-12 04:24 FTurtle Note Edited: 0091963 View Revisions
2016-04-12 04:25 FTurtle Note Edited: 0091963 View Revisions
2016-04-12 15:51 Juha Manninen Note Added: 0091975
2016-04-14 12:32 Juha Manninen Fixed in Revision => r52193, r52194, r52195
2016-04-14 12:32 Juha Manninen LazTarget => -
2016-04-14 12:32 Juha Manninen Note Added: 0092036
2016-04-14 12:32 Juha Manninen Status assigned => resolved
2016-04-14 12:32 Juha Manninen Resolution open => fixed
2016-04-17 13:37 FTurtle Note Added: 0092059
2016-04-17 13:37 FTurtle Status resolved => closed