Merged revision(s) 61996 #5ff78d5320, 62001 #6362b3d71a from trunk:

Designer: Support Undo-action for changed Parent of a component. Issue .
........
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:
maxim 2019-10-18 21:59:34 +00:00
parent be966557d4
commit 4455557d6e
3 changed files with 140 additions and 98 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;