diff --git a/components/ideintf/ideintf.lpk b/components/ideintf/ideintf.lpk
index 44c91153c8..c8a35d9a8e 100644
--- a/components/ideintf/ideintf.lpk
+++ b/components/ideintf/ideintf.lpk
@@ -20,7 +20,7 @@
-
+
@@ -334,6 +334,14 @@
+
+
+
+
+
+
+
+
diff --git a/components/ideintf/ideintf.pas b/components/ideintf/ideintf.pas
index 4a745a0677..53a440a280 100644
--- a/components/ideintf/ideintf.pas
+++ b/components/ideintf/ideintf.pas
@@ -21,7 +21,7 @@ uses
PackageIntf, ProjectIntf, ProjectResourcesIntf, PropEdits, PropEditUtils,
SrcEditorIntf, StatusBarPropEdit, StringsPropEditDlg, TextTools,
TreeViewPropEdit, UnitResources, ProjPackIntf, DBGridColumnsPropEditForm,
- ToolBarIntf, LazarusPackageIntf;
+ ToolBarIntf, ChangeParentDlg, LazarusPackageIntf;
implementation
diff --git a/components/ideintf/objectinspector.pp b/components/ideintf/objectinspector.pp
index 027a6cd833..08f8b02996 100644
--- a/components/ideintf/objectinspector.pp
+++ b/components/ideintf/objectinspector.pp
@@ -30,7 +30,7 @@ uses
// IMPORTANT: the object inspector is a tool and can be used in other programs
// too. Don't put Lazarus IDE specific things here.
// RTL / FCL
- SysUtils, Types, Classes, TypInfo, FPCanvas,
+ SysUtils, Types, Classes, TypInfo, math, FPCanvas,
// LCL
InterfaceBase, LCLType, LCLIntf, Forms, Buttons, Graphics, GraphType, StdCtrls,
Controls, ComCtrls, ExtCtrls, Menus, Dialogs, Themes, LMessages, LCLProc,
@@ -40,8 +40,9 @@ uses
// LazUtils
LazConfigStorage, LazLoggerBase,
// IdeIntf
- ObjInspStrConsts, PropEdits, ListViewPropEdit, ImageListEditor, ComponentTreeView,
- ComponentEditors, IDEImagesIntf, IDEHelpIntf, OIFavoriteProperties, PropEditUtils;
+ IDEImagesIntf, IDEHelpIntf, ObjInspStrConsts,
+ PropEdits, PropEditUtils, ComponentTreeView, OIFavoriteProperties,
+ ListViewPropEdit, ImageListEditor, ComponentEditors, ChangeParentDlg;
const
OIOptionsFileVersion = 3;
@@ -712,7 +713,7 @@ type
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 +777,8 @@ type
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);
@@ -840,9 +843,6 @@ implementation
{$R *.lfm}
{$R images\ideintf_images.res}
-uses
- math;
-
const
DefaultOIPageNames: array[TObjectInspectorPage] of shortstring = (
'PropertyPage',
@@ -4108,9 +4108,9 @@ begin
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 +4500,138 @@ begin
end;
end;
+function TObjectInspectorDlg.GetParentCandidates: TFPList;
+var
+ i, j: Integer;
+ CurSelected: TPersistent;
+ Candidate: TWinControl;
+begin
+ Result := TFPList.Create;
+ if not (FPropertyEditorHook.LookupRoot is TWinControl) then
+ exit; // only LCL controls are supported at the moment
+
+ // check if any selected control can be moved
+ i := Selection.Count-1;
+ while i >= 0 do
+ begin
+ if (Selection[i] is TControl)
+ and (TControl(Selection[i]).Owner = FPropertyEditorHook.LookupRoot)
+ then
+ // this one can be moved
+ break;
+ dec(i);
+ end;
+ if i < 0 then Exit;
+
+ // find possible new parents
+ for i := 0 to TWinControl(FPropertyEditorHook.LookupRoot).ComponentCount-1 do
+ begin
+ Candidate := TWinControl(TWinControl(FPropertyEditorHook.LookupRoot).Components[i]);
+ if not (Candidate is TWinControl) then continue;
+ j := Selection.Count-1;
+ while j >= 0 do
+ begin
+ CurSelected := Selection[j];
+ if CurSelected is TControl then begin
+ if CurSelected = Candidate then break;
+ if (CurSelected is TWinControl) and
+ (TWinControl(CurSelected) = Candidate.Parent) then
+ break;
+ if not ControlAcceptsStreamableChildComponent(Candidate,
+ TComponentClass(CurSelected.ClassType), FPropertyEditorHook.LookupRoot)
+ then
+ break;
+ end;
+ dec(j);
+ end;
+ if j < 0 then
+ Result.Add(Candidate);
+ end;
+ Result.Add(FPropertyEditorHook.LookupRoot);
+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(Selection, Candidates, NewParentName) 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,56 +5448,6 @@ begin
end;
// ---
-function TObjectInspectorDlg.GetChangeParentCandidates: TFPList;
-var
- i, j: Integer;
- CurSelected: TPersistent;
- Candidate: TWinControl;
-begin
- Result := TFPList.Create;
- if not (FPropertyEditorHook.LookupRoot is TWinControl) then
- exit; // only LCL controls are supported at the moment
-
- // check if any selected control can be moved
- i := Selection.Count-1;
- while i >= 0 do
- begin
- if (Selection[i] is TControl)
- and (TControl(Selection[i]).Owner = FPropertyEditorHook.LookupRoot)
- then
- // this one can be moved
- break;
- dec(i);
- end;
- if i < 0 then Exit;
-
- // find possible new parents
- for i := 0 to TWinControl(FPropertyEditorHook.LookupRoot).ComponentCount-1 do
- begin
- Candidate := TWinControl(TWinControl(FPropertyEditorHook.LookupRoot).Components[i]);
- if not (Candidate is TWinControl) then continue;
- j := Selection.Count-1;
- while j >= 0 do
- begin
- CurSelected := Selection[j];
- if CurSelected is TControl then begin
- if CurSelected = Candidate then break;
- if (CurSelected is TWinControl) and
- (TWinControl(CurSelected) = Candidate.Parent) then
- break;
- if not ControlAcceptsStreamableChildComponent(Candidate,
- TComponentClass(CurSelected.ClassType), FPropertyEditorHook.LookupRoot)
- then
- break;
- end;
- dec(j);
- end;
- if j < 0 then
- Result.Add(Candidate);
- end;
- Result.Add(FPropertyEditorHook.LookupRoot);
-end;
-
procedure TObjectInspectorDlg.OnMainPopupMenuPopup(Sender: TObject);
const
PropertyEditorMIPrefix = 'PropertyEditorVerbMenuItem';
@@ -5482,27 +5564,6 @@ var
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 +5601,9 @@ begin
// 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 +5667,9 @@ begin
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);
diff --git a/components/ideintf/objinspstrconsts.pas b/components/ideintf/objinspstrconsts.pas
index 8f1078338a..09f97b6bdc 100644
--- a/components/ideintf/objinspstrconsts.pas
+++ b/components/ideintf/objinspstrconsts.pas
@@ -441,6 +441,13 @@ resourcestring
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';
diff --git a/designer/designer.pp b/designer/designer.pp
index aea30b5f00..b7fd8f7ec5 100644
--- a/designer/designer.pp
+++ b/designer/designer.pp
@@ -45,7 +45,7 @@ uses
LazFileUtils, LazFileCache,
// IDEIntf
IDEDialogs, PropEdits, PropEditUtils, ComponentEditors, MenuIntf, IDEImagesIntf,
- FormEditingIntf, ComponentReg, IDECommands, LazIDEIntf, ProjectIntf,
+ FormEditingIntf, ComponentReg, IDECommands, LazIDEIntf, ProjectIntf, MainIntf,
// IDE
LazarusIDEStrConsts, EnvironmentOpts, EditorOptions, SourceEditor,
// Designer
@@ -410,7 +410,7 @@ var
DesignerMenuSelectAll: TIDEMenuCommand;
DesignerMenuChangeClass: TIDEMenuCommand;
- DesignerMenuChangeParent: TIDEMenuSection;
+ DesignerMenuChangeParent: TIDEMenuCommand;
DesignerMenuViewLFM: TIDEMenuCommand;
DesignerMenuSaveAsXML: TIDEMenuCommand;
DesignerMenuCenterForm: TIDEMenuCommand;
@@ -600,10 +600,8 @@ begin
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 +3262,11 @@ begin
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;
+ Assert(ObjectInspector1.PropertyEditorHook.LookupRoot = LookupRoot,
+ 'TDesigner.OnChangeParentMenuClick: LookupRoot mismatch.');
+ if Assigned(ObjectInspector1) then
+ ObjectInspector1.ChangeParent;
end;
procedure TDesigner.OnSnapToGridOptionMenuClick(Sender: TObject);
@@ -3886,6 +3852,7 @@ begin
DesignerMenuSelectAll.OnClick:=@OnSelectAllMenuClick;
DesignerMenuChangeClass.OnClick:=@OnChangeClassMenuClick;
+ DesignerMenuChangeParent.OnClick:=@OnChangeParentMenuClick;
DesignerMenuViewLFM.OnClick:=@OnViewLFMMenuClick;
DesignerMenuSaveAsXML.OnClick:=@OnSaveAsXMLMenuClick;
DesignerMenuCenterForm.OnClick:=@OnCenterFormMenuClick;
@@ -3908,84 +3875,6 @@ var
SelectionVisible: Boolean;
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;
- end;
-
begin
SrcFile:=LazarusIDE.GetProjectFileWithDesigner(Self);
ControlSelIsNotEmpty:=(ControlSelection.Count>0)
@@ -4025,8 +3914,8 @@ begin
DesignerMenuChangeClass.Enabled := CompsAreSelected and (ControlSelection.Count = 1);
// Disable ViewLFM menu item for virtual units. There is no form file yet.
DesignerMenuViewLFM.Enabled := not UnitIsVirtual;
- UpdateChangeParentMenu;
-
+ DesignerMenuChangeParent.Enabled := Assigned(ObjectInspector1)
+ and ObjectInspector1.GetHasParentCandidates;
DesignerMenuSnapToGridOption.Checked := EnvironmentOptions.SnapToGrid;
DesignerMenuSnapToGuideLinesOption.Checked := EnvironmentOptions.SnapToGuideLines;
end;