pascalscript/Source/uPSComponentExt.pas
carlokok afe3fdfd77 re-checkin
git-svn-id: http://code.remobjects.com/svn/pascalscript@1 5c9d2617-0215-0410-a2ee-e80e04d1c6d8
2006-05-30 14:23:25 +00:00

950 lines
28 KiB
ObjectPascal

{
@abstract(Component wrapper for IFPS3 compiler and executer)
A component wrapper for IFPS3, including debugging support.
}
unit uPSComponentExt;
interface
uses
{$IFNDEF LINUX} Windows, {$ENDIF} SysUtils, Classes, uPSRuntime, uPSDebugger, uPSUtils, uPSComponent,
contnrs, uPSCompiler, uPSC_dll, uPSR_dll, uPSPreProcessor, typInfo;
const
{alias to @link(ifps3.cdRegister)}
cdRegister = uPSRuntime.cdRegister;
{alias to @link(ifps3.cdPascal)}
cdPascal = uPSRuntime.cdPascal;
{ alias to ifps3.cdCdecl }
CdCdecl = uPSRuntime.CdCdecl;
{alias to @link(ifps3.cdStdcall)}
CdStdCall = uPSRuntime.CdStdCall;
type
{Alias to @link(ifps3.TPSCallingConvention)}
TDelphiCallingConvention = uPSRuntime.TPSCallingConvention;
{Alias to @link(ifps3.TPSRuntimeClassImporter)}
TPSRuntimeClassImporter = uPSRuntime.TPSRuntimeClassImporter;
TPSScriptExtension = class;
{Base class for all plugins for the component}
TPSOnCompCleanup = Function (Sender: TObject; aComp: TPSPascalCompiler):Boolean of object;
TPSOnInsertProcedure = Procedure (Sender: TObject; aProc: String; OnTop: Boolean) of object;
TPSOnException = procedure (Sender: TPSExec; ExError: TPSError; const ExParam: string;
ExObject: TObject; ProcNo, Position: Cardinal) of object;
TMethodList = class;
TProcObj = Class
private
FName : String;
fOwner : TMethodList;
procedure SetName(const Value: String);
public
ProcType : TStringList;
Method : TMethod;
constructor create(aOwner: TMethodList);
destructor Destroy; override;
property Name: String read FName write SetName;
end;
TMethodObj = Class
Instance : TPersistent;
PropName : String;
ProcName : String;
end;
TMethodList = class
private
fOwner : TPSScriptExtension;
fProcList : TObjectList;
fEventList : TObjectList;
function GetObject(Index: Integer): TMethodObj; virtual;
function GetProcObj(Index: Integer): TProcObj;
function GetMethodName(Instance: TObject; PropName: String): String;
procedure SetMethodName(Instance: TObject; PropName: String; const Value: String);
procedure CreateProc(ProcName: string; aPropType: TTypeData);
public
constructor create(aOwner: TPSScriptExtension);
destructor Destroy; override;
function methodIndexOf(Instance: TObject; PropName: String):Integer;
Function ProcIndexOf(Name: String): Integer;
Procedure ListEventsName(EventType:string; List : TStrings);
Procedure AddProcedure(ProcName, ProcType:String);
procedure InsertMethod(NewProc: String; OnTop: Boolean = false);
Procedure FillMethods;
procedure ClearProcList;
Procedure ClearAll;
function ProcCount :Integer;
Function MethodCount :Integer;
property Procs[Index: Integer]: TProcObj read GetProcObj ;
property Methods[Index: Integer]: TMethodObj read GetObject;
property ProcName[Instance: TObject; PropName:String]: String read GetMethodName write SetMethodName;
end;
TPSScriptExtension = class(TPSScriptDebugger)
private
FOnBeforeCleanUp: TPSOnCompCleanup;
FMethodList : TMethodList;
FOnInsertMethod: TPSOnInsertProcedure;
FNeedCompiling :Boolean;
FOnScriptChance: TNotifyEvent;
FOnException: TPSOnException;
fItems, fInserts: TStrings;
fScriptPos : Cardinal;
fObjectNest: STring;
Procedure GetCodeProps ;
function GetProcName(Instance: TObject; PropName: String): string;
procedure SetProcName(Instance: TObject; PropName: String; const Value: string);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure DoVerifyProc(Sender: TPSScript; Proc: TPSInternalProcedure;
const Decl: string; var Error: Boolean); reintroduce;
Function DoBeforeCleanup(Sender: TObject; aComp: TPSPascalCompiler):Boolean;
procedure DoScriptChance(sender:TObject);
public
{Create an instance of the CompExec component}
constructor Create(AOwner: TComponent); override;
{Destroy the CompExec component}
destructor Destroy; override;
function Compile: Boolean; Override;
function Execute: Boolean; Override;
{ Create a list of all var's, const's, Type's and functions }
Procedure GetValueDefs(aItems, aInserts: TStrings; Const aObjectNest: String=''; aScriptPos: Integer = 0);
{Compile the source only when the source is modified}
procedure CompileIfNeeded;
{Is the source modified}
Property NeedCompiling : Boolean read FNeedCompiling;
{Fills all function in the script to there connected Events.
This is called automatic after a succesfull Compilition}
Procedure FillMethods;
{Removes all events from the Objects Fills all function in the script to there connected Events.
This function is automatic called before a Compilition}
procedure ClearProcList;
Procedure RemoveObjEvents(Obj: TObject);
{This property helps you set the events that must becalled from within the script
Instance is the object where the Propname must be set.
You need te create the function yopur self in the script.
When the new Procname dose not exists in the script, it is automatic created for you.}
property ProcName[Instance: TObject; PropName:String]: string read GetProcName write SetProcName;
property MethodList : TMethodList read FMethodList;
published
property OnBeforeCleanUp: TPSOnCompCleanup read FOnBeforeCleanUp write FOnBeforeCleanUp; //<NVDS>
property OnInsertMethod : TPSOnInsertProcedure read FOnInsertMethod write FOnInsertMethod;
Property OnScriptChance : TNotifyEvent read FOnScriptChance write fOnScriptChance;
property OnException : TPSOnException read FOnException write FOnException;
end;
implementation
resourcestring
sMissingEndStatment = 'Missing some ''End'' statments';
function CompExportCheck(Sender: TPSPascalCompiler; Proc: TPSInternalProcedure; const ProcDecl: string): Boolean;
begin
Result := True;
TPSScriptExtension(Sender.ID).DoVerifyProc(Sender.Id, Proc, ProcDecl, Result);
end;
Function BeforeCleanup(Sender: TPSPascalCompiler):Boolean;
begin
result := TPSScriptExtension(Sender.ID).DoBeforeCleanUp(Sender.ID,Sender);
end;
procedure CEException(Sender: TPSExec; ExError: TIFError; const ExParam: string; ExObject: TObject; ProcNo, Position: Cardinal);
begin
if @TPSScriptExtension(Sender.ID).FOnException <> nil then
TPSScriptExtension(Sender.ID).FOnException(Sender, ExError, ExParam, ExObject, ProcNo, Position);
end;
{ TPSScriptExtension }
function TPSScriptExtension.Compile: Boolean;
begin
ClearProcList;
result := inherited Compile;
if result then FillMethods;
FNeedCompiling := false;
end;
constructor TPSScriptExtension.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Comp.OnBeforeCleanup := BeforeCleanup;
Comp.OnExportCheck := CompExportCheck;
Exec.OnException := CEException;
TStringList(script).OnChange := DoScriptChance;
FMethodList := TMethodList.create(Self);
FNeedCompiling := True;
end;
destructor TPSScriptExtension.Destroy;
begin
FMethodList.Free;
inherited Destroy;
end;
procedure TPSScriptExtension.DoVerifyProc(Sender: TPSScript;
Proc: TPSInternalProcedure; const Decl: string; var Error: Boolean);
var
n{,m,p} : Integer;
tstType : TPSProceduralType;
begin
for n := 0 to sender.comp.GetTypeCount -1 do begin
If comp.GetType(n) is TPSProceduralType then begin
tstType := comp.GetType(n) as TPSProceduralType;
If tstType.ProcDef.Same(Proc.Decl) then begin
MethodList.addprocedure(Proc.OriginalName, tstType.Name);
// Proc. aExport := etExportDecl;
end;
end;
end;
if assigned(OnVerifyProc) then
begin
onVerifyProc(Sender, Proc, Decl, Error);
end;
end;
type
TMyPascalCompiler = class(TPSPascalCompiler);
const
sIFPSParameterMode : array [pmIn..pmInOut] of string = ('','\style{+B}out\style{-B} ','\style{+B}Var\style{-B} ');
Procedure TPSScriptExtension.GetCodeProps;
Function existsItem(aName:String):Boolean;
Begin
result := FInserts.indexof(aName)<> -1;
end;
Procedure addListItem(aType, aName:String; aDef:String='');
var
x : LongInt;
begin
If not ((aName ='') or (aName[1]='!')) then begin
x := FInserts.Add(aName);
fItems.Insert(x, format('%s \column{}\style{+B}%s\style{-B} %s',[aType, aName, aDef]));
end;
end;
procedure Getdecl(decl : TPSParametersDecl; var T,v :string);
var
m : Integer;
begin
v := '';
for m := 0 to Decl.ParamCount-1 do begin
v := V +';'+sIFPSParameterMode[Decl.Params[m].Mode]+
Decl.Params[m].OrgName;
if Decl.Params[m].aType <> nil then
v := v +':'+ Decl.Params[m].aType.OriginalName;
end;
delete(v,1,1);
If v <> '' then v := '('+ v +')';
if Decl.Result<>nil then begin
v := v +':'+ Decl.Result.OriginalName;
t := 'Function';
end else t := 'Procedure';
end;
Function getTypeDef(xr: TPSType; aZoek:string = ''):Boolean; forward;
Function getClassDef(xc: TPSCompileTimeClass; aZoek:string = ''):Boolean;
var
Show : Boolean;
Zoek,bZoek : String;
tci : TPSDelphiClassItem;
n : Integer;
T,v : String;
begin
Show := aZoek='';
Zoek := aZoek;
If Pos('.',aZoek)>0 then begin
Zoek := copy(aZoek, 1 ,Pos('.',aZoek)-1);
bZoek := copy(aZoek, Pos('.',aZoek)+1, 999);
end else bZoek := '';
result := (xc <> nil) and Show;
if XC<> nil then begin
For n := 0 to xc.Count-1 do begin
tci := xc.Items[n];
If (tci = nil) or existsItem(tci.OrgName) then continue;
if tci is TPSDelphiClassItemConstructor then begin
Getdecl(tci.decl, T, V);
If Show then addListItem('Constructor',tci.OrgName, v);
end else
if tci is TPSDelphiClassItemMethod then begin
If Show then begin
Getdecl(tci.decl, T, V);
addListItem(T,tci.OrgName, v)
end else
If (tci.decl.Result <> nil) and (tci.Name = Zoek) then
result := getTypeDef(tci.decl.Result, bZoek);
end else
if tci is TPSDelphiClassItemProperty then begin
If Show then begin
t := '';
If tci.Decl.Result<> nil then t := ': '+ tci.Decl.Result.OriginalName;
addListItem('Property',tci.OrgName, t);
end else
If (tci.decl.Result <> nil) and (tci.Name = Zoek) then
result := getTypeDef(tci.decl.Result, bZoek);
end;
If result and not show then exit;
end;
result := getClassDef(XC.ClassInheritsFrom, aZoek) or result;
end;
end;
Function getTypeDef(xr: TPSType; aZoek:string = ''):Boolean;
var
Show : Boolean;
Zoek : String;
xri : PIFPSRecordFieldTypeDef;
n : Integer;
begin
Show := aZoek='';
result := (xr <> nil) and Show;
if xr <> nil then begin
If xr is TPSRecordType then begin
Zoek := aZoek;
If Pos('.',aZoek)>0 then begin
Zoek := copy(aZoek, 1 ,Pos('.',aZoek)-1);
aZoek := copy(aZoek, Pos('.',aZoek)+1, 999);
end else aZoek := '';
for n := 0 to (xr as TPSRecordType).RecValCount-1 do begin
xri := (xr as TPSRecordType).RecVal(n);
If Show then begin
addListItem('Var',xri.FieldOrgName,xri.aType.OriginalName)
end else
If (xri.aType <> nil) and (xri.FieldName = Zoek) then
result := getTypeDef(xri.aType, aZoek);
end;
end else
If (xr is TPSClassType) then begin
result := getClassDef((xr as TPSClassType).Cl, aZoek)
end else
result := False;
end;
end;
Function FindVarProc(aVarName:string; aZoek : string= ''):Boolean;
var
// cv : String;
hh, h, i : Longint;
proc : TPSProcedure;
ip : TPSInternalProcedure;
ipv : PIFPSProcVar;
ipp : TPSParameterDecl;
// t : String;
begin
Hh := MakeHash(aVarName);
result := False;
If FScriptPos =0 then exit;
for i := Comp.GetProcCount -1 downto 0 do begin
Proc := Comp.GetProc(i);
If (Proc.ClassType = TPSInternalProcedure) and
((Proc as TPSInternalProcedure).DeclarePos < FScriptPos) then begin
ip := Proc as TPSInternalProcedure;
for h := 0 to ip.ProcVars.Count-1 do begin
ipv := PIFPSProcVar(ip.ProcVars[h]);
If aVarName = '' then begin
addListItem('Var',ipv.OrgName, ': '+ipv.AType.OriginalName);
end else
If (ipv.NameHash = HH) and (ipv.Name = aVarName) then begin
result := getTypeDef(ipv.aType, aZoek);
exit;
end;
end;
for h := 0 to ip.Decl.ParamCount-1 do begin
ipp := TPSParameterDecl(ip.Decl.Params[h]);
If aVarName = '' then begin
addListItem('Var',ipp.OrgName, ': '+ipp.aType.OriginalName);
end else
If {(ipp.Hash = HH) and} (ipp.Name = aVarName) then begin
result := getTypeDef(ipp.aType, aZoek);
exit;
end;
end;
end;
end;
end;
Function FindVarFunctType(aProcName:string): Boolean;
var
cv : String;
h, i : Longint;
proc : TPSProcedure;
xr : TPSRegProc;
// t : String;
begin
cv := aProcName;
If Pos('.',aProcName)>0 then begin
cv := copy(aProcName, 1 ,Pos('.',aProcName)-1);
aProcName := copy(aProcName, Pos('.',aProcName)+1, 999);
end else aProcName := '';
H := MakeHash(Cv);
// Result := False;
for i :=0 to Comp.GetVarCount -1 do begin
if (Comp.GetVar(I).NameHash = H) and (Comp.GetVar(I).Name = CV) then begin
Result := getTypeDef(Comp.GetVar(I).aType, aProcName);
Exit;
end;
end;
result := FindVarProc(cv, aProcName);
If result then exit;
for i :=0 to Comp.GetProcCount -1 do begin
Proc := Comp.GetProc(i);
If Proc.ClassType = TPSInternalProcedure then begin
if ((Proc as TPSInternalProcedure).NameHash = H) and
((Proc as TPSInternalProcedure).Name = CV) then begin
Result := getTypeDef((Proc as TPSInternalProcedure).Decl.Result, aProcName);
exit;
end;
end;
end;
with TMyPascalCompiler(Comp) do begin
for i := 0 to FRegProcs.Count-1 do begin
xr := FRegProcs[i];
if (xr.NameHash = H) and (xr.Name = CV) then begin
result := getTypeDef(xr.Decl.Result, aProcName);
exit;
end;
end;
end;
end;
Var
n : Integer;
s, t, v : String;
proc : TPSProcedure;
xr : TPSRegProc;
begin
If (fItems = nil) or (fInserts = Nil) then exit;
fItems.BeginUpdate;
fInserts.BeginUpdate;
tStringList(fInserts).Sorted := true;
tStringList(fInserts).Duplicates := dupAccept;
try
fInserts.Clear;
fItems.Clear;
If (FObjectNest <> '') then begin
FindVarFunctType(FastUpperCase(FObjectNest));
exit;
end;
for n := 0 to Comp.GetTypeCount-1 do begin
addListItem('Type',Comp.GetType(n).OriginalName);
end;
for n := 0 to Comp.GetVarCount-1 do begin
addListItem('Var',Comp.GetVar(n).OrgName, ': '+Comp.Getvar(n).aType.OriginalName);
end;
with TMyPascalCompiler(Comp) do begin
for n := 0 to FConstants.Count-1 do begin
addListItem('Const', TPSConstant(FConstants[n]).OrgName );
end;
for n := 0 to FRegProcs.Count-1 do begin
xr := FRegProcs[n];
Getdecl(xr.decl, T, v);
addListItem(t,xr.OrgName, v );
end;
end;
FindVarProc('');
for n := 0 to Comp.GetProcCount-1 do begin
s := '';
proc := Comp.GetProc(n);
If Proc.ClassType = TPSInternalProcedure then begin
s := (Proc as TPSInternalProcedure).OriginalName;
Getdecl((Proc as TPSInternalProcedure).decl, T, v);
end;
If s <> '' then begin
addListItem(t,s, v );
end;
end;
Finally
fInserts.EndUpdate;
fItems.EndUpdate;
end;
end;
procedure TPSScriptExtension.GetValueDefs(aItems, aInserts: TStrings; const aObjectNest: STring; aScriptPos: Integer);
begin
fItems := aItems;
fInserts := aInserts;
FScriptPos := aScriptPos;
fObjectNest := aObjectNest;
Try
compile;
finally
fItems := Nil;
fInserts := Nil;
FScriptPos := 0;
fObjectNest := '';
end;
end;
function TPSScriptExtension.DoBeforeCleanup(Sender: TObject;
aComp: TPSPascalCompiler): Boolean;
begin
result := true;
If fItems <> nil then GetCodeProps;
If @FOnBeforeCleanUp<> nil then
result := FOnBeforeCleanUp(Sender, aComp);
end;
function TPSScriptExtension.Execute: Boolean;
begin
CompileIfNeeded;
MethodList.FillMethods;
result := inherited Execute;
end;
procedure TPSScriptExtension.DoScriptChance(sender: TObject);
begin
FNeedCompiling := True;
self.ClearProcList;
If @FOnScriptChance <> NIL then
FOnScriptChance(sender);
end;
procedure TPSScriptExtension.CompileIfNeeded;
begin
if FNeedCompiling then begin
Compile;
end;
end;
procedure TPSScriptExtension.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
If Operation = opRemove then begin
MethodList.SetMethodName(aComponent,'','');
end;
end;
function TPSScriptExtension.GetProcName(Instance: TObject; PropName: String): string;
begin
Result := MethodList.ProcName[Instance, Propname];
end;
procedure TPSScriptExtension.SetProcName(Instance: TObject; PropName: String; const Value: string);
begin
MethodList.ProcName[Instance, Propname] := Value;
end;
procedure TPSScriptExtension.ClearProcList;
begin
MethodList.ClearProcList;
end;
procedure TPSScriptExtension.RemoveObjEvents(Obj: TObject);
begin
MethodList.SetMethodName(Obj, '', '');
end;
procedure TPSScriptExtension.FillMethods;
begin
MethodList.FillMethods;
end;
{ TMethodList }
procedure TMethodList.AddProcedure(ProcName, ProcType: String);
var
po : TProcObj;
x,y : Integer;
begin
ProcType := Uppercase(ProcType);
x := ProcIndexOf(ProcName);
if x <> -1 then begin
y := Procs[x].ProcType.IndexOf(ProcType);
If y = -1 then TProcObj(fProcList.Items[x]).ProcType.add(ProcType);
end else begin
po := TProcObj.create(self);
po.Name := ProcName;
po.ProcType.add(ProcType);
fProcList.add(po);
end
end;
procedure TMethodList.ClearProcList;
begin
fProcList.Clear;
end;
constructor TMethodList.create(aOwner: TPSScriptExtension);
begin
inherited create;
fOwner := aOwner;
fProcList := TObjectList.create(true);
fEventList := TObjectList.create(true);
end;
procedure TMethodList.CreateProc(ProcName:String; aPropType: TTypeData);
var
newProc: string;
P: PByte;
i: Integer;
pf : TParamFlags;
{$IFDEF FPC}
// mh: TParamFlags(P^) doesn't compile in FPC, this function will "fix" it.
// yes it's ugly, but I don't know an other way to fix it
function GetParamFlags(P: Byte): TParamFlags;
begin
result := [];
if (Ord(pfVar) and P <> 0) then Include(result, pfVar);
if (Ord(pfConst) and P <> 0) then Include(result, pfConst);
if (Ord(pfArray) and P <> 0) then Include(result, pfArray);
if (Ord(pfAddress) and P <> 0) then Include(result, pfAddress);
if (Ord(pfReference) and P <> 0) then Include(result, pfReference);
if (Ord(pfOut) and P <> 0) then Include(result, pfOut);
end;
{$ENDIF}
begin
WITH aPropType do begin
if MethodKind=mkProcedure then NewProc:='procedure '
else NewProc:='function ';
NewProc:=NewProc + ProcName+'(';
P:=PByte(@ParamList);
for i:=0 to Pred(ParamCount) do
begin
{$IFDEF FPC}
pf:=GetParamFlags(P^);
{$ELSE}
pf:=TParamFlags(P^);
{$ENDIF}
if pfVar in pf then NewProc:=NewProc+'var ';
if pfConst in pf then NewProc:=NewProc+'const ';
Inc(P);
NewProc:=NewProc +PShortString(P)^ +' : ';
Inc(P,Succ(P^));
if pfArray in pf then NewProc:=NewProc+'array of ';
NewProc := NewProc + PShortString(P)^;
Inc(P,Succ(P^));
If i < Pred(ParamCount) then NewProc := NewProc + '; ';
end;
NewProc := NewProc +')' ;
if (MethodKind=mkFunction) then
NewProc := NewProc +':'+ PShortString(P)^;
NewProc:=NewProc+';'^m^j
+'Begin'^m^j^m^j
+'End;'^m^j;
If @fowner.FOnInsertMethod <> nil then begin
fowner.FOnInsertMethod(fOwner, NewProc, false);
end else begin
InsertMethod(NewProc);
end;
fowner.CompileIfNeeded;
end;
end;
procedure TMethodList.InsertMethod(NewProc: String; OnTop: Boolean = false);
var
x : Integer;
sl : TStringList;
nBegins : Integer;
nProcs : Integer;
line, test : String;
function IsItem(line,item:String; First :Boolean = false):Boolean;
var
nPos : Integer;
begin
nPos := pos(item,line);
result := ((npos>0) and ((length(Line)-nPos<= length(item)) or not(line[nPos+length(item)] in ['0'..'9','A'..'Z','_'])) And
((Npos = 1) or ((not first) and not(line[nPos-1] in ['0'..'9','A'..'Z','_']))));
end;
begin
sl := TStringList.create;
Try
sl.Text := NewProc;
test := uppercase(trim(sl[0]));
finally
Sl.free;
end;
nProcs := 0;
nBegins := 0;
x := 0;
If Not Ontop Then begin
for x := 0 to fOwner.script.count -1 do begin
Line := fowner.script[x];
Line := uppercase(trim(line));
If IsItem(line,'PROCEDURE', true) or IsItem(line,'FUNCTION', true) then begin
If nBegins >0 then Raise exception.create('Missing some ''End'' statments');
If (nProcs = 0) and (line = test) then
Exit;
Inc(nProcs);
end;
If Pos('END',line) < Pos('BEGIN',line) then begin
If IsItem(line,'END') then begin
If (nBegins = 0) and (nProcs=0) then Break;
Dec(nBegins);
If nBegins = 0 then Dec(nProcs);
end;
If IsItem(line,'BEGIN') or IsItem(line,'TRY') then begin
If nProcs = 0 then Break;
Inc(nBegins);
end;
end else begin
If IsItem(line,'BEGIN') or IsItem(line,'TRY') then begin
If nProcs = 0 then Break;
Inc(nBegins);
end;
If IsItem(line,'END') then begin
If (nBegins = 0) and (nProcs=0) then Break;
Dec(nBegins);
If nBegins = 0 then Dec(nProcs);
end;
end;
end;
end;
FOwner.script.BeginUpdate;
Try
If (nProcs <> 0) or (nBegins<>0) then
Raise exception.create(sMissingEndStatment);
If (Not Ontop) and (x>0) and (TRim(FOwner.script[x-1])<>'') then begin
FOwner.script.Insert(x,'');
inc(x);
end;
FOwner.script.Insert(x,NewProc);
FOwner.script.text := FOwner.script.text;
finally
FOwner.script.EndUpdate;
end;
end;
destructor TMethodList.Destroy;
begin
fProcList.Free; {<< Needs Eventlist for removing Methods}
fEventList.Free;
inherited;
end;
procedure TMethodList.FillMethods;
var
x, y : Integer;
m : TMethod;
begin
for x := 0 to fEventList.Count-1 do begin
Y := ProcIndexOf(MethodS[x].ProcName);
If (Y >= 0) and assigned(Methods[x].Instance) then begin
m := Procs[Y].Method;
if m.Data = nil then begin
m := fOwner.Exec.GetProcAsMethodN(Procs[Y].name);
TProcObj(fProcList.Items[Y]).Method := m;
end;
SetMethodProp(Methods[x].Instance, Methods[x].propname, m );
end;
end;
end;
function TMethodList.GetMethodName(Instance: TObject; PropName: String): String;
var
x : Integer;
begin
fOwner.CompileIfNeeded;
x := methodIndexOf(Instance,PropName);
If x>=0 then result := Methods[x].ProcName
else result := '';
end;
function TMethodList.GetObject(Index: Integer): TMethodObj;
begin
result := TMethodObj(fEventList.items[Index]);
end;
function TMethodList.GetProcObj(Index: Integer): TProcObj;
begin
result := TProcObj(fProcList.items[Index]);
end;
procedure TMethodList.ListEventsName(EventType: string; List: TStrings);
var
x : Integer;
begin
If List = nil then exit;
EventType := Uppercase(EventType);
List.Clear;
fOwner.CompileIfNeeded;
for x := 0 to fProcList.count-1 do begin
If Procs[x].ProcType.indexof(EventType)<> -1 then
List.add(Procs[x].name);
end;
end;
function TMethodList.MethodCount: Integer;
begin
result := fEventList.count;
end;
function TMethodList.methodIndexOf(Instance: TObject;
PropName: String): Integer;
var x : integer;
begin
Result := -1;
for x := 0 to fEventList.count-1 do begin
if (TMethodObj(fEventList.Items[x]).Instance = Instance) and
((propName='') or(TMethodObj(fEventList.Items[x]).PropName = PropName)) then begin
Result := x;
exit;
end;
end;
end;
function TMethodList.ProcCount: Integer;
begin
result := fProcList.count;
end;
function TMethodList.ProcIndexOf(Name: String): Integer;
var x : integer;
begin
result := -1;
Name := Uppercase(name);
For x := 0 to fProcList.count-1 do begin
If Uppercase(TProcObj(fProcList.Items[x]).name) = name then begin
Result := x;
exit;
end;
end;
end;
procedure TMethodList.SetMethodName(Instance: TObject; PropName: String;
const Value: String);
var
x, y : Integer;
mo : TMethodObj;
function TypeData(Instance: TObject; const PropName: string):PTypeData;
var
PropInfo: PPropInfo;
begin
// assume failure
Result := Nil;
PropInfo := GetPropInfo(Instance, PropName);
if PropInfo <> nil then
begin
Result:= GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});
end
end;
begin
If PropName = '' then begin
x := 0;
While x < MethodCount do begin
If (Methods[x].Instance = Instance) or (Instance = nil) then
fEventList.Delete(x)
else Inc(x);
end;
end else begin
x := methodIndexOf(Instance, PropName);
if value = '' then begin
if x >= 0 then fEventList.Delete(x);
end else begin
fOwner.CompileIfNeeded;
y := ProcIndexOf(Value);
If (Y = -1) then begin
CreateProc(Value, TypeData(Instance,propName)^);
y := 0;
end;
If (x = -1) then begin
If (Y <> -1) then begin
mo := TMethodObj.create;
mo.Instance := TPersistent(Instance);
mo.ProPName := Propname;
mo.procName := Value;
If (methodIndexOf(Instance,'')<>-1) and Instance.InheritsFrom(TComponent) then
fOwner.FreeNotification(TComponent(Instance));
fEventList.add(mo);
end;
end else
begin
Methods[x].procname := Value;
end;
end;
end;
end;
procedure TMethodList.ClearAll;
begin
fProclist.clear;
fEventList.Clear;
end;
{ TProcObj }
constructor TProcObj.create(aOwner: TMethodList);
begin
inherited create();
fOwner := aOwner;
ProcType := TStringList.Create;
end;
destructor TProcObj.Destroy;
var x : Integer;
m :TMethod;
begin
m.Code := nil;
m.Data := nil;
If ((Method.Data <> nil) or (method.Code<> nil)) and (fOwner<>nil) and assigned(fOwner) then begin
for x := 0 to fOwner.MethodCount-1 do begin
If (name = fOwner.Methods[x].ProcName) and assigned(fOwner.Methods[x].Instance) then begin
Try
SetMethodProp(fOwner.Methods[x].Instance, fOwner.Methods[x].PropName,m);
except; end;
end;
end;
end;
ProcType.free;
inherited;
end;
procedure TProcObj.SetName(const Value: String);
var
x : Integer;
begin
If FName <> Value then begin
If fName<>'' then begin
for x := 0 to fOwner.MethodCount-1 do begin
If Fname = fOwner.Methods[x].ProcName then begin
fOwner.Methods[x].ProcName := Value;
end;
end;
end;
FName := Value;
end;
end;
end.