mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 04:29:28 +02:00
Designer: Support Undo-action for changed Parent of a component. Issue #26815.
git-svn-id: trunk@61996 -
This commit is contained in:
parent
77b19309f9
commit
5ff78d5320
@ -28,9 +28,9 @@ uses
|
|||||||
// LazUtils
|
// LazUtils
|
||||||
LazLoggerBase,
|
LazLoggerBase,
|
||||||
// LCL
|
// LCL
|
||||||
LCLProc, Dialogs, Controls, ComCtrls, Graphics,
|
LCLProc, Dialogs, Forms, Controls, ComCtrls, Graphics,
|
||||||
// IdeIntf
|
// IdeIntf
|
||||||
ObjInspStrConsts, PropEdits, PropEditUtils, IDEImagesIntf;
|
ObjInspStrConsts, PropEdits, PropEditUtils, ComponentEditors, IDEImagesIntf;
|
||||||
|
|
||||||
type
|
type
|
||||||
TCTVGetImageIndexEvent = procedure(APersistent: TPersistent;
|
TCTVGetImageIndexEvent = procedure(APersistent: TPersistent;
|
||||||
@ -341,22 +341,32 @@ end;
|
|||||||
|
|
||||||
procedure TComponentTreeView.DragDrop(Source: TObject; X, Y: Integer);
|
procedure TComponentTreeView.DragDrop(Source: TObject; X, Y: Integer);
|
||||||
var
|
var
|
||||||
Node, SelNode: TTreeNode;
|
Node, ParentNode, SelNode: TTreeNode;
|
||||||
ACollection: TCollection;
|
ACollection: TCollection;
|
||||||
AContainer: TWinControl;
|
AContainer, OldContainer: TWinControl;
|
||||||
AControl: TControl;
|
AControl: TControl;
|
||||||
ParentNode: TTreeNode;
|
|
||||||
InsertType: TTreeViewInsertMarkType;
|
InsertType: TTreeViewInsertMarkType;
|
||||||
|
RootDesigner: TIDesigner;
|
||||||
|
CompEditDsg: TComponentEditorDesigner;
|
||||||
NewIndex, AIndex: Integer;
|
NewIndex, AIndex: Integer;
|
||||||
ok: Boolean;
|
ok: Boolean;
|
||||||
begin
|
begin
|
||||||
GetComponentInsertMarkAt(X, Y, Node, InsertType);
|
GetComponentInsertMarkAt(X, Y, Node, InsertType);
|
||||||
SetInsertMark(nil, tvimNone);
|
SetInsertMark(nil, tvimNone);
|
||||||
ParentNode := Node;
|
|
||||||
if InsertType in [tvimAsNextSibling, tvimAsPrevSibling] then
|
if InsertType in [tvimAsNextSibling, tvimAsPrevSibling] then
|
||||||
ParentNode := ParentNode.Parent;
|
ParentNode := Node.Parent
|
||||||
|
else
|
||||||
|
ParentNode := Node;
|
||||||
if Assigned(ParentNode) then
|
if Assigned(ParentNode) then
|
||||||
begin
|
begin
|
||||||
|
// Find designer for Undo actions.
|
||||||
|
Assert(Assigned(FPropertyEditorHook), 'TComponentTreeView.DragDrop: PropertyEditorHook=Nil.');
|
||||||
|
RootDesigner := FindRootDesigner(FPropertyEditorHook.LookupRoot);
|
||||||
|
if (RootDesigner is TComponentEditorDesigner) then
|
||||||
|
CompEditDsg := TComponentEditorDesigner(RootDesigner) //if CompEditDsg.IsUndoLocked then Exit;
|
||||||
|
else
|
||||||
|
CompEditDsg := nil;
|
||||||
|
|
||||||
if TObject(ParentNode.Data) is TWinControl then
|
if TObject(ParentNode.Data) is TWinControl then
|
||||||
begin
|
begin
|
||||||
AContainer := TWinControl(ParentNode.Data);
|
AContainer := TWinControl(ParentNode.Data);
|
||||||
@ -368,7 +378,11 @@ begin
|
|||||||
AControl := TControl(SelNode.Data);
|
AControl := TControl(SelNode.Data);
|
||||||
ok:=false;
|
ok:=false;
|
||||||
try
|
try
|
||||||
|
OldContainer := AControl.Parent;
|
||||||
AControl.Parent := AContainer;
|
AControl.Parent := AContainer;
|
||||||
|
if Assigned(CompEditDsg) then
|
||||||
|
CompEditDsg.AddUndoAction(AControl, uopChange, True, 'Parent',
|
||||||
|
OldContainer.Name, AContainer.Name);
|
||||||
ok:=true;
|
ok:=true;
|
||||||
DoModified;
|
DoModified;
|
||||||
except
|
except
|
||||||
|
@ -1555,12 +1555,12 @@ var
|
|||||||
OldExpanded: boolean;
|
OldExpanded: boolean;
|
||||||
OldChangeStep: integer;
|
OldChangeStep: integer;
|
||||||
RootDesigner: TIDesigner;
|
RootDesigner: TIDesigner;
|
||||||
|
CompEditDsg: TComponentEditorDesigner;
|
||||||
APersistent: TPersistent;
|
APersistent: TPersistent;
|
||||||
i: integer;
|
i: integer;
|
||||||
NewVal: string;
|
NewVal: string;
|
||||||
oldVal: array of string;
|
oldVal: array of string;
|
||||||
isExcept: boolean;
|
isExcept: boolean;
|
||||||
CompEditDsg: TComponentEditorDesigner;
|
|
||||||
prpInfo: PPropInfo;
|
prpInfo: PPropInfo;
|
||||||
Editor: TPropertyEditor;
|
Editor: TPropertyEditor;
|
||||||
begin
|
begin
|
||||||
@ -2368,7 +2368,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState;
|
procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState;
|
||||||
X,Y:integer);
|
X,Y:integer);
|
||||||
var
|
var
|
||||||
IconX,Index:integer;
|
IconX,Index:integer;
|
||||||
@ -4781,9 +4781,10 @@ var
|
|||||||
NewParent: TPersistent;
|
NewParent: TPersistent;
|
||||||
NewSelection: TPersistentSelectionList;
|
NewSelection: TPersistentSelectionList;
|
||||||
Candidates: TFPList = nil;
|
Candidates: TFPList = nil;
|
||||||
|
RootDesigner: TIDesigner;
|
||||||
|
CompEditDsg: TComponentEditorDesigner;
|
||||||
begin
|
begin
|
||||||
if (Selection.Count < 1) then Exit;
|
if (Selection.Count < 1) then Exit;
|
||||||
|
|
||||||
try
|
try
|
||||||
Candidates := GetParentCandidates;
|
Candidates := GetParentCandidates;
|
||||||
if not ShowChangeParentDlg(Selection, Candidates, NewParentName) then
|
if not ShowChangeParentDlg(Selection, Candidates, NewParentName) then
|
||||||
@ -4796,14 +4797,23 @@ begin
|
|||||||
NewParent := FPropertyEditorHook.LookupRoot
|
NewParent := FPropertyEditorHook.LookupRoot
|
||||||
else
|
else
|
||||||
NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName);
|
NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName);
|
||||||
|
|
||||||
if not (NewParent is TWinControl) then Exit;
|
if not (NewParent is TWinControl) then Exit;
|
||||||
|
|
||||||
|
// Find designer for Undo actions.
|
||||||
|
RootDesigner := FindRootDesigner(FPropertyEditorHook.LookupRoot);
|
||||||
|
if (RootDesigner is TComponentEditorDesigner) then
|
||||||
|
CompEditDsg := TComponentEditorDesigner(RootDesigner) //if CompEditDsg.IsUndoLocked then Exit;
|
||||||
|
else
|
||||||
|
CompEditDsg := nil;
|
||||||
|
|
||||||
for i := 0 to Selection.Count-1 do
|
for i := 0 to Selection.Count-1 do
|
||||||
begin
|
begin
|
||||||
if not (Selection[i] is TControl) then Continue;
|
if not (Selection[i] is TControl) then Continue;
|
||||||
Control := TControl(Selection[i]);
|
Control := TControl(Selection[i]);
|
||||||
if Control.Parent = nil then Continue;
|
if Control.Parent = nil then Continue;
|
||||||
|
if Assigned(CompEditDsg) then
|
||||||
|
CompEditDsg.AddUndoAction(Control, uopChange, i=0, 'Parent',
|
||||||
|
Control.Parent.Name, NewParentName);
|
||||||
Control.Parent := TWinControl(NewParent);
|
Control.Parent := TWinControl(NewParent);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ type
|
|||||||
function Undo: Boolean; override;
|
function Undo: Boolean; override;
|
||||||
function Redo: Boolean; override;
|
function Redo: Boolean; override;
|
||||||
function AddUndoAction(const aPersistent: TPersistent; aOpType: TUndoOpType;
|
function AddUndoAction(const aPersistent: TPersistent; aOpType: TUndoOpType;
|
||||||
StartNewGroup: boolean; aFieldName: string; const aOldVal, aNewVal: variant): boolean; override;
|
StartNewGroup: boolean; aFieldName: string; const aOldVal, aNewVal: Variant): boolean; override;
|
||||||
function IsUndoLocked: boolean; override;
|
function IsUndoLocked: boolean; override;
|
||||||
procedure ClearUndoItem(AIndex: Integer);
|
procedure ClearUndoItem(AIndex: Integer);
|
||||||
procedure AddComponent(const NewRegisteredComponent: TRegisteredComponent;
|
procedure AddComponent(const NewRegisteredComponent: TRegisteredComponent;
|
||||||
@ -1418,96 +1418,84 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDesigner.ExecuteUndoItem(IsActUndo: boolean);
|
procedure TDesigner.ExecuteUndoItem(IsActUndo: boolean);
|
||||||
|
var
|
||||||
|
AValue: Variant;
|
||||||
|
ValueStr, tmpFieldN: string;
|
||||||
|
tmpObj: TComponent;
|
||||||
|
|
||||||
procedure SetPropVal(AVal: variant);
|
procedure SetPublished; // published field
|
||||||
var
|
var
|
||||||
tmpStr, tmpFieldN, str: string;
|
|
||||||
tmpCompN: TComponentName;
|
|
||||||
tmpObj: TObject;
|
|
||||||
tmpInt: integer;
|
|
||||||
aPropType: PTypeInfo;
|
aPropType: PTypeInfo;
|
||||||
|
s: string;
|
||||||
|
i: integer;
|
||||||
begin
|
begin
|
||||||
tmpCompN := FUndoList[FUndoCurr].compName;
|
aPropType:=FUndoList[FUndoCurr].propInfo^.propType;
|
||||||
tmpFieldN := FUndoList[FUndoCurr].fieldName;
|
case aPropType^.Kind of
|
||||||
if tmpFieldN = 'Name' then
|
tkInteger, tkInt64:
|
||||||
begin
|
|
||||||
if IsActUndo then
|
|
||||||
tmpCompN := FUndoList[FUndoCurr].newVal
|
|
||||||
else
|
|
||||||
tmpCompN := FUndoList[FUndoCurr].oldVal;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if FForm.Name <> tmpCompN then
|
|
||||||
tmpObj := TObject(FForm.FindSubComponent(tmpCompN))
|
|
||||||
else
|
|
||||||
tmpObj := TObject(FForm);
|
|
||||||
|
|
||||||
if VarIsError(AVal) or VarIsEmpty(AVal) or VarIsNull(AVal) then
|
|
||||||
ShowMessage('error: invalid var type');
|
|
||||||
tmpStr := VarToStr(AVal);
|
|
||||||
//DebugLn(['TDesigner.ExecuteUndoItem: FForm=', FForm.Name, ', CompName=', tmpCompN,
|
|
||||||
// ', FieldName=', tmpFieldN, ', tmpObj=', tmpObj, ', tmpStr=', tmpStr, ', IsActUndo=', IsActUndo]);
|
|
||||||
|
|
||||||
if FUndoList[FUndoCurr].propInfo<>nil then
|
|
||||||
begin
|
|
||||||
aPropType:=FUndoList[FUndoCurr].propInfo^.propType;
|
|
||||||
case aPropType^.Kind of
|
|
||||||
tkInteger, tkInt64:
|
|
||||||
begin
|
|
||||||
if (aPropType^.Name = 'TColor') or
|
|
||||||
(aPropType^.Name = 'TGraphicsColor') then
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, StringToColor(tmpStr))
|
|
||||||
else if aPropType^.Name = 'TCursor' then
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, StringToCursor(tmpStr))
|
|
||||||
else
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, StrToInt(tmpStr));
|
|
||||||
end;
|
|
||||||
tkChar, tkWChar, tkUChar:
|
|
||||||
begin
|
|
||||||
if Length(tmpStr) = 1 then
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, Ord(tmpStr[1]))
|
|
||||||
else if (tmpStr[1] = '#') then
|
|
||||||
begin
|
|
||||||
str := Copy(tmpStr, 2, Length(tmpStr) - 1);
|
|
||||||
if TryStrToInt(str, tmpInt) and (tmpInt >= 0) and (tmpInt <= High(Byte)) then
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, tmpInt);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
tkEnumeration:
|
|
||||||
SetEnumProp(tmpObj, tmpFieldN, tmpStr);
|
|
||||||
tkFloat:
|
|
||||||
SetFloatProp(tmpObj, tmpFieldN, StrToFloat(tmpStr));
|
|
||||||
tkBool:
|
|
||||||
SetOrdProp(tmpObj, tmpFieldN, Integer(StrToBoolOI(tmpStr)));
|
|
||||||
tkString, tkLString, tkAString, tkUString, tkWString:
|
|
||||||
SetStrProp(tmpObj, tmpFieldN, tmpStr);
|
|
||||||
tkSet:
|
|
||||||
SetSetProp(tmpObj, tmpFieldN, tmpStr);
|
|
||||||
tkVariant:
|
|
||||||
SetVariantProp(tmpObj, tmpFieldN, AVal);
|
|
||||||
else
|
|
||||||
ShowMessage(Format('error: unknown TTypeKind(%d)', [Integer(aPropType^.Kind)]));
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
// field is not published
|
|
||||||
if tmpObj is TComponent then
|
|
||||||
begin
|
begin
|
||||||
// special case: TComponent.Left,Top
|
if (aPropType^.Name = 'TColor') or
|
||||||
if CompareText(tmpFieldN,'Left')=0 then
|
(aPropType^.Name = 'TGraphicsColor') then
|
||||||
SetDesignInfoLeft(TComponent(tmpObj),StrToInt(tmpStr))
|
SetOrdProp(tmpObj, tmpFieldN, StringToColor(ValueStr))
|
||||||
else if CompareText(tmpFieldN,'Top')=0 then
|
else if aPropType^.Name = 'TCursor' then
|
||||||
SetDesignInfoTop(TComponent(tmpObj),StrToInt(tmpStr));
|
SetOrdProp(tmpObj, tmpFieldN, StringToCursor(ValueStr))
|
||||||
|
else
|
||||||
|
SetOrdProp(tmpObj, tmpFieldN, StrToInt(ValueStr));
|
||||||
|
end;
|
||||||
|
tkChar, tkWChar, tkUChar:
|
||||||
|
begin
|
||||||
|
if Length(ValueStr) = 1 then
|
||||||
|
SetOrdProp(tmpObj, tmpFieldN, Ord(ValueStr[1]))
|
||||||
|
else if (ValueStr[1] = '#') then
|
||||||
|
begin
|
||||||
|
s := Copy(ValueStr, 2, Length(ValueStr) - 1);
|
||||||
|
if TryStrToInt(s, i) and (i >= 0) and (i <= High(Byte)) then
|
||||||
|
SetOrdProp(tmpObj, tmpFieldN, i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
tkEnumeration:
|
||||||
|
SetEnumProp(tmpObj, tmpFieldN, ValueStr);
|
||||||
|
tkFloat:
|
||||||
|
SetFloatProp(tmpObj, tmpFieldN, StrToFloat(ValueStr));
|
||||||
|
tkBool:
|
||||||
|
SetOrdProp(tmpObj, tmpFieldN, Integer(StrToBoolOI(ValueStr)));
|
||||||
|
tkString, tkLString, tkAString, tkUString, tkWString:
|
||||||
|
SetStrProp(tmpObj, tmpFieldN, ValueStr);
|
||||||
|
tkSet:
|
||||||
|
SetSetProp(tmpObj, tmpFieldN, ValueStr);
|
||||||
|
tkVariant:
|
||||||
|
SetVariantProp(tmpObj, tmpFieldN, AValue);
|
||||||
|
else
|
||||||
|
ShowMessage(Format('error: unknown TTypeKind(%d)', [Integer(aPropType^.Kind)]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetUnPublished; // field is not published
|
||||||
|
var
|
||||||
|
NewParent: TComponent;
|
||||||
|
begin
|
||||||
|
if tmpObj is TControl then
|
||||||
|
begin
|
||||||
|
if CompareText(tmpFieldN,'Parent')=0 then // Special treatment for Parent.
|
||||||
|
begin
|
||||||
|
if FForm.Name <> ValueStr then // Find the parent by name.
|
||||||
|
NewParent := FForm.FindComponent(ValueStr)
|
||||||
|
else
|
||||||
|
NewParent := FForm;
|
||||||
|
Assert(NewParent is TWinControl, 'TDesigner.ExecuteUndoItem: New Parent "'
|
||||||
|
+ DbgS(NewParent) + '" is not a TWinControl.');
|
||||||
|
TControl(tmpObj).Parent := TWinControl(NewParent);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
PropertyEditorHook.Modified(tmpObj);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
CurTextCompStream: TMemoryStream;
|
CurTextCompStream: TMemoryStream;
|
||||||
SaveControlSelection: TControlSelection;
|
SaveControlSelection: TControlSelection;
|
||||||
|
CompN: TComponentName;
|
||||||
begin
|
begin
|
||||||
if (IsActUndo and (FUndoList[FUndoCurr].opType in [uopAdd])) or
|
// Undo Add component
|
||||||
(not IsActUndo and (FUndoList[FUndoCurr].opType in [uopDelete])) then
|
if (IsActUndo and (FUndoList[FUndoCurr].opType = uopAdd)) or
|
||||||
|
(not IsActUndo and (FUndoList[FUndoCurr].opType = uopDelete)) then
|
||||||
begin
|
begin
|
||||||
Selection.BeginUpdate;
|
Selection.BeginUpdate;
|
||||||
try
|
try
|
||||||
@ -1527,8 +1515,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (IsActUndo and (FUndoList[FUndoCurr].opType in [uopDelete])) or
|
// Undo Delete component
|
||||||
(not IsActUndo and (FUndoList[FUndoCurr].opType in [uopAdd])) then
|
if (IsActUndo and (FUndoList[FUndoCurr].opType = uopDelete)) or
|
||||||
|
(not IsActUndo and (FUndoList[FUndoCurr].opType = uopAdd)) then
|
||||||
begin
|
begin
|
||||||
CurTextCompStream := TMemoryStream.Create;
|
CurTextCompStream := TMemoryStream.Create;
|
||||||
try
|
try
|
||||||
@ -1543,14 +1532,42 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Undo Change properties of component
|
||||||
if FUndoList[FUndoCurr].opType = uopChange then
|
if FUndoList[FUndoCurr].opType = uopChange then
|
||||||
begin
|
begin
|
||||||
Inc(FUndoLock);
|
Inc(FUndoLock);
|
||||||
try
|
try
|
||||||
if IsActUndo then
|
tmpFieldN := FUndoList[FUndoCurr].fieldName;
|
||||||
SetPropVal(FUndoList[FUndoCurr].oldVal)
|
if tmpFieldN = 'Name' then
|
||||||
|
begin
|
||||||
|
if IsActUndo then
|
||||||
|
CompN := FUndoList[FUndoCurr].newVal
|
||||||
|
else
|
||||||
|
CompN := FUndoList[FUndoCurr].oldVal;
|
||||||
|
end
|
||||||
else
|
else
|
||||||
SetPropVal(FUndoList[FUndoCurr].newVal);
|
CompN := FUndoList[FUndoCurr].compName;
|
||||||
|
|
||||||
|
if FForm.Name <> CompN then
|
||||||
|
tmpObj := FForm.FindSubComponent(CompN)
|
||||||
|
else
|
||||||
|
tmpObj := FForm;
|
||||||
|
|
||||||
|
if IsActUndo then
|
||||||
|
AValue := FUndoList[FUndoCurr].oldVal
|
||||||
|
else
|
||||||
|
AValue := FUndoList[FUndoCurr].newVal;
|
||||||
|
if VarIsError(AValue) or VarIsEmpty(AValue) or VarIsNull(AValue) then
|
||||||
|
ShowMessage('error: invalid var type');
|
||||||
|
ValueStr := VarToStr(AValue);
|
||||||
|
//DebugLn(['TDesigner.ExecuteUndoItem: FForm=', FForm.Name, ', CompName=', CompN,
|
||||||
|
// ', FieldName=', tmpFieldN, ', tmpObj=', tmpObj, ', tmpStr=', ValueStr, ', IsActUndo=', IsActUndo]);
|
||||||
|
|
||||||
|
if FUndoList[FUndoCurr].propInfo<>nil then
|
||||||
|
SetPublished
|
||||||
|
else
|
||||||
|
SetUnPublished;
|
||||||
|
PropertyEditorHook.Modified(tmpObj);
|
||||||
finally
|
finally
|
||||||
Dec(FUndoLock);
|
Dec(FUndoLock);
|
||||||
end;
|
end;
|
||||||
@ -1785,8 +1802,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TDesigner.AddUndoAction(const aPersistent: TPersistent;
|
function TDesigner.AddUndoAction(const aPersistent: TPersistent;
|
||||||
aOpType: TUndoOpType; StartNewGroup: boolean; aFieldName: string; const aOldVal,
|
aOpType: TUndoOpType; StartNewGroup: boolean; aFieldName: string;
|
||||||
aNewVal: variant): boolean;
|
const aOldVal, aNewVal: Variant): boolean;
|
||||||
|
|
||||||
procedure ShiftUndoList;
|
procedure ShiftUndoList;
|
||||||
var
|
var
|
||||||
|
Loading…
Reference in New Issue
Block a user