resref.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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. EnterCriticalSection(ResolveSection);
  85. Try
  86. If Assigned(NeedResolving) then
  87. begin
  88. Result:=TUnResolvedInstance(NeedResolving.Root);
  89. While (Result<>Nil) and (Result.Instance<>AInstance) do
  90. Result:=TUnResolvedInstance(Result.Next);
  91. end;
  92. finally
  93. LeaveCriticalSection(ResolveSection);
  94. end;
  95. end;
  96. Function AddtoResolveList(AInstance: TPersistent) : TUnResolvedInstance;
  97. begin
  98. Result:=FindUnresolvedInstance(AInstance);
  99. If (Result=Nil) then
  100. begin
  101. EnterCriticalSection(ResolveSection);
  102. Try
  103. If not Assigned(NeedResolving) then
  104. NeedResolving:=TLinkedList.Create(TUnResolvedInstance);
  105. Result:=NeedResolving.Add as TUnResolvedInstance;
  106. Result.Instance:=AInstance;
  107. finally
  108. LeaveCriticalSection(ResolveSection);
  109. end;
  110. end;
  111. end;
  112. // Walk through the global list of instances to be resolved.
  113. Procedure VisitResolveList(V : TLinkedListVisitor);
  114. begin
  115. EnterCriticalSection(ResolveSection);
  116. Try
  117. try
  118. NeedResolving.Foreach(V);
  119. Finally
  120. FreeAndNil(V);
  121. end;
  122. Finally
  123. LeaveCriticalSection(ResolveSection);
  124. end;
  125. end;
  126. procedure GlobalFixupReferences;
  127. begin
  128. If (NeedResolving=Nil) then
  129. Exit;
  130. GlobalNameSpace.BeginWrite;
  131. try
  132. VisitResolveList(TResolveReferenceVisitor.Create);
  133. finally
  134. GlobalNameSpace.EndWrite;
  135. end;
  136. end;
  137. procedure GetFixupReferenceNames(Root: TComponent; Names: TStrings);
  138. begin
  139. If (NeedResolving=Nil) then
  140. Exit;
  141. VisitResolveList(TReferenceNamesVisitor.Create(Root,Names));
  142. end;
  143. procedure GetFixupInstanceNames(Root: TComponent; const ReferenceRootName: string; Names: TStrings);
  144. begin
  145. If (NeedResolving=Nil) then
  146. Exit;
  147. VisitResolveList(TReferenceInstancesVisitor.Create(Root,ReferenceRootName,Names));
  148. end;
  149. procedure RedirectFixupReferences(Root: TComponent; const OldRootName, NewRootName: string);
  150. begin
  151. If (NeedResolving=Nil) then
  152. Exit;
  153. VisitResolveList(TRedirectReferenceVisitor.Create(Root,OldRootName,NewRootName));
  154. end;
  155. procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
  156. begin
  157. If (NeedResolving=Nil) then
  158. Exit;
  159. VisitResolveList(TRemoveReferenceVisitor.Create(Root,RootName));
  160. end;
  161. procedure RemoveFixups(Instance: TPersistent);
  162. begin
  163. // This needs work.
  164. {
  165. if not Assigned(GlobalFixupList) then
  166. exit;
  167. with GlobalFixupList.LockList do
  168. try
  169. for i := Count - 1 downto 0 do
  170. begin
  171. CurFixup := TPropFixup(Items[i]);
  172. if (CurFixup.FInstance = Instance) then
  173. begin
  174. Delete(i);
  175. CurFixup.Free;
  176. end;
  177. end;
  178. finally
  179. GlobalFixupList.UnlockList;
  180. end;
  181. }
  182. end;
  183. { TUnresolvedReference }
  184. Function TUnresolvedReference.Resolve(Instance : TPersistent) : Boolean;
  185. Var
  186. C : TComponent;
  187. begin
  188. C:=FindGlobalComponent(FGlobal);
  189. Result:=(C<>Nil);
  190. If Result then
  191. begin
  192. C:=FindNestedComponent(C,FRelative);
  193. Result:=C<>Nil;
  194. If Result then
  195. SetObjectProp(Instance, FPropInfo,C);
  196. end;
  197. end;
  198. Function TUnresolvedReference.RootMatches(ARoot : TComponent) : Boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  199. begin
  200. Result:=(ARoot=Nil) or (ARoot=FRoot);
  201. end;
  202. Function TUnResolvedReference.NextRef : TUnresolvedReference;
  203. begin
  204. Result:=TUnresolvedReference(Next);
  205. end;
  206. { TUnResolvedInstance }
  207. destructor TUnResolvedInstance.Destroy;
  208. begin
  209. FUnresolved.Free;
  210. inherited Destroy;
  211. end;
  212. function TUnResolvedInstance.AddReference(ARoot: TComponent;
  213. APropInfo: PPropInfo; AGlobal, ARelative: String): TUnresolvedReference;
  214. begin
  215. If (FUnResolved=Nil) then
  216. FUnResolved:=TLinkedList.Create(TUnresolvedReference);
  217. Result:=FUnResolved.Add as TUnresolvedReference;
  218. Result.FGlobal:=AGLobal;
  219. Result.FRelative:=ARelative;
  220. Result.FPropInfo:=APropInfo;
  221. Result.FRoot:=ARoot;
  222. end;
  223. Function TUnResolvedInstance.RootUnresolved : TUnresolvedReference;
  224. begin
  225. Result:=Nil;
  226. If Assigned(FUnResolved) then
  227. Result:=TUnresolvedReference(FUnResolved.Root);
  228. end;
  229. Function TUnResolvedInstance.ResolveReferences:Boolean;
  230. Var
  231. R,RN : TUnresolvedReference;
  232. begin
  233. R:=RootUnResolved;
  234. While (R<>Nil) do
  235. begin
  236. RN:=R.NextRef;
  237. If R.Resolve(Self.Instance) then
  238. FUnresolved.RemoveItem(R,True);
  239. R:=RN;
  240. end;
  241. Result:=RootUnResolved=Nil;
  242. end;
  243. { TReferenceNamesVisitor }
  244. Constructor TReferenceNamesVisitor.Create(ARoot : TComponent;AList : TStrings);
  245. begin
  246. FRoot:=ARoot;
  247. FList:=AList;
  248. end;
  249. Function TReferenceNamesVisitor.Visit(Item : TLinkedListItem) : Boolean;
  250. Var
  251. R : TUnresolvedReference;
  252. begin
  253. R:=TUnResolvedInstance(Item).RootUnresolved;
  254. While (R<>Nil) do
  255. begin
  256. If R.RootMatches(FRoot) then
  257. If (FList.IndexOf(R.FGlobal)=-1) then
  258. FList.Add(R.FGlobal);
  259. R:=R.NextRef;
  260. end;
  261. Result:=True;
  262. end;
  263. { TReferenceInstancesVisitor }
  264. Constructor TReferenceInstancesVisitor.Create(ARoot : TComponent; Const ARef : String;AList : TStrings);
  265. begin
  266. FRoot:=ARoot;
  267. FRef:=UpperCase(ARef);
  268. FList:=AList;
  269. end;
  270. Function TReferenceInstancesVisitor.Visit(Item : TLinkedListItem) : Boolean;
  271. Var
  272. R : TUnresolvedReference;
  273. begin
  274. R:=TUnResolvedInstance(Item).RootUnresolved;
  275. While (R<>Nil) do
  276. begin
  277. If (FRoot=R.FRoot) and (FRef=UpperCase(R.FGLobal)) Then
  278. If Flist.IndexOf(R.FRelative)=-1 then
  279. Flist.Add(R.FRelative);
  280. R:=R.NextRef;
  281. end;
  282. Result:=True;
  283. end;
  284. { TRedirectReferenceVisitor }
  285. Constructor TRedirectReferenceVisitor.Create(ARoot : TComponent; Const AOld,ANew : String);
  286. begin
  287. FRoot:=ARoot;
  288. FOld:=UpperCase(AOld);
  289. FNew:=ANew;
  290. end;
  291. Function TRedirectReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  292. Var
  293. R : TUnresolvedReference;
  294. begin
  295. R:=TUnResolvedInstance(Item).RootUnresolved;
  296. While (R<>Nil) do
  297. begin
  298. If R.RootMatches(FRoot) and (FOld=UpperCase(R.FGLobal)) Then
  299. R.FGlobal:=FNew;
  300. R:=R.NextRef;
  301. end;
  302. Result:=True;
  303. end;
  304. { TRemoveReferenceVisitor }
  305. Constructor TRemoveReferenceVisitor.Create(ARoot : TComponent; Const ARef : String);
  306. begin
  307. FRoot:=ARoot;
  308. FRef:=UpperCase(ARef);
  309. end;
  310. Function TRemoveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  311. Var
  312. I : Integer;
  313. UI : TUnResolvedInstance;
  314. R : TUnresolvedReference;
  315. L : TFPList;
  316. begin
  317. UI:=TUnResolvedInstance(Item);
  318. R:=UI.RootUnresolved;
  319. L:=Nil;
  320. Try
  321. // Collect all matches.
  322. While (R<>Nil) do
  323. begin
  324. If R.RootMatches(FRoot) and ((FRef = '') or (FRef=UpperCase(R.FGLobal))) Then
  325. begin
  326. If Not Assigned(L) then
  327. L:=TFPList.Create;
  328. L.Add(R);
  329. end;
  330. R:=R.NextRef;
  331. end;
  332. // Remove all matches.
  333. IF Assigned(L) then
  334. begin
  335. For I:=0 to L.Count-1 do
  336. UI.FUnresolved.RemoveItem(TLinkedListitem(L[i]),True);
  337. end;
  338. // If any references are left, leave them.
  339. If UI.FUnResolved.Root=Nil then
  340. begin
  341. If List=Nil then
  342. List:=TFPList.Create;
  343. List.Add(UI);
  344. end;
  345. Finally
  346. L.Free;
  347. end;
  348. Result:=True;
  349. end;
  350. { TBuildListVisitor }
  351. Procedure TBuildListVisitor.Add(Item : TlinkedListItem);
  352. begin
  353. If (List=Nil) then
  354. List:=TFPList.Create;
  355. List.Add(Item);
  356. end;
  357. Destructor TBuildListVisitor.Destroy;
  358. Var
  359. I : Integer;
  360. begin
  361. If Assigned(List) then
  362. For I:=0 to List.Count-1 do
  363. NeedResolving.RemoveItem(TLinkedListItem(List[I]),True);
  364. FreeAndNil(List);
  365. Inherited;
  366. end;
  367. { TResolveReferenceVisitor }
  368. Function TResolveReferenceVisitor.Visit(Item : TLinkedListItem) : Boolean;
  369. begin
  370. If TUnResolvedInstance(Item).ResolveReferences then
  371. Add(Item);
  372. Result:=True;
  373. end;