mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-18 14:09:26 +02:00
Merged revision(s) 61996 #5ff78d5320, 62001 #6362b3d71a from trunk:
Designer: Support Undo-action for changed Parent of a component. Issue #26815. ........ Designer: Fix a crash bug caused by r61974 #dcb8bd49fb. Top form has no Owner. ........ git-svn-id: branches/fixes_2_0@62081 -
This commit is contained in:
parent
be966557d4
commit
4455557d6e
@ -28,9 +28,9 @@ uses
|
||||
// LazUtils
|
||||
LazLoggerBase,
|
||||
// LCL
|
||||
LCLProc, Dialogs, Controls, ComCtrls, Graphics,
|
||||
LCLProc, Dialogs, Forms, Controls, ComCtrls, Graphics,
|
||||
// IdeIntf
|
||||
ObjInspStrConsts, PropEdits, PropEditUtils, IDEImagesIntf;
|
||||
ObjInspStrConsts, PropEdits, PropEditUtils, ComponentEditors, IDEImagesIntf;
|
||||
|
||||
type
|
||||
TCTVGetImageIndexEvent = procedure(APersistent: TPersistent;
|
||||
@ -342,22 +342,32 @@ end;
|
||||
|
||||
procedure TComponentTreeView.DragDrop(Source: TObject; X, Y: Integer);
|
||||
var
|
||||
Node, SelNode: TTreeNode;
|
||||
Node, ParentNode, SelNode: TTreeNode;
|
||||
ACollection: TCollection;
|
||||
AContainer: TWinControl;
|
||||
AContainer, OldContainer: TWinControl;
|
||||
AControl: TControl;
|
||||
ParentNode: TTreeNode;
|
||||
InsertType: TTreeViewInsertMarkType;
|
||||
RootDesigner: TIDesigner;
|
||||
CompEditDsg: TComponentEditorDesigner;
|
||||
NewIndex, AIndex: Integer;
|
||||
ok: Boolean;
|
||||
begin
|
||||
GetComponentInsertMarkAt(X, Y, Node, InsertType);
|
||||
SetInsertMark(nil, tvimNone);
|
||||
ParentNode := Node;
|
||||
if InsertType in [tvimAsNextSibling, tvimAsPrevSibling] then
|
||||
ParentNode := ParentNode.Parent;
|
||||
ParentNode := Node.Parent
|
||||
else
|
||||
ParentNode := Node;
|
||||
if Assigned(ParentNode) then
|
||||
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
|
||||
begin
|
||||
AContainer := TWinControl(ParentNode.Data);
|
||||
@ -369,7 +379,11 @@ begin
|
||||
AControl := TControl(SelNode.Data);
|
||||
ok:=false;
|
||||
try
|
||||
OldContainer := AControl.Parent;
|
||||
AControl.Parent := AContainer;
|
||||
if Assigned(CompEditDsg) then
|
||||
CompEditDsg.AddUndoAction(AControl, uopChange, True, 'Parent',
|
||||
OldContainer.Name, AContainer.Name);
|
||||
ok:=true;
|
||||
DoModified;
|
||||
except
|
||||
|
@ -1544,12 +1544,12 @@ var
|
||||
OldExpanded: boolean;
|
||||
OldChangeStep: integer;
|
||||
RootDesigner: TIDesigner;
|
||||
CompEditDsg: TComponentEditorDesigner;
|
||||
APersistent: TPersistent;
|
||||
i: integer;
|
||||
NewVal: string;
|
||||
oldVal: array of string;
|
||||
isExcept: boolean;
|
||||
CompEditDsg: TComponentEditorDesigner;
|
||||
prpInfo: PPropInfo;
|
||||
Editor: TPropertyEditor;
|
||||
begin
|
||||
@ -2358,7 +2358,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState;
|
||||
procedure TOICustomPropertyGrid.MouseDown(Button:TMouseButton; Shift:TShiftState;
|
||||
X,Y:integer);
|
||||
var
|
||||
IconX,Index:integer;
|
||||
@ -4740,9 +4740,10 @@ var
|
||||
NewParent: TPersistent;
|
||||
NewSelection: TPersistentSelectionList;
|
||||
Candidates: TFPList = nil;
|
||||
RootDesigner: TIDesigner;
|
||||
CompEditDsg: TComponentEditorDesigner;
|
||||
begin
|
||||
if (Selection.Count < 1) then Exit;
|
||||
|
||||
try
|
||||
Candidates := GetParentCandidates;
|
||||
if not ShowChangeParentDlg(Selection, Candidates, NewParentName) then
|
||||
@ -4755,14 +4756,23 @@ begin
|
||||
NewParent := FPropertyEditorHook.LookupRoot
|
||||
else
|
||||
NewParent := TWinControl(FPropertyEditorHook.LookupRoot).FindComponent(NewParentName);
|
||||
|
||||
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
|
||||
begin
|
||||
if not (Selection[i] is TControl) then Continue;
|
||||
Control := TControl(Selection[i]);
|
||||
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);
|
||||
end;
|
||||
|
||||
|
@ -305,7 +305,7 @@ type
|
||||
function Undo: Boolean; override;
|
||||
function Redo: Boolean; override;
|
||||
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;
|
||||
procedure ClearUndoItem(AIndex: Integer);
|
||||
procedure AddComponent(const NewRegisteredComponent: TRegisteredComponent;
|
||||
@ -1418,96 +1418,84 @@ begin
|
||||
end;
|
||||
|
||||
procedure TDesigner.ExecuteUndoItem(IsActUndo: boolean);
|
||||
var
|
||||
AValue: Variant;
|
||||
ValueStr, tmpFieldN: string;
|
||||
tmpObj: TComponent;
|
||||
|
||||
procedure SetPropVal(AVal: variant);
|
||||
procedure SetPublished; // published field
|
||||
var
|
||||
tmpStr, tmpFieldN, str: string;
|
||||
tmpCompN: TComponentName;
|
||||
tmpObj: TObject;
|
||||
tmpInt: integer;
|
||||
aPropType: PTypeInfo;
|
||||
s: string;
|
||||
i: integer;
|
||||
begin
|
||||
tmpCompN := FUndoList[FUndoCurr].compName;
|
||||
tmpFieldN := FUndoList[FUndoCurr].fieldName;
|
||||
if tmpFieldN = 'Name' then
|
||||
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
|
||||
aPropType:=FUndoList[FUndoCurr].propInfo^.propType;
|
||||
case aPropType^.Kind of
|
||||
tkInteger, tkInt64:
|
||||
begin
|
||||
// special case: TComponent.Left,Top
|
||||
if CompareText(tmpFieldN,'Left')=0 then
|
||||
SetDesignInfoLeft(TComponent(tmpObj),StrToInt(tmpStr))
|
||||
else if CompareText(tmpFieldN,'Top')=0 then
|
||||
SetDesignInfoTop(TComponent(tmpObj),StrToInt(tmpStr));
|
||||
if (aPropType^.Name = 'TColor') or
|
||||
(aPropType^.Name = 'TGraphicsColor') then
|
||||
SetOrdProp(tmpObj, tmpFieldN, StringToColor(ValueStr))
|
||||
else if aPropType^.Name = 'TCursor' then
|
||||
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;
|
||||
PropertyEditorHook.Modified(tmpObj);
|
||||
end;
|
||||
|
||||
var
|
||||
CurTextCompStream: TMemoryStream;
|
||||
SaveControlSelection: TControlSelection;
|
||||
CompN: TComponentName;
|
||||
begin
|
||||
if (IsActUndo and (FUndoList[FUndoCurr].opType in [uopAdd])) or
|
||||
(not IsActUndo and (FUndoList[FUndoCurr].opType in [uopDelete])) then
|
||||
// Undo Add component
|
||||
if (IsActUndo and (FUndoList[FUndoCurr].opType = uopAdd)) or
|
||||
(not IsActUndo and (FUndoList[FUndoCurr].opType = uopDelete)) then
|
||||
begin
|
||||
Selection.BeginUpdate;
|
||||
try
|
||||
@ -1527,8 +1515,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
if (IsActUndo and (FUndoList[FUndoCurr].opType in [uopDelete])) or
|
||||
(not IsActUndo and (FUndoList[FUndoCurr].opType in [uopAdd])) then
|
||||
// Undo Delete component
|
||||
if (IsActUndo and (FUndoList[FUndoCurr].opType = uopDelete)) or
|
||||
(not IsActUndo and (FUndoList[FUndoCurr].opType = uopAdd)) then
|
||||
begin
|
||||
CurTextCompStream := TMemoryStream.Create;
|
||||
try
|
||||
@ -1543,14 +1532,42 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Undo Change properties of component
|
||||
if FUndoList[FUndoCurr].opType = uopChange then
|
||||
begin
|
||||
Inc(FUndoLock);
|
||||
try
|
||||
if IsActUndo then
|
||||
SetPropVal(FUndoList[FUndoCurr].oldVal)
|
||||
tmpFieldN := FUndoList[FUndoCurr].fieldName;
|
||||
if tmpFieldN = 'Name' then
|
||||
begin
|
||||
if IsActUndo then
|
||||
CompN := FUndoList[FUndoCurr].newVal
|
||||
else
|
||||
CompN := FUndoList[FUndoCurr].oldVal;
|
||||
end
|
||||
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
|
||||
Dec(FUndoLock);
|
||||
end;
|
||||
@ -1785,8 +1802,8 @@ begin
|
||||
end;
|
||||
|
||||
function TDesigner.AddUndoAction(const aPersistent: TPersistent;
|
||||
aOpType: TUndoOpType; StartNewGroup: boolean; aFieldName: string; const aOldVal,
|
||||
aNewVal: variant): boolean;
|
||||
aOpType: TUndoOpType; StartNewGroup: boolean; aFieldName: string;
|
||||
const aOldVal, aNewVal: Variant): boolean;
|
||||
|
||||
procedure ShiftUndoList;
|
||||
var
|
||||
@ -1861,8 +1878,9 @@ begin
|
||||
if aPersistent is TComponent then begin
|
||||
Comp := TComponent(aPersistent);
|
||||
compName := Comp.Name;
|
||||
if Comp.Owner <> LookupRoot then // This is a subcomponent.
|
||||
compName := Comp.Owner.Name + '.' + compName; // Add owner to the name.
|
||||
// Add owner to the name of a subcomponent.
|
||||
if Assigned(Comp.Owner) and (Comp.Owner <> LookupRoot) then
|
||||
compName := Comp.Owner.Name + '.' + compName;
|
||||
if Comp.HasParent then
|
||||
parentName := Comp.GetParentComponent.Name;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user