mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 03:48:07 +02:00
477 lines
12 KiB
PHP
477 lines
12 KiB
PHP
{
|
|
This file is part of the Free Pascal Run Time Library (rtl)
|
|
Copyright (c) 2007 by Michael Van Canneyt,
|
|
member of the Free Pascal development team
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
|
|
type
|
|
// Quadruple representing an unresolved component property.
|
|
|
|
{ TUnresolvedReference }
|
|
|
|
TUnresolvedReference = class(TlinkedListItem)
|
|
Private
|
|
FRoot: TComponent; // Root component when streaming
|
|
FPropInfo: PPropInfo; // Property to set.
|
|
FGlobal, // Global component.
|
|
FRelative : string; // Path relative to global component.
|
|
Function Resolve(Instance : TPersistent) : Boolean; // Resolve this reference
|
|
Function RootMatches(ARoot : TComponent) : Boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE} // True if Froot matches or ARoot is nil.
|
|
Function NextRef : TUnresolvedReference; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
|
|
end;
|
|
|
|
TLocalUnResolvedReference = class(TUnresolvedReference)
|
|
Finstance : TPersistent;
|
|
end;
|
|
|
|
// Linked list of TPersistent items that have unresolved properties.
|
|
|
|
{ TUnResolvedInstance }
|
|
|
|
TUnResolvedInstance = Class(TLinkedListItem)
|
|
Instance : TPersistent; // Instance we're handling unresolveds for
|
|
FUnresolved : TLinkedList; // The list
|
|
Destructor Destroy; override;
|
|
Function AddReference(ARoot : TComponent; APropInfo : PPropInfo; AGlobal,ARelative : String) : TUnresolvedReference;
|
|
Function RootUnresolved : TUnresolvedReference; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE} // Return root element in list.
|
|
Function ResolveReferences : Boolean; // Return true if all unresolveds were resolved.
|
|
end;
|
|
|
|
// Builds a list of TUnResolvedInstances, removes them from global list on free.
|
|
TBuildListVisitor = Class(TLinkedListVisitor)
|
|
List : TFPList;
|
|
Procedure Add(Item : TlinkedListItem); // Add TUnResolvedInstance item to list. Create list if needed
|
|
Destructor Destroy; override; // All elements in list (if any) are removed from the global list.
|
|
end;
|
|
|
|
// Visitor used to try and resolve instances in the global list
|
|
TResolveReferenceVisitor = Class(TBuildListVisitor)
|
|
Function Visit(Item : TLinkedListItem) : Boolean; override;
|
|
end;
|
|
|
|
// Visitor used to remove all references to a certain component.
|
|
TRemoveReferenceVisitor = Class(TBuildListVisitor)
|
|
FRef : String;
|
|
FRoot : TComponent;
|
|
Constructor Create(ARoot : TComponent;Const ARef : String);
|
|
Function Visit(Item : TLinkedListItem) : Boolean; override;
|
|
end;
|
|
|
|
// Visitor used to collect reference names.
|
|
TReferenceNamesVisitor = Class(TLinkedListVisitor)
|
|
FList : TStrings;
|
|
FRoot : TComponent;
|
|
Function Visit(Item : TLinkedListItem) : Boolean; override;
|
|
Constructor Create(ARoot : TComponent;AList : TStrings);
|
|
end;
|
|
|
|
// Visitor used to collect instance names.
|
|
TReferenceInstancesVisitor = Class(TLinkedListVisitor)
|
|
FList : TStrings;
|
|
FRef : String;
|
|
FRoot : TComponent;
|
|
Function Visit(Item : TLinkedListItem) : Boolean; override;
|
|
Constructor Create(ARoot : TComponent;Const ARef : String; AList : TStrings);
|
|
end;
|
|
|
|
// Visitor used to redirect links to another root component.
|
|
TRedirectReferenceVisitor = Class(TLinkedListVisitor)
|
|
FOld,
|
|
FNew : String;
|
|
FRoot : TComponent;
|
|
Function Visit(Item : TLinkedListItem) : Boolean; override;
|
|
Constructor Create(ARoot : TComponent;Const AOld,ANew : String);
|
|
end;
|
|
|
|
var
|
|
NeedResolving : TLinkedList;
|
|
ResolveSection : TRTLCriticalSection;
|
|
|
|
// Add an instance to the global list of instances which need resolving.
|
|
Function FindUnresolvedInstance(AInstance: TPersistent) : TUnResolvedInstance;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
EnterCriticalSection(ResolveSection);
|
|
Try
|
|
{$endif}
|
|
If Assigned(NeedResolving) then
|
|
begin
|
|
Result:=TUnResolvedInstance(NeedResolving.Root);
|
|
While (Result<>Nil) and (Result.Instance<>AInstance) do
|
|
Result:=TUnResolvedInstance(Result.Next);
|
|
end;
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
finally
|
|
LeaveCriticalSection(ResolveSection);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
Function AddtoResolveList(AInstance: TPersistent) : TUnResolvedInstance;
|
|
|
|
begin
|
|
Result:=FindUnresolvedInstance(AInstance);
|
|
If (Result=Nil) then
|
|
begin
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
EnterCriticalSection(ResolveSection);
|
|
Try
|
|
{$endif}
|
|
If not Assigned(NeedResolving) then
|
|
NeedResolving:=TLinkedList.Create(TUnResolvedInstance);
|
|
Result:=NeedResolving.Add as TUnResolvedInstance;
|
|
Result.Instance:=AInstance;
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
finally
|
|
LeaveCriticalSection(ResolveSection);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
end;
|
|
|
|
// Walk through the global list of instances to be resolved.
|
|
|
|
Procedure VisitResolveList(V : TLinkedListVisitor);
|
|
|
|
begin
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
EnterCriticalSection(ResolveSection);
|
|
Try
|
|
{$endif}
|
|
try
|
|
NeedResolving.Foreach(V);
|
|
Finally
|
|
FreeAndNil(V);
|
|
end;
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
Finally
|
|
LeaveCriticalSection(ResolveSection);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure GlobalFixupReferences;
|
|
|
|
begin
|
|
If (NeedResolving=Nil) then
|
|
Exit;
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
GlobalNameSpace.BeginWrite;
|
|
try
|
|
{$endif}
|
|
VisitResolveList(TResolveReferenceVisitor.Create);
|
|
{$ifdef FPC_HAS_FEATURE_THREADING}
|
|
finally
|
|
GlobalNameSpace.EndWrite;
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
|
|
procedure GetFixupReferenceNames(Root: TComponent; Names: TStrings);
|
|
|
|
begin
|
|
If (NeedResolving=Nil) then
|
|
Exit;
|
|
VisitResolveList(TReferenceNamesVisitor.Create(Root,Names));
|
|
end;
|
|
|
|
procedure GetFixupInstanceNames(Root: TComponent; const ReferenceRootName: string; Names: TStrings);
|
|
|
|
begin
|
|
If (NeedResolving=Nil) then
|
|
Exit;
|
|
VisitResolveList(TReferenceInstancesVisitor.Create(Root,ReferenceRootName,Names));
|
|
end;
|
|
|
|
procedure RedirectFixupReferences(Root: TComponent; const OldRootName, NewRootName: string);
|
|
|
|
begin
|
|
If (NeedResolving=Nil) then
|
|
Exit;
|
|
VisitResolveList(TRedirectReferenceVisitor.Create(Root,OldRootName,NewRootName));
|
|
end;
|
|
|
|
procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
|
|
|
|
begin
|
|
If (NeedResolving=Nil) then
|
|
Exit;
|
|
VisitResolveList(TRemoveReferenceVisitor.Create(Root,RootName));
|
|
end;
|
|
|
|
procedure RemoveFixups(Instance: TPersistent);
|
|
|
|
begin
|
|
// This needs work.
|
|
{
|
|
if not Assigned(GlobalFixupList) then
|
|
exit;
|
|
|
|
with GlobalFixupList.LockList do
|
|
try
|
|
for i := Count - 1 downto 0 do
|
|
begin
|
|
CurFixup := TPropFixup(Items[i]);
|
|
if (CurFixup.FInstance = Instance) then
|
|
begin
|
|
Delete(i);
|
|
CurFixup.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
GlobalFixupList.UnlockList;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
{ TUnresolvedReference }
|
|
|
|
Function TUnresolvedReference.Resolve(Instance : TPersistent) : Boolean;
|
|
|
|
Var
|
|
C : TComponent;
|
|
|
|
begin
|
|
C:=FindGlobalComponent(FGlobal);
|
|
Result:=(C<>Nil);
|
|
If Result then
|
|
begin
|
|
C:=FindNestedComponent(C,FRelative);
|
|
Result:=C<>Nil;
|
|
If Result then
|
|
SetObjectProp(Instance, FPropInfo,C);
|
|
end;
|
|
end;
|
|
|
|
Function TUnresolvedReference.RootMatches(ARoot : TComponent) : Boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
|
|
|
|
begin
|
|
Result:=(ARoot=Nil) or (ARoot=FRoot);
|
|
end;
|
|
|
|
Function TUnResolvedReference.NextRef : TUnresolvedReference;
|
|
|
|
begin
|
|
Result:=TUnresolvedReference(Next);
|
|
end;
|
|
|
|
{ TUnResolvedInstance }
|
|
|
|
destructor TUnResolvedInstance.Destroy;
|
|
begin
|
|
FUnresolved.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TUnResolvedInstance.AddReference(ARoot: TComponent;
|
|
APropInfo: PPropInfo; AGlobal, ARelative: String): TUnresolvedReference;
|
|
begin
|
|
If (FUnResolved=Nil) then
|
|
FUnResolved:=TLinkedList.Create(TUnresolvedReference);
|
|
Result:=FUnResolved.Add as TUnresolvedReference;
|
|
Result.FGlobal:=AGLobal;
|
|
Result.FRelative:=ARelative;
|
|
Result.FPropInfo:=APropInfo;
|
|
Result.FRoot:=ARoot;
|
|
end;
|
|
|
|
Function TUnResolvedInstance.RootUnresolved : TUnresolvedReference;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
If Assigned(FUnResolved) then
|
|
Result:=TUnresolvedReference(FUnResolved.Root);
|
|
end;
|
|
|
|
Function TUnResolvedInstance.ResolveReferences:Boolean;
|
|
|
|
Var
|
|
R,RN : TUnresolvedReference;
|
|
|
|
begin
|
|
R:=RootUnResolved;
|
|
While (R<>Nil) do
|
|
begin
|
|
RN:=R.NextRef;
|
|
If R.Resolve(Self.Instance) then
|
|
FUnresolved.RemoveItem(R,True);
|
|
R:=RN;
|
|
end;
|
|
Result:=RootUnResolved=Nil;
|
|
end;
|
|
|
|
{ TReferenceNamesVisitor }
|
|
|
|
Constructor TReferenceNamesVisitor.Create(ARoot : TComponent;AList : TStrings);
|
|
|
|
begin
|
|
FRoot:=ARoot;
|
|
FList:=AList;
|
|
end;
|
|
|
|
Function TReferenceNamesVisitor.Visit(Item : TLinkedListItem) : Boolean;
|
|
|
|
Var
|
|
R : TUnresolvedReference;
|
|
|
|
begin
|
|
R:=TUnResolvedInstance(Item).RootUnresolved;
|
|
While (R<>Nil) do
|
|
begin
|
|
If R.RootMatches(FRoot) then
|
|
If (FList.IndexOf(R.FGlobal)=-1) then
|
|
FList.Add(R.FGlobal);
|
|
R:=R.NextRef;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
{ TReferenceInstancesVisitor }
|
|
|
|
Constructor TReferenceInstancesVisitor.Create(ARoot : TComponent; Const ARef : String;AList : TStrings);
|
|
|
|
begin
|
|
FRoot:=ARoot;
|
|
FRef:=UpperCase(ARef);
|
|
FList:=AList;
|
|
end;
|
|
|
|
Function TReferenceInstancesVisitor.Visit(Item : TLinkedListItem) : Boolean;
|
|
|
|
Var
|
|
R : TUnresolvedReference;
|
|
|
|
begin
|
|
R:=TUnResolvedInstance(Item).RootUnresolved;
|
|
While (R<>Nil) do
|
|
begin
|
|
If (FRoot=R.FRoot) and (FRef=UpperCase(R.FGLobal)) Then
|
|
If Flist.IndexOf(R.FRelative)=-1 then
|
|
Flist.Add(R.FRelative);
|
|
R:=R.NextRef;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
{ TRedirectReferenceVisitor }
|
|
|
|
Constructor TRedirectReferenceVisitor.Create(ARoot : TComponent; Const AOld,ANew : String);
|
|
|
|
begin
|
|
FRoot:=ARoot;
|
|
FOld:=UpperCase(AOld);
|
|
FNew:=ANew;
|
|
end;
|
|
|
|
Function TRedirectReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
|
|
|
|
Var
|
|
R : TUnresolvedReference;
|
|
|
|
begin
|
|
R:=TUnResolvedInstance(Item).RootUnresolved;
|
|
While (R<>Nil) do
|
|
begin
|
|
If R.RootMatches(FRoot) and (FOld=UpperCase(R.FGLobal)) Then
|
|
R.FGlobal:=FNew;
|
|
R:=R.NextRef;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
{ TRemoveReferenceVisitor }
|
|
|
|
Constructor TRemoveReferenceVisitor.Create(ARoot : TComponent; Const ARef : String);
|
|
|
|
begin
|
|
FRoot:=ARoot;
|
|
FRef:=UpperCase(ARef);
|
|
end;
|
|
|
|
Function TRemoveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
|
|
|
|
Var
|
|
I : Integer;
|
|
UI : TUnResolvedInstance;
|
|
R : TUnresolvedReference;
|
|
L : TFPList;
|
|
|
|
begin
|
|
UI:=TUnResolvedInstance(Item);
|
|
R:=UI.RootUnresolved;
|
|
L:=Nil;
|
|
Try
|
|
// Collect all matches.
|
|
While (R<>Nil) do
|
|
begin
|
|
If R.RootMatches(FRoot) and ((FRef = '') or (FRef=UpperCase(R.FGLobal))) Then
|
|
begin
|
|
If Not Assigned(L) then
|
|
L:=TFPList.Create;
|
|
L.Add(R);
|
|
end;
|
|
R:=R.NextRef;
|
|
end;
|
|
// Remove all matches.
|
|
IF Assigned(L) then
|
|
begin
|
|
For I:=0 to L.Count-1 do
|
|
UI.FUnresolved.RemoveItem(TLinkedListitem(L[i]),True);
|
|
end;
|
|
// If any references are left, leave them.
|
|
If UI.FUnResolved.Root=Nil then
|
|
begin
|
|
If List=Nil then
|
|
List:=TFPList.Create;
|
|
List.Add(UI);
|
|
end;
|
|
Finally
|
|
L.Free;
|
|
end;
|
|
Result:=True;
|
|
end;
|
|
|
|
{ TBuildListVisitor }
|
|
|
|
Procedure TBuildListVisitor.Add(Item : TlinkedListItem);
|
|
|
|
begin
|
|
If (List=Nil) then
|
|
List:=TFPList.Create;
|
|
List.Add(Item);
|
|
end;
|
|
|
|
Destructor TBuildListVisitor.Destroy;
|
|
|
|
Var
|
|
I : Integer;
|
|
|
|
begin
|
|
If Assigned(List) then
|
|
For I:=0 to List.Count-1 do
|
|
NeedResolving.RemoveItem(TLinkedListItem(List[I]),True);
|
|
FreeAndNil(List);
|
|
Inherited;
|
|
end;
|
|
|
|
{ TResolveReferenceVisitor }
|
|
|
|
Function TResolveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
|
|
|
|
begin
|
|
If TUnResolvedInstance(Item).ResolveReferences then
|
|
Add(Item);
|
|
Result:=True;
|
|
end;
|