fpdocclasstree.pp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. unit fpdocclasstree;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, dGlobals, pastree, contnrs{$IFDEF TREE_TEST}, DOM ,XMLWrite{$ENDIF};
  6. Type
  7. { TPasElementNode }
  8. TPasElementNode = Class
  9. Private
  10. FElement : TPasClassType;
  11. FParentNode: TPasElementNode;
  12. FChildren : TFPObjectList;
  13. function GetChild(aIndex : Integer): TPasElementNode;
  14. function GetChildCount: Integer;
  15. Public
  16. Constructor Create (aElement : TPasClassType);
  17. Destructor Destroy; override;
  18. Procedure AddChild(C : TPasElementNode);
  19. Procedure SortChildren;
  20. Property Element : TPasClassType Read FElement;
  21. Property ParentNode : TPasElementNode read FParentNode;
  22. Property Children [aIndex : Integer] : TPasElementNode Read GetChild;
  23. Property ChildCount : Integer Read GetChildCount;
  24. end;
  25. { TClassTreeBuilder }
  26. TClassTreeBuilder = Class
  27. Private
  28. FEngine:TFPDocEngine;
  29. FElementList : TFPObjectHashTable;
  30. FObjectKind : TPasObjKind;
  31. FPackage: TPasPackage;
  32. FParentObject : TPasClassType;
  33. FRootNode : TPasElementNode;
  34. FRootObjectName : string;
  35. FRootObjectPathName : string;
  36. Protected
  37. function AddToList(aElement: TPasClassType): TPasElementNode;
  38. Public
  39. Constructor Create(AEngine:TFPDocEngine; APackage : TPasPackage;
  40. AObjectKind : TPasObjKind = okClass);
  41. Destructor Destroy; override;
  42. Function BuildTree(AObjects : TStringList) : Integer;
  43. {$IFDEF TREE_TEST}
  44. Procedure SaveToXml(AFileName: String);
  45. {$ENDIF}
  46. Property RootNode : TPasElementNode Read FRootNode;
  47. Property PasElToNodes: TFPObjectHashTable read FElementList;
  48. function GetPasElNode (APasEl: TPasElement) : TPasElementNode;
  49. end;
  50. implementation
  51. { TPasElementNode }
  52. function SortOnElementName(Item1, Item2: Pointer): Integer;
  53. begin
  54. Result:=CompareText(TPasElementNode(Item1).Element.Name,TPasElementNode(Item2).Element.Name);
  55. end;
  56. function TPasElementNode.GetChild(aIndex : Integer): TPasElementNode;
  57. begin
  58. if Assigned(FChildren) then
  59. Result:=TPasElementNode(FChildren[aIndex])
  60. else
  61. Raise EListError.Create('Index out of range');
  62. end;
  63. function TPasElementNode.GetChildCount: Integer;
  64. begin
  65. if Assigned(FChildren) then
  66. Result:=FChildren.Count
  67. else
  68. Result:=0
  69. end;
  70. constructor TPasElementNode.Create(aElement: TPasClassType);
  71. begin
  72. FElement:=aElement;
  73. end;
  74. destructor TPasElementNode.Destroy;
  75. begin
  76. FreeAndNil(FChildren);
  77. inherited Destroy;
  78. end;
  79. procedure TPasElementNode.AddChild(C: TPasElementNode);
  80. begin
  81. if FChildren=Nil then
  82. FChildren:=TFPObjectList.Create(True);
  83. FChildren.Add(C);
  84. end;
  85. procedure TPasElementNode.SortChildren;
  86. begin
  87. if Assigned(FChildren) then
  88. FChildren.Sort(@SortOnElementName);
  89. end;
  90. constructor TClassTreeBuilder.Create(AEngine:TFPDocEngine; APackage : TPasPackage;
  91. AObjectKind: TPasObjKind);
  92. begin
  93. FEngine:= AEngine;
  94. FPackage:= APAckage;
  95. FObjectKind:=AObjectKind;
  96. Case FObjectkind of
  97. okInterface :
  98. begin
  99. FRootObjectPathName:='#rtl.System.IInterface';
  100. FRootObjectName:= 'IInterface';
  101. end;
  102. okObject, okClass :
  103. begin
  104. FRootObjectPathName:='#rtl.System.TObject';
  105. FRootObjectName:= 'TObject';
  106. end
  107. else
  108. begin
  109. FRootObjectPathName:='#rtl.System.TObject';
  110. FRootObjectName:= 'TObject';
  111. end;
  112. end;
  113. FParentObject:=TPasClassType.Create(FRootObjectName,FEngine.FindModule('System'));
  114. if not Assigned(FParentObject) then
  115. FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
  116. FParentObject.ObjKind:=FObjectKind;
  117. FRootNode:=TPasElementNode.Create(FParentObject);
  118. FRootNode.FParentNode := nil;
  119. FElementList:=TFPObjectHashTable.Create(False);
  120. FElementList.Add(FRootObjectPathName,FRootNode);
  121. end;
  122. destructor TClassTreeBuilder.Destroy;
  123. begin
  124. FreeAndNil(FParentObject);
  125. FreeAndNil(FRootNode);
  126. FreeAndNil(FElementList);
  127. Inherited;
  128. end;
  129. function TClassTreeBuilder.AddToList ( aElement: TPasClassType
  130. ) : TPasElementNode;
  131. Var
  132. aParentNode : TPasElementNode;
  133. aName : String;
  134. begin
  135. Result:= nil;
  136. if (aElement.ObjKind <> FObjectKind) then exit;
  137. aParentNode:= nil;
  138. if aElement=Nil then
  139. aName:=FRootObjectName
  140. else
  141. aName:=aElement.PathName;
  142. Result:=TPasElementNode(FElementList.Items[aName]);
  143. if (Result=Nil) then
  144. begin
  145. if aElement.AncestorType is TPasClassType then
  146. aParentNode:=AddToList(aElement.AncestorType as TPasClassType);
  147. if not Assigned(aParentNode) then
  148. aParentNode:=FRootNode;
  149. Result:=TPasElementNode.Create(aElement);
  150. aParentNode.AddChild(Result);
  151. Result.FParentNode := aParentNode;
  152. FElementList.Add(aName,Result);
  153. end;
  154. end;
  155. function TClassTreeBuilder.BuildTree ( AObjects: TStringList ) : Integer;
  156. (*
  157. Procedure DumpNode(Prefix : String; N : TPasElementNode);
  158. Var
  159. I : Integer;
  160. begin
  161. Writeln(Prefix,N.FElement.Name);
  162. if Assigned(N.FChildren) then
  163. For I:=0 to N.FChildren.Count-1 do
  164. DumpNode(Prefix+' ',TPasElementNode(N.FChildren[i]));
  165. end;
  166. *)
  167. Var
  168. I : Integer;
  169. PC : TPasClassType;
  170. begin
  171. Result:=0;
  172. For I:=0 to AObjects.Count-1 do
  173. // Advanced records
  174. if AObjects.Objects[i] is TPasClassType then
  175. begin
  176. PC:=AObjects.Objects[i] as TPasClassType;
  177. AddToList(PC);
  178. end;
  179. end;
  180. function TClassTreeBuilder.GetPasElNode ( APasEl: TPasElement
  181. ) : TPasElementNode;
  182. begin
  183. Result:= TPasElementNode(FElementList.Items[APasEl.PathName]);
  184. end;
  185. {$IFDEF TREE_TEST}
  186. procedure TClassTreeBuilder.SaveToXml ( AFileName: String ) ;
  187. procedure AddPasElChildsToXml (ParentxmlEl : TDOMElement ; ParentPasEl: TPasElementNode ) ;
  188. var
  189. CounterVar: Integer;
  190. PasElNode: TPasElementNode;
  191. AXmlDoc: TDOMDocument;
  192. xmlEl: TDOMElement;
  193. M: TPasModule;
  194. begin
  195. if not Assigned(ParentPasEl) or (ParentPasEl.ChildCount = 0) then exit;
  196. AXmlDoc:= ParentxmlEl.OwnerDocument;
  197. for CounterVar := 0 to ParentPasEl.ChildCount-1 do
  198. begin
  199. PasElNode:= ParentPasEl.Children[CounterVar];
  200. xmlEl:= AXmlDoc.CreateElement(UnicodeString(PasElNode.Element.Name));
  201. M:= PasElNode.Element.GetModule;
  202. xmlEl['unit'] := UnicodeString(M.Name);
  203. xmlEl['package'] := UnicodeString(M.PackageName);
  204. ParentxmlEl.AppendChild(xmlEl);
  205. AddPasElChildsToXml(xmlEl, PasElNode);
  206. end;
  207. end;
  208. var
  209. XmlDoc: TXMLDocument;
  210. XmlRootEl: TDOMElement;
  211. M: TPasModule;
  212. begin
  213. XmlDoc:= TXMLDocument.Create;
  214. try
  215. XmlRootEl:= XmlDoc.CreateElement(UnicodeString(FRootNode.Element.Name));
  216. M:= FRootNode.Element.GetModule;
  217. if Assigned(M) then
  218. begin
  219. XmlRootEl['unit'] := UnicodeString(M.Name);
  220. XmlRootEl['package'] := UnicodeString(M.PackageName);
  221. end
  222. else
  223. begin
  224. XmlRootEl['unit'] := 'system';
  225. XmlRootEl['package'] := 'rtl';
  226. end;
  227. XmlDoc.AppendChild(XmlRootEl);
  228. AddPasElChildsToXml(XmlRootEl, FRootNode);
  229. WriteXMLFile(XmlDoc, AFileName);
  230. finally
  231. XmlDoc.Free;
  232. end;
  233. end;
  234. {$ENDIF}
  235. end.