resref.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. type
  2. // Quadruple representing an unresolved component property.
  3. { TUnresolvedReference }
  4. TUnresolvedReference = class(TlinkedListItem)
  5. Private
  6. FRoot: TComponent; // Root component when streaming
  7. FPropInfo: PPropInfo; // Property to set.
  8. FGlobal, // Global component.
  9. FRelative : string; // Path relative to global component.
  10. Function Resolve(Instance : TPersistent) : Boolean; // Resolve this reference
  11. Function RootMatches(ARoot : TComponent) : Boolean; Inline; // True if Froot matches or ARoot is nil.
  12. Function NextRef : TUnresolvedReference; inline;
  13. end;
  14. TLocalUnResolvedReference = class(TUnresolvedReference)
  15. Finstance : TPersistent;
  16. end;
  17. // Linked list of TPersistent items that have unresolved properties.
  18. { TUnResolvedInstance }
  19. TUnResolvedInstance = Class(TLinkedListItem)
  20. Instance : TPersistent; // Instance we're handling unresolveds for
  21. FUnresolved : TLinkedList; // The list
  22. Destructor Destroy; override;
  23. Function AddReference(ARoot : TComponent; APropInfo : PPropInfo; AGlobal,ARelative : String) : TUnresolvedReference;
  24. Function RootUnresolved : TUnresolvedReference; inline; // Return root element in list.
  25. Function ResolveReferences : Boolean; // Return true if all unresolveds were resolved.
  26. end;
  27. // Builds a list of TUnResolvedInstances, removes them from global list on free.
  28. TBuildListVisitor = Class(TLinkedListVisitor)
  29. List : TFPList;
  30. Procedure Add(Item : TlinkedListItem); // Add TUnResolvedInstance item to list. Create list if needed
  31. Destructor Destroy; override; // All elements in list (if any) are removed from the global list.
  32. end;
  33. // Visitor used to try and resolve instances in the global list
  34. TResolveReferenceVisitor = Class(TBuildListVisitor)
  35. Function Visit(Item : TLinkedListItem) : Boolean; override;
  36. end;
  37. // Visitor used to remove all references to a certain component.
  38. TRemoveReferenceVisitor = Class(TBuildListVisitor)
  39. FRef : String;
  40. FRoot : TComponent;
  41. Constructor Create(ARoot : TComponent;Const ARef : String);
  42. Function Visit(Item : TLinkedListItem) : Boolean; override;
  43. end;
  44. // Visitor used to collect reference names.
  45. TReferenceNamesVisitor = Class(TLinkedListVisitor)
  46. FList : TStrings;
  47. FRoot : TComponent;
  48. Function Visit(Item : TLinkedListItem) : Boolean; override;
  49. Constructor Create(ARoot : TComponent;AList : TStrings);
  50. end;
  51. // Visitor used to collect instance names.
  52. TReferenceInstancesVisitor = Class(TLinkedListVisitor)
  53. FList : TStrings;
  54. FRef : String;
  55. FRoot : TComponent;
  56. Function Visit(Item : TLinkedListItem) : Boolean; override;
  57. Constructor Create(ARoot : TComponent;Const ARef : String; AList : TStrings);
  58. end;
  59. // Visitor used to redirect links to another root component.
  60. TRedirectReferenceVisitor = Class(TLinkedListVisitor)
  61. FOld,
  62. FNew : String;
  63. FRoot : TComponent;
  64. Function Visit(Item : TLinkedListItem) : Boolean; override;
  65. Constructor Create(ARoot : TComponent;Const AOld,ANew : String);
  66. end;
  67. var
  68. NeedResolving : TLinkedList;
  69. ResolveSection : TRTLCriticalSection;
  70. LastAddInstance : TUnresolvedInstance;
  71. // Add an instance to the global list of instances which need resolving.
  72. Function FindUnresolvedInstance(AInstance: TPersistent) : TUnResolvedInstance;
  73. begin
  74. Result:=Nil;
  75. EnterCriticalSection(ResolveSection);
  76. Try
  77. If Assigned(NeedResolving) then
  78. begin
  79. Result:=TUnResolvedInstance(NeedResolving.Root);
  80. While (Result<>Nil) and (Result.Instance<>AInstance) do
  81. Result:=TUnResolvedInstance(Result.Next);
  82. end;
  83. finally
  84. LeaveCriticalSection(ResolveSection);
  85. end;
  86. end;
  87. Function AddtoResolveList(AInstance: TPersistent) : TUnResolvedInstance;
  88. begin
  89. Result:=FindUnresolvedInstance(AInstance);
  90. If (Result=Nil) then
  91. begin
  92. EnterCriticalSection(ResolveSection);
  93. Try
  94. If not Assigned(NeedResolving) then
  95. NeedResolving:=TLinkedList.Create(TUnResolvedInstance);
  96. Result:=NeedResolving.Add as TUnResolvedInstance;
  97. Result.Instance:=AInstance;
  98. finally
  99. LeaveCriticalSection(ResolveSection);
  100. end;
  101. end;
  102. end;
  103. // Walk through the global list of instances to be resolved.
  104. Procedure VisitResolveList(V : TLinkedListVisitor);
  105. begin
  106. EnterCriticalSection(ResolveSection);
  107. Try
  108. try
  109. NeedResolving.Foreach(V);
  110. Finally
  111. FreeAndNil(V);
  112. end;
  113. Finally
  114. LeaveCriticalSection(ResolveSection);
  115. end;
  116. end;
  117. procedure GlobalFixupReferences;
  118. var
  119. V : TResolveReferenceVisitor;
  120. I : Integer;
  121. begin
  122. If (NeedResolving=Nil) then
  123. Exit;
  124. GlobalNameSpace.BeginWrite;
  125. try
  126. VisitResolveList(TResolveReferenceVisitor.Create);
  127. finally
  128. GlobalNameSpace.EndWrite;
  129. end;
  130. end;
  131. procedure GetFixupReferenceNames(Root: TComponent; Names: TStrings);
  132. begin
  133. If (NeedResolving=Nil) then
  134. Exit;
  135. VisitResolveList(TReferenceNamesVisitor.Create(Root,Names));
  136. end;
  137. procedure GetFixupInstanceNames(Root: TComponent; const ReferenceRootName: string; Names: TStrings);
  138. begin
  139. If (NeedResolving=Nil) then
  140. Exit;
  141. VisitResolveList(TReferenceInstancesVisitor.Create(Root,ReferenceRootName,Names));
  142. end;
  143. procedure RedirectFixupReferences(Root: TComponent; const OldRootName, NewRootName: string);
  144. begin
  145. If (NeedResolving=Nil) then
  146. Exit;
  147. VisitResolveList(TRedirectReferenceVisitor.Create(Root,OldRootName,NewRootName));
  148. end;
  149. procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
  150. begin
  151. If (NeedResolving=Nil) then
  152. Exit;
  153. VisitResolveList(TRemoveReferenceVisitor.Create(Root,RootName));
  154. end;
  155. procedure RemoveFixups(Instance: TPersistent);
  156. begin
  157. // This needs work.
  158. {
  159. if not Assigned(GlobalFixupList) then
  160. exit;
  161. with GlobalFixupList.LockList do
  162. try
  163. for i := Count - 1 downto 0 do
  164. begin
  165. CurFixup := TPropFixup(Items[i]);
  166. if (CurFixup.FInstance = Instance) then
  167. begin
  168. Delete(i);
  169. CurFixup.Free;
  170. end;
  171. end;
  172. finally
  173. GlobalFixupList.UnlockList;
  174. end;
  175. }
  176. end;
  177. { TUnresolvedReference }
  178. Function TUnresolvedReference.Resolve(Instance : TPersistent) : Boolean;
  179. Var
  180. C : TComponent;
  181. begin
  182. C:=FindGlobalComponent(FGlobal);
  183. Result:=(C<>Nil);
  184. If Result then
  185. begin
  186. C:=FindNestedComponent(C,FRelative);
  187. Result:=C<>Nil;
  188. If Result then
  189. SetObjectProp(Instance, FPropInfo,C);
  190. end;
  191. end;
  192. Function TUnresolvedReference.RootMatches(ARoot : TComponent) : Boolean; Inline;
  193. begin
  194. Result:=(ARoot=Nil) or (ARoot=FRoot);
  195. end;
  196. Function TUnResolvedReference.NextRef : TUnresolvedReference;
  197. begin
  198. Result:=TUnresolvedReference(Next);
  199. end;
  200. { TUnResolvedInstance }
  201. destructor TUnResolvedInstance.Destroy;
  202. begin
  203. FUnresolved.Free;
  204. inherited Destroy;
  205. end;
  206. function TUnResolvedInstance.AddReference(ARoot: TComponent;
  207. APropInfo: PPropInfo; AGlobal, ARelative: String): TUnresolvedReference;
  208. begin
  209. If (FUnResolved=Nil) then
  210. FUnResolved:=TLinkedList.Create(TUnresolvedReference);
  211. Result:=FUnResolved.Add as TUnresolvedReference;
  212. Result.FGlobal:=AGLobal;
  213. Result.FRelative:=ARelative;
  214. Result.FPropInfo:=APropInfo;
  215. Result.FRoot:=ARoot;
  216. end;
  217. Function TUnResolvedInstance.RootUnresolved : TUnresolvedReference;
  218. begin
  219. Result:=Nil;
  220. If Assigned(FUnResolved) then
  221. Result:=TUnresolvedReference(FUnResolved.Root);
  222. end;
  223. Function TUnResolvedInstance.ResolveReferences:Boolean;
  224. Var
  225. R,RN : TUnresolvedReference;
  226. begin
  227. R:=RootUnResolved;
  228. While (R<>Nil) do
  229. begin
  230. RN:=R.NextRef;
  231. If R.Resolve(Self.Instance) then
  232. FUnresolved.RemoveItem(R,True);
  233. R:=RN;
  234. end;
  235. Result:=RootUnResolved=Nil;
  236. end;
  237. { TReferenceNamesVisitor }
  238. Constructor TReferenceNamesVisitor.Create(ARoot : TComponent;AList : TStrings);
  239. begin
  240. FRoot:=ARoot;
  241. FList:=AList;
  242. end;
  243. Function TReferenceNamesVisitor.Visit(Item : TLinkedListItem) : Boolean;
  244. Var
  245. R : TUnresolvedReference;
  246. begin
  247. R:=TUnResolvedInstance(Item).RootUnresolved;
  248. While (R<>Nil) do
  249. begin
  250. If R.RootMatches(FRoot) then
  251. If (FList.IndexOf(R.FGlobal)=-1) then
  252. FList.Add(R.FGlobal);
  253. R:=R.NextRef;
  254. end;
  255. Result:=True;
  256. end;
  257. { TReferenceInstancesVisitor }
  258. Constructor TReferenceInstancesVisitor.Create(ARoot : TComponent; Const ARef : String;AList : TStrings);
  259. begin
  260. FRoot:=ARoot;
  261. FRef:=UpperCase(ARef);
  262. FList:=AList;
  263. end;
  264. Function TReferenceInstancesVisitor.Visit(Item : TLinkedListItem) : Boolean;
  265. Var
  266. R : TUnresolvedReference;
  267. begin
  268. R:=TUnResolvedInstance(Item).RootUnresolved;
  269. While (R<>Nil) do
  270. begin
  271. If (FRoot=R.FRoot) and (FRef=UpperCase(R.FGLobal)) Then
  272. If Flist.IndexOf(R.FRelative)=-1 then
  273. Flist.Add(R.FRelative);
  274. R:=R.NextRef;
  275. end;
  276. Result:=True;
  277. end;
  278. { TRedirectReferenceVisitor }
  279. Constructor TRedirectReferenceVisitor.Create(ARoot : TComponent; Const AOld,ANew : String);
  280. begin
  281. FRoot:=ARoot;
  282. FOld:=UpperCase(AOld);
  283. FNew:=ANew;
  284. end;
  285. Function TRedirectReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  286. Var
  287. R : TUnresolvedReference;
  288. begin
  289. R:=TUnResolvedInstance(Item).RootUnresolved;
  290. While (R<>Nil) do
  291. begin
  292. If R.RootMatches(FRoot) and (FOld=UpperCase(R.FGLobal)) Then
  293. R.FGlobal:=FNew;
  294. R:=R.NextRef;
  295. end;
  296. Result:=True;
  297. end;
  298. { TRemoveReferenceVisitor }
  299. Constructor TRemoveReferenceVisitor.Create(ARoot : TComponent; Const ARef : String);
  300. begin
  301. FRoot:=ARoot;
  302. FRef:=UpperCase(ARef);
  303. end;
  304. Function TRemoveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  305. Var
  306. I : Integer;
  307. UI : TUnResolvedInstance;
  308. R : TUnresolvedReference;
  309. L : TFPList;
  310. begin
  311. UI:=TUnResolvedInstance(Item);
  312. R:=UI.RootUnresolved;
  313. L:=Nil;
  314. Try
  315. // Collect all matches.
  316. While (R<>Nil) do
  317. begin
  318. If R.RootMatches(FRoot) and (FRef=UpperCase(R.FGLobal)) Then
  319. begin
  320. If Not Assigned(L) then
  321. L:=TFPList.Create;
  322. L.Add(R);
  323. end;
  324. R:=R.NextRef;
  325. end;
  326. // Remove all matches.
  327. IF Assigned(L) then
  328. begin
  329. For I:=0 to L.Count-1 do
  330. UI.FUnresolved.RemoveItem(TLinkedListitem(L[i]),True);
  331. end;
  332. // If any references are left, leave them.
  333. If UI.FUnResolved.Root=Nil then
  334. begin
  335. If List=Nil then
  336. List:=TFPList.Create;
  337. List.Add(UI);
  338. end;
  339. Finally
  340. L.Free;
  341. end;
  342. Result:=True;
  343. end;
  344. { TBuildListVisitor }
  345. Procedure TBuildListVisitor.Add(Item : TlinkedListItem);
  346. begin
  347. If (List=Nil) then
  348. List:=TFPList.Create;
  349. List.Add(Item);
  350. end;
  351. Destructor TBuildListVisitor.Destroy;
  352. Var
  353. I : Integer;
  354. begin
  355. If Assigned(List) then
  356. For I:=0 to List.Count-1 do
  357. NeedResolving.RemoveItem(TLinkedListItem(List[I]),True);
  358. FreeAndNil(List);
  359. Inherited;
  360. end;
  361. { TResolveReferenceVisitor }
  362. Function TResolveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  363. begin
  364. If TUnResolvedInstance(Item).ResolveReferences then
  365. Add(Item);
  366. Result:=True;
  367. end;