fpdocclasstree.pp 6.8 KB

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