fpdocclasstree.pp 7.5 KB

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