resref.inc 12 KB

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