IDE: method property editor: edit: ask whether jump to inherited or add override

git-svn-id: trunk@55206 -
This commit is contained in:
mattias 2017-06-04 09:21:06 +00:00
parent 4975382c55
commit b29915c159
5 changed files with 193 additions and 57 deletions

View File

@ -400,7 +400,7 @@ type
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
function ApplyClassCompletion(AddMissingProcBodies: boolean): boolean; function ApplyClassCompletion(AddMissingProcBodies: boolean): boolean;
function ProcExistsInCodeCompleteClass( function ProcExistsInCodeCompleteClass(
const NameAndParamsUpCase: string): boolean; const NameAndParamsUpCase: string; SearchInAncestors: boolean = true): boolean;
function VarExistsInCodeCompleteClass(const UpperName: string): boolean; function VarExistsInCodeCompleteClass(const UpperName: string): boolean;
procedure AddClassInsertion( procedure AddClassInsertion(
const CleanDef, Def, IdentifierName: string; const CleanDef, Def, IdentifierName: string;
@ -474,7 +474,7 @@ end;
{ TCodeCompletionCodeTool } { TCodeCompletionCodeTool }
function TCodeCompletionCodeTool.ProcExistsInCodeCompleteClass( function TCodeCompletionCodeTool.ProcExistsInCodeCompleteClass(
const NameAndParamsUpCase: string): boolean; const NameAndParamsUpCase: string; SearchInAncestors: boolean): boolean;
// NameAndParams should be uppercase and contains the proc name and the // NameAndParams should be uppercase and contains the proc name and the
// parameter list without names and default values // parameter list without names and default values
// and should not contain any comments and no result type // and should not contain any comments and no result type
@ -495,7 +495,7 @@ begin
end; end;
// search in current class // search in current class
Result:=(FindProcNode(FCompletingFirstEntryNode,NameAndParamsUpCase,mgMethod,[phpInUpperCase])<>nil); Result:=(FindProcNode(FCompletingFirstEntryNode,NameAndParamsUpCase,mgMethod,[phpInUpperCase])<>nil);
if not Result then if (not Result) and SearchInAncestors then
begin begin
//search in ancestor classes //search in ancestor classes
Params:=TFindDeclarationParams.Create; Params:=TFindDeclarationParams.Create;

View File

@ -855,7 +855,7 @@ type
NewMethodName: string; ATypeInfo: PTypeInfo; NewMethodName: string; ATypeInfo: PTypeInfo;
UseTypeInfoForParameters: boolean = false; UseTypeInfoForParameters: boolean = false;
const APropertyUnitName: string = ''; const APropertyPath: string = ''; const APropertyUnitName: string = ''; const APropertyPath: string = '';
const CallAncestorMethod: string = '' const CallAncestorMethod: string = ''; AddOverride: boolean = false
): boolean; ): boolean;
// private class parts // private class parts
@ -3856,9 +3856,9 @@ end;
function TCodeToolManager.CreatePublishedMethod(Code: TCodeBuffer; function TCodeToolManager.CreatePublishedMethod(Code: TCodeBuffer;
const AClassName, NewMethodName: string; ATypeInfo: PTypeInfo; const AClassName, NewMethodName: string; ATypeInfo: PTypeInfo;
UseTypeInfoForParameters: boolean; UseTypeInfoForParameters: boolean; const APropertyUnitName: string;
const APropertyUnitName: string; const APropertyPath: string; const APropertyPath: string; const CallAncestorMethod: string;
const CallAncestorMethod: string): boolean; AddOverride: boolean): boolean;
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.CreatePublishedMethod A'); DebugLn('TCodeToolManager.CreatePublishedMethod A');
@ -3870,7 +3870,7 @@ begin
Result:=FCurCodeTool.CreateMethod(AClassName, Result:=FCurCodeTool.CreateMethod(AClassName,
NewMethodName,ATypeInfo,APropertyUnitName,APropertyPath, NewMethodName,ATypeInfo,APropertyUnitName,APropertyPath,
SourceChangeCache,UseTypeInfoForParameters,pcsPublished, SourceChangeCache,UseTypeInfoForParameters,pcsPublished,
CallAncestorMethod); CallAncestorMethod,AddOverride);
except except
on e: Exception do Result:=HandleException(e); on e: Exception do Result:=HandleException(e);
end; end;

View File

@ -103,14 +103,16 @@ type
SourceChangeCache: TSourceChangeCache; SourceChangeCache: TSourceChangeCache;
UseTypeInfoForParameters: boolean = false; UseTypeInfoForParameters: boolean = false;
Section: TPascalClassSection = pcsPublished; Section: TPascalClassSection = pcsPublished;
const CallAncestorMethod: string = ''): boolean; const CallAncestorMethod: string = '';
AddOverride: boolean = false): boolean;
function CreateMethod(ClassNode: TCodeTreeNode; function CreateMethod(ClassNode: TCodeTreeNode;
const AMethodName: string; const AMethodName: string;
ATypeInfo: PTypeInfo; const APropertyUnitName, APropertyPath: string; ATypeInfo: PTypeInfo; const APropertyUnitName, APropertyPath: string;
SourceChangeCache: TSourceChangeCache; SourceChangeCache: TSourceChangeCache;
UseTypeInfoForParameters: boolean = false; UseTypeInfoForParameters: boolean = false;
Section: TPascalClassSection = pcsPublished; Section: TPascalClassSection = pcsPublished;
const CallAncestorMethod: string = ''): boolean; const CallAncestorMethod: string = '';
AddOverride: boolean = false): boolean;
function FindClassOfInstance(Instance: TObject; function FindClassOfInstance(Instance: TObject;
out FindContext: TFindContext; ExceptionOnNotFound: boolean): boolean; out FindContext: TFindContext; ExceptionOnNotFound: boolean): boolean;
@ -725,9 +727,9 @@ begin
exit; exit;
end; end;
SrcClassName:=SrcTool.ExtractClassName(ClassNode,true); SrcClassName:=SrcTool.ExtractClassName(ClassNode,true);
ANode:=SrcTool.FindMethodNodeInImplementation(SrcClassName,AMethodName,false); ANode:=SrcTool.FindMethodNodeInImplementation(SrcClassName,AMethodName,true);
if ANode=nil then begin if ANode=nil then begin
DebugLn(['TEventsCodeTool.JumpToPublishedMethodBody method not found ',SrcClassName,'.',AMethodName,' in ',SrcTool.MainFilename]); DebugLn(['TEventsCodeTool.JumpToPublishedMethodBody method body not found ',SrcClassName,'.',AMethodName,' in ',SrcTool.MainFilename]);
if ErrorOnNotFound then if ErrorOnNotFound then
RaiseExceptionFmt(20170421202044,'implementation of method "%s.%s" in %s', [AClassName,AMethodName,SrcTool.MainFilename]); RaiseExceptionFmt(20170421202044,'implementation of method "%s.%s" in %s', [AClassName,AMethodName,SrcTool.MainFilename]);
exit; exit;
@ -824,13 +826,11 @@ begin
Result:=SourceChangeCache.Apply; Result:=SourceChangeCache.Apply;
end; end;
function TEventsCodeTool.CreateMethod(const AClassName, function TEventsCodeTool.CreateMethod(const AClassName, AMethodName: string;
AMethodName: string; ATypeInfo: PTypeInfo; ATypeInfo: PTypeInfo; const APropertyUnitName, APropertyPath: string;
const APropertyUnitName, APropertyPath: string; SourceChangeCache: TSourceChangeCache; UseTypeInfoForParameters: boolean;
SourceChangeCache: TSourceChangeCache; Section: TPascalClassSection; const CallAncestorMethod: string;
UseTypeInfoForParameters: boolean; AddOverride: boolean): boolean;
Section: TPascalClassSection;
const CallAncestorMethod: string): boolean;
var AClassNode: TCodeTreeNode; var AClassNode: TCodeTreeNode;
begin begin
Result:=false; Result:=false;
@ -839,15 +839,14 @@ begin
Result:=CreateMethod(AClassNode,AMethodName,ATypeInfo, Result:=CreateMethod(AClassNode,AMethodName,ATypeInfo,
APropertyUnitName,APropertyPath, APropertyUnitName,APropertyPath,
SourceChangeCache,UseTypeInfoForParameters,Section, SourceChangeCache,UseTypeInfoForParameters,Section,
CallAncestorMethod); CallAncestorMethod,AddOverride);
end; end;
function TEventsCodeTool.CreateMethod(ClassNode: TCodeTreeNode; function TEventsCodeTool.CreateMethod(ClassNode: TCodeTreeNode;
const AMethodName: string; ATypeInfo: PTypeInfo; const AMethodName: string; ATypeInfo: PTypeInfo; const APropertyUnitName,
const APropertyUnitName, APropertyPath: string; APropertyPath: string; SourceChangeCache: TSourceChangeCache;
SourceChangeCache: TSourceChangeCache; UseTypeInfoForParameters: boolean; UseTypeInfoForParameters: boolean; Section: TPascalClassSection;
Section: TPascalClassSection; const CallAncestorMethod: string; AddOverride: boolean): boolean;
const CallAncestorMethod: string): boolean;
procedure AddNeededUnits(const AFindContext: TFindContext); procedure AddNeededUnits(const AFindContext: TFindContext);
var var
@ -933,8 +932,15 @@ begin
try try
if (ClassNode=nil) or (not (ClassNode.Desc in [ctnClass,ctnObjCClass])) or (AMethodName='') if (ClassNode=nil) or (not (ClassNode.Desc in [ctnClass,ctnObjCClass])) or (AMethodName='')
or (ATypeInfo=nil) or (SourceChangeCache=nil) or (Scanner=nil) then exit; or (ATypeInfo=nil) or (SourceChangeCache=nil) or (Scanner=nil) then exit;
{$IFDEF CTDEBUG} if CallAncestorMethod<>'' then
DebugLn(['[TEventsCodeTool.CreateMethod] A AMethodName="',AMethodName,'" in "',MainFilename,'" UseTypeInfoForParameters=',UseTypeInfoForParameters]); AddOverride:=true;
{$IFDEF VerboseMethodPropEdit}
DebugLn(['[TEventsCodeTool.CreateMethod] A AMethodName="',AMethodName,'" in "',MainFilename,'"',
' APropertyUnitName="',APropertyUnitName,'"',
' APropertyPath="',APropertyPath,'"',
' UseTypeInfoForParameters=',UseTypeInfoForParameters,
' CallAncestorMethod="',CallAncestorMethod,'"',
' AddOverride=',AddOverride]);
{$ENDIF} {$ENDIF}
// initialize class for code completion // initialize class for code completion
CodeCompleteClassNode:=ClassNode; CodeCompleteClassNode:=ClassNode;
@ -955,8 +961,8 @@ begin
+FindContext.Tool.ExtractProcHead(FindContext.Node, +FindContext.Tool.ExtractProcHead(FindContext.Node,
[phpWithoutClassName, phpWithoutName, phpInUpperCase]); [phpWithoutClassName, phpWithoutName, phpInUpperCase]);
end; end;
if not ProcExistsInCodeCompleteClass(CleanMethodDefinition) then begin if not ProcExistsInCodeCompleteClass(CleanMethodDefinition,not AddOverride) then begin
{$IFDEF CTDEBUG} {$IFDEF VerboseMethodPropEdit}
DebugLn('[TEventsCodeTool.CreateMethod] insert method definition to class'); DebugLn('[TEventsCodeTool.CreateMethod] insert method definition to class');
{$ENDIF} {$ENDIF}
// insert method definition into class // insert method definition into class
@ -989,7 +995,7 @@ begin
phpWithoutParamTypes])); phpWithoutParamTypes]));
end; end;
end; end;
{$IFDEF CTDEBUG} {$IFDEF VerboseMethodPropEdit}
DebugLn('[TEventsCodeTool.CreateMethod] MethodDefinition="',MethodDefinition,'"'); DebugLn('[TEventsCodeTool.CreateMethod] MethodDefinition="',MethodDefinition,'"');
{$ENDIF} {$ENDIF}
if Section in [pcsPublished,pcsPublic] then if Section in [pcsPublished,pcsPublic] then
@ -1016,7 +1022,7 @@ begin
AddClassInsertion(CleanMethodDefinition, MethodDefinition, AMethodName, AddClassInsertion(CleanMethodDefinition, MethodDefinition, AMethodName,
NewSection,nil,ProcBody); NewSection,nil,ProcBody);
end; end;
{$IFDEF CTDEBUG} {$IFDEF VerboseMethodPropEdit}
DebugLn('[TEventsCodeTool.CreateMethod] invoke class completion'); DebugLn('[TEventsCodeTool.CreateMethod] invoke class completion');
{$ENDIF} {$ENDIF}
if not InsertAllNewClassParts then if not InsertAllNewClassParts then
@ -1029,7 +1035,7 @@ begin
// apply the changes // apply the changes
if not SourceChangeCache.Apply then if not SourceChangeCache.Apply then
RaiseException(20170421202122,ctsUnableToApplyChanges); RaiseException(20170421202122,ctsUnableToApplyChanges);
{$IFDEF CTDEBUG} {$IFDEF VerboseMethodPropEdit}
DebugLn('[TEventsCodeTool.CreateMethod] END'); DebugLn('[TEventsCodeTool.CreateMethod] END');
{$ENDIF} {$ENDIF}
Result:=true; Result:=true;

View File

@ -1261,6 +1261,7 @@ type
TPropHookRenameMethod = procedure(const CurName, NewName: String) of object; TPropHookRenameMethod = procedure(const CurName, NewName: String) of object;
TPropHookShowMethod = procedure(const Name: String) of object; TPropHookShowMethod = procedure(const Name: String) of object;
TPropHookMethodFromAncestor = function(const Method:TMethod):boolean of object; TPropHookMethodFromAncestor = function(const Method:TMethod):boolean of object;
TPropHookMethodFromLookupRoot = function(const Method:TMethod):boolean of object;
TPropHookChainCall = procedure(const AMethodName, InstanceName, TPropHookChainCall = procedure(const AMethodName, InstanceName,
InstanceMethod:ShortString; TypeData:PTypeData) of object; InstanceMethod:ShortString; TypeData:PTypeData) of object;
// components // components
@ -1319,6 +1320,7 @@ type
htRenameMethod, htRenameMethod,
htShowMethod, htShowMethod,
htMethodFromAncestor, htMethodFromAncestor,
htMethodFromLookupRoot,
htChainCall, htChainCall,
// components // components
htGetComponent, htGetComponent,
@ -1392,6 +1394,7 @@ type
procedure RenameMethod(const CurName, NewName: String); procedure RenameMethod(const CurName, NewName: String);
procedure ShowMethod(const aName: String); procedure ShowMethod(const aName: String);
function MethodFromAncestor(const Method: TMethod): boolean; function MethodFromAncestor(const Method: TMethod): boolean;
function MethodFromLookupRoot(const Method: TMethod): boolean;
procedure ChainCall(const AMethodName, InstanceName, procedure ChainCall(const AMethodName, InstanceName,
InstanceMethod: ShortString; TypeData: PTypeData); InstanceMethod: ShortString; TypeData: PTypeData);
// components // components
@ -1470,6 +1473,10 @@ type
const OnMethodFromAncestor: TPropHookMethodFromAncestor); const OnMethodFromAncestor: TPropHookMethodFromAncestor);
procedure RemoveHandlerMethodFromAncestor( procedure RemoveHandlerMethodFromAncestor(
const OnMethodFromAncestor: TPropHookMethodFromAncestor); const OnMethodFromAncestor: TPropHookMethodFromAncestor);
procedure AddHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
procedure RemoveHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
procedure AddHandlerChainCall(const OnChainCall: TPropHookChainCall); procedure AddHandlerChainCall(const OnChainCall: TPropHookChainCall);
procedure RemoveHandlerChainCall(const OnChainCall: TPropHookChainCall); procedure RemoveHandlerChainCall(const OnChainCall: TPropHookChainCall);
// component event // component event
@ -4592,25 +4599,54 @@ var
begin begin
NewMethodName := GetValue; NewMethodName := GetValue;
{$IFDEF VerboseMethodPropEdit} {$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit OldValue="',NewMethodName,'"']); debugln(['TMethodPropertyEditor.Edit OldValue="',NewMethodName,'" FromLookupRoot=',(LazIsValidIdent(NewMethodName, True, True) and PropertyHook.MethodFromLookupRoot(GetMethodValue))]);
DumpStack; DumpStack;
{$ENDIF} {$ENDIF}
if not LazIsValidIdent(NewMethodName, True, True) if IsValidIdent(NewMethodName)
or PropertyHook.MethodFromAncestor(GetMethodValue) then and PropertyHook.MethodFromLookupRoot(GetMethodValue) then
begin begin
// the current method is from the ancestor
// -> add an override with the default name
NewMethodName := GetFormMethodName;
{$IFDEF VerboseMethodPropEdit} {$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit NewValue="',NewMethodName,'"']); debugln(['TMethodPropertyEditor.Edit Show']);
{$ENDIF} {$ENDIF}
if not IsValidIdent(NewMethodName) then
raise EPropertyError.Create('Method name "'+NewMethodName+'" must be an identifier');
SetValue(NewMethodName); // this will jump to the method
PropertyHook.RefreshPropertyValues;
end
else
PropertyHook.ShowMethod(NewMethodName); PropertyHook.ShowMethod(NewMethodName);
end else begin
// the current method is from the another class (e.g. ancestor or frame)
case QuestionDlg('Override or jump',
'The event "'+GetName+'" currently points to an inherited method.',
mtConfirmation,[mrYes,'Create Override',mrOk,'Jump to inherited method',mrCancel],
0) of
mrYes:
begin
// -> add an override with the default name
NewMethodName := GetFormMethodName;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit NewValue="',NewMethodName,'"']);
{$ENDIF}
if not IsValidIdent(NewMethodName) then
raise EPropertyError.Create('Method name "'+NewMethodName+'" must be an identifier');
NewMethodName:=PropertyHook.LookupRoot.ClassName+'.'+NewMethodName;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit CreateMethod "',NewMethodName,'"...']);
{$ENDIF}
SetMethodValue(
PropertyHook.CreateMethod(NewMethodName, GetPropType,
GetComponent(0), GetPropertyPath(0)));
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit CHANGED new method=',GetValue]);
{$ENDIF}
PropertyHook.RefreshPropertyValues;
ShowValue;
end;
mrOk:
begin
// -> jump to ancestor method
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit Jump to ancestor method ',NewMethodName]);
{$ENDIF}
PropertyHook.ShowMethod(NewMethodName);
end;
end;
end;
end; end;
procedure TMethodPropertyEditor.ShowValue; procedure TMethodPropertyEditor.ShowValue;
@ -6029,7 +6065,7 @@ var
begin begin
Result.Code := nil; Result.Code := nil;
Result.Data := nil; Result.Data := nil;
if IsValidIdent(aName) and Assigned(ATypeInfo) then if LazIsValidIdent(aName,true,true) and Assigned(ATypeInfo) then
begin begin
i := GetHandlerCount(htCreateMethod); i := GetHandlerCount(htCreateMethod);
while GetNextHandlerIndex(htCreateMethod, i) do while GetNextHandlerIndex(htCreateMethod, i) do
@ -6181,6 +6217,29 @@ begin
end; end;
end; end;
function TPropertyEditorHook.MethodFromLookupRoot(const Method: TMethod
): boolean;
var
Root: TPersistent;
i: Integer;
Handler: TPropHookMethodFromLookupRoot;
begin
// check if given Method is in LookupRoot source,
Root:=LookupRoot;
if Root=nil then exit(false);
i := GetHandlerCount(htMethodFromLookupRoot);
if GetNextHandlerIndex(htMethodFromLookupRoot, i) then
begin
Handler := TPropHookMethodFromLookupRoot(FHandlers[htMethodFromLookupRoot][i]);
Result := Handler(Method);
end
else
begin
Result := (TObject(Method.Data)=Root) and Assigned(Method.Code)
and (Root.MethodName(Method.Code)<>'');
end;
end;
procedure TPropertyEditorHook.ChainCall(const AMethodName, InstanceName, procedure TPropertyEditorHook.ChainCall(const AMethodName, InstanceName,
InstanceMethod: ShortString; TypeData: PTypeData); InstanceMethod: ShortString; TypeData: PTypeData);
var var
@ -6784,6 +6843,18 @@ begin
RemoveHandler(htMethodFromAncestor,TMethod(OnMethodFromAncestor)); RemoveHandler(htMethodFromAncestor,TMethod(OnMethodFromAncestor));
end; end;
procedure TPropertyEditorHook.AddHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
begin
AddHandler(htMethodFromLookupRoot,TMethod(OnMethodFromLookupRoot));
end;
procedure TPropertyEditorHook.RemoveHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
begin
RemoveHandler(htMethodFromLookupRoot,TMethod(OnMethodFromLookupRoot));
end;
procedure TPropertyEditorHook.AddHandlerChainCall( procedure TPropertyEditorHook.AddHandlerChainCall(
const OnChainCall: TPropHookChainCall); const OnChainCall: TPropHookChainCall);
begin begin

View File

@ -525,6 +525,8 @@ type
APersistent: TPersistent; APersistent: TPersistent;
const APropertyPath: string): TMethod; const APropertyPath: string): TMethod;
procedure PropHookShowMethod(const AMethodName: String); procedure PropHookShowMethod(const AMethodName: String);
function PropHookMethodFromAncestor(const Method: TMethod): boolean;
function PropHookMethodFromLookupRoot(const Method: TMethod): boolean;
procedure PropHookRenameMethod(const CurName, NewName: String); procedure PropHookRenameMethod(const CurName, NewName: String);
function PropHookBeforeAddPersistent(Sender: TObject; function PropHookBeforeAddPersistent(Sender: TObject;
APersistentClass: TPersistentClass; APersistentClass: TPersistentClass;
@ -2086,6 +2088,8 @@ begin
GlobalDesignHook.AddHandlerMethodExists(@PropHookMethodExists); GlobalDesignHook.AddHandlerMethodExists(@PropHookMethodExists);
GlobalDesignHook.AddHandlerCreateMethod(@PropHookCreateMethod); GlobalDesignHook.AddHandlerCreateMethod(@PropHookCreateMethod);
GlobalDesignHook.AddHandlerShowMethod(@PropHookShowMethod); GlobalDesignHook.AddHandlerShowMethod(@PropHookShowMethod);
GlobalDesignHook.AddHandlerMethodFromAncestor(@PropHookMethodFromAncestor);
GlobalDesignHook.AddHandlerMethodFromLookupRoot(@PropHookMethodFromLookupRoot);
GlobalDesignHook.AddHandlerRenameMethod(@PropHookRenameMethod); GlobalDesignHook.AddHandlerRenameMethod(@PropHookRenameMethod);
GlobalDesignHook.AddHandlerBeforeAddPersistent(@PropHookBeforeAddPersistent); GlobalDesignHook.AddHandlerBeforeAddPersistent(@PropHookBeforeAddPersistent);
GlobalDesignHook.AddHandlerComponentRenamed(@PropHookComponentRenamed); GlobalDesignHook.AddHandlerComponentRenamed(@PropHookComponentRenamed);
@ -12503,7 +12507,11 @@ end;
function TMainIDE.PropHookCreateMethod(const AMethodName: ShortString; function TMainIDE.PropHookCreateMethod(const AMethodName: ShortString;
ATypeInfo: PTypeInfo; ATypeInfo: PTypeInfo;
APersistent: TPersistent; const APropertyPath: string): TMethod; APersistent: TPersistent; const APropertyPath: string): TMethod;
{ APersistent is the instance that gets the new method, not the lookuproot. { AMethodName is the name of the published method in the LookupRoot (class or ancestors)
It can take the explicit form LookupRootClassName.MethodName to create an
override for an ancestor method.
APersistent is the instance that gets the new method, not the lookuproot.
For example assign 'Button1Click' to Form1.Button1.OnClick: For example assign 'Button1Click' to Form1.Button1.OnClick:
APersistent = APersistent APersistent = APersistent
AMethodName = 'Button1Click' AMethodName = 'Button1Click'
@ -12616,8 +12624,8 @@ var
var var
r: boolean; r: boolean;
OldChange: Boolean; OldChange: Boolean;
InheritedMethodPath: String; InheritedMethodPath, MethodClassName, ShortMethodName: String;
UseRTTIForMethods: Boolean; UseRTTIForMethods, AddOverride: Boolean;
begin begin
Result.Code:=nil; Result.Code:=nil;
Result.Data:=nil; Result.Data:=nil;
@ -12635,28 +12643,45 @@ begin
{$ENDIF} {$ENDIF}
end; end;
if IsValidIdentPair(AMethodName,MethodClassName,ShortMethodName) then
begin
if CompareText(MethodClassName,ActiveUnitInfo.Component.ClassName)<>0 then
begin
debugln(['TMainIDE.PropHookCreateMethod wrong class AMethodName="',AMethodName,'" lookuproot=',DbgSName(ActiveUnitInfo.Component)]);
raise Exception.Create('Invalid classname "'+AMethodName+'"');
end;
AddOverride:=true;
end else begin
MethodClassName:='';
ShortMethodName:=AMethodName;
AddOverride:=false;
end;
InheritedMethodPath:=GetInheritedMethodPath; InheritedMethodPath:=GetInheritedMethodPath;
OldChange:=OpenEditorsOnCodeToolChange; OldChange:=OpenEditorsOnCodeToolChange;
OpenEditorsOnCodeToolChange:=true; OpenEditorsOnCodeToolChange:=true;
UseRTTIForMethods:=FormEditor1.ComponentUsesRTTIForMethods(ActiveUnitInfo.Component); UseRTTIForMethods:=FormEditor1.ComponentUsesRTTIForMethods(ActiveUnitInfo.Component);
try try
// create published method // create published method in active unit
{$IFDEF VerboseOnPropHookCreateMethod} {$IFDEF VerboseOnPropHookCreateMethod}
debugln(['TMainIDE.OnPropHookCreateMethod CreatePublishedMethod ',ActiveUnitInfo.Source.Filename,' LookupRoot=',ActiveUnitInfo.Component.ClassName,' AMethodName="',AMethodName,'" PropertyUnit=',GetClassUnitName(APersistent.ClassType),' APropertyPath="',APropertyPath,'" CallInherited=',InheritedMethodPath]); debugln(['TMainIDE.OnPropHookCreateMethod CreatePublishedMethod ',ActiveUnitInfo.Source.Filename,' LookupRoot=',ActiveUnitInfo.Component.ClassName,' ShortMethodName="',ShortMethodName,'" PropertyUnit=',GetClassUnitName(APersistent.ClassType),' APropertyPath="',APropertyPath,'" CallInherited=',InheritedMethodPath]);
{$ENDIF} {$ENDIF}
r:=CodeToolBoss.CreatePublishedMethod(ActiveUnitInfo.Source, r:=CodeToolBoss.CreatePublishedMethod(ActiveUnitInfo.Source,
ActiveUnitInfo.Component.ClassName,AMethodName, ActiveUnitInfo.Component.ClassName,ShortMethodName,
ATypeInfo,UseRTTIForMethods,GetClassUnitName(APersistent.ClassType),APropertyPath, ATypeInfo,UseRTTIForMethods,GetClassUnitName(APersistent.ClassType),
InheritedMethodPath); APropertyPath,InheritedMethodPath,AddOverride);
{$IFDEF VerboseOnPropHookCreateMethod} {$IFDEF VerboseOnPropHookCreateMethod}
debugln(['[TMainIDE.OnPropHookCreateMethod] ************ ',dbgs(r),' AMethodName="',AMethodName,'"']); debugln(['[TMainIDE.OnPropHookCreateMethod] ************ ',dbgs(r),' ShortMethodName="',ShortMethodName,'"']);
{$ENDIF} {$ENDIF}
ApplyCodeToolChanges; ApplyCodeToolChanges;
if r then begin if r then begin
Result:=FormEditor1.CreateNewJITMethod(ActiveUnitInfo.Component, Result:=FormEditor1.CreateNewJITMethod(ActiveUnitInfo.Component,
AMethodName); ShortMethodName);
{$IFDEF VerboseOnPropHookCreateMethod}
debugln(['TMainIDE.PropHookCreateMethod JITClass=',TJITMethod(Result.Data).TheClass.ClassName]);
{$ENDIF}
end else begin end else begin
DebugLn(['Error: (lazarus) TMainIDE.OnPropHookCreateMethod failed adding method "'+AMethodName+'" to source']); DebugLn(['Error: (lazarus) TMainIDE.OnPropHookCreateMethod failed adding method "'+ShortMethodName+'" to source']);
DoJumpToCodeToolBossError; DoJumpToCodeToolBossError;
raise Exception.Create(lisUnableToCreateNewMethod+' '+lisPleaseFixTheErrorInTheMessageWindow); raise Exception.Create(lisUnableToCreateNewMethod+' '+lisPleaseFixTheErrorInTheMessageWindow);
end; end;
@ -12713,6 +12738,40 @@ begin
end; end;
end; end;
function TMainIDE.PropHookMethodFromAncestor(const Method: TMethod): boolean;
var
AncestorClass: TClass;
JITMethod: TJITMethod;
begin
Result:=false;
if Method.Code<>nil then begin
if Method.Data<>nil then begin
AncestorClass := TObject(Method.Data).ClassParent;
Result := Assigned(AncestorClass) and (AncestorClass.MethodName(Method.Code)<>'');
end;
end
else if IsJITMethod(Method) then begin
JITMethod:=TJITMethod(Method.Data);
Result:=(GlobalDesignHook.LookupRoot<>nil) and
GlobalDesignHook.LookupRoot.InheritsFrom(JITMethod.TheClass);
end;
end;
function TMainIDE.PropHookMethodFromLookupRoot(const Method: TMethod): boolean;
var
Root: TPersistent;
JITMethod: TJITMethod;
begin
Root:=GlobalDesignHook.LookupRoot;
if Root=nil then exit(false);
if TObject(Method.Data)=Root then begin
Result:=(Method.Code<>nil) and (Root.MethodName(Method.Code)<>'');
end else if IsJITMethod(Method) then begin
JITMethod:=TJITMethod(Method.Data);
Result:=Root.ClassType=JITMethod.TheClass;
end;
end;
procedure TMainIDE.PropHookRenameMethod(const CurName, NewName: String); procedure TMainIDE.PropHookRenameMethod(const CurName, NewName: String);
var var
ActiveSrcEdit: TSourceEditor; ActiveSrcEdit: TSourceEditor;