resref.inc 12 KB

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