123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- unit fpdocclasstree;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, dGlobals, pastree, contnrs, DOM ,XMLWrite;
- Type
- TPasObjKindSet = set of TPasObjKind;
- { TPasElementNode }
- TPasElementNode = Class
- Private
- FElement : TPasType;
- FParentNode: TPasElementNode;
- FChildren : TFPObjectList;
- function GetChild(aIndex : Integer): TPasElementNode;
- function GetChildCount: Integer;
- Public
- Constructor Create (aElement : TPasType);
- Destructor Destroy; override;
- Procedure AddChild(C : TPasElementNode);
- Procedure SortChildren;
- Property Element : TPasType Read FElement;
- Property ParentNode : TPasElementNode read FParentNode;
- Property Children [aIndex : Integer] : TPasElementNode Read GetChild;
- Property ChildCount : Integer Read GetChildCount;
- end;
- { TClassTreeBuilder }
- TClassTreeBuilder = Class
- Private
- FEngine:TFPDocEngine;
- FElementList : TFPObjectHashTable;
- FObjectKind : TPasObjKindSet;
- FPackage: TPasPackage;
- FParentObject : TPasClassType;
- FRootNode : TPasElementNode;
- FRootObjectName : string;
- FRootObjectPathName : string;
- Protected
- function AddToList(aElement: TPasType): TPasElementNode;
- Public
- Constructor Create(AEngine:TFPDocEngine; APackage : TPasPackage;
- AObjectKind : TPasObjKindSet = okWithFields);
- Destructor Destroy; override;
- Function BuildTree(AObjects : TStringList) : Integer;
- Procedure SaveToXml(AFileName: String);
- Property RootNode : TPasElementNode Read FRootNode;
- Property PasElToNodes: TFPObjectHashTable read FElementList;
- function GetPasElNode (APasEl: TPasElement) : TPasElementNode;
- end;
- implementation
- uses
- fpdocstrs, pasresolver;
- { TPasElementNode }
- function SortOnElementName(Item1, Item2: Pointer): Integer;
- begin
- Result:=CompareText(TPasElementNode(Item1).Element.Name,TPasElementNode(Item2).Element.Name);
- end;
- function TPasElementNode.GetChild(aIndex : Integer): TPasElementNode;
- begin
- if Assigned(FChildren) then
- Result:=TPasElementNode(FChildren[aIndex])
- else
- Raise EListError.Create('Index out of range');
- end;
- function TPasElementNode.GetChildCount: Integer;
- begin
- if Assigned(FChildren) then
- Result:=FChildren.Count
- else
- Result:=0
- end;
- constructor TPasElementNode.Create(aElement: TPasType);
- begin
- FElement:=aElement;
- end;
- destructor TPasElementNode.Destroy;
- begin
- FreeAndNil(FChildren);
- inherited Destroy;
- end;
- procedure TPasElementNode.AddChild(C: TPasElementNode);
- begin
- if FChildren=Nil then
- FChildren:=TFPObjectList.Create(True);
- FChildren.Add(C);
- end;
- procedure TPasElementNode.SortChildren;
- begin
- if Assigned(FChildren) then
- FChildren.Sort(@SortOnElementName);
- end;
- constructor TClassTreeBuilder.Create(AEngine:TFPDocEngine; APackage : TPasPackage;
- AObjectKind: TPasObjKindSet);
- begin
- FEngine:= AEngine;
- FPackage:= APAckage;
- FObjectKind:=AObjectKind;
- if (okInterface in FObjectkind) then
- begin
- FRootObjectPathName:='#rtl.System.IInterface';
- FRootObjectName:= 'IInterface';
- end
- else if (FObjectkind * okWithFields) <> [] then
- begin
- FRootObjectPathName:='#rtl.System.TObject';
- FRootObjectName:= 'TObject';
- end
- else // TODO: I don`t know need it ? Without that the code may be simplified.
- begin
- FRootObjectPathName:='#rtl.System.TObject';
- FRootObjectName:= 'TObject';
- end;
- FParentObject:=TPasClassType.Create(FRootObjectName,FEngine.FindModule('System'));
- if not Assigned(FParentObject) then
- FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
- if (okInterface in FObjectkind) then
- FParentObject.ObjKind:=okInterface
- else if (FObjectkind * okWithFields) <> [] then
- FParentObject.ObjKind:=okClass
- else
- FParentObject.ObjKind:=okClass;
- FRootNode:=TPasElementNode.Create(FParentObject);
- FRootNode.FParentNode := nil;
- FElementList:=TFPObjectHashTable.Create(False);
- FElementList.Add(FRootObjectPathName,FRootNode);
- end;
- destructor TClassTreeBuilder.Destroy;
- begin
- FreeAndNil(FParentObject);
- FreeAndNil(FRootNode);
- FreeAndNil(FElementList);
- Inherited;
- end;
- function TClassTreeBuilder.AddToList ( aElement: TPasType
- ) : TPasElementNode;
- Var
- aParentNode : TPasElementNode;
- aName : String;
- aElementClass: TPasClassType;
- begin
- Result:= nil; aElementClass:=nil;
- if (aElement is TPasClassType) then
- aElementClass:= TPasClassType(aElement);
- if Assigned(aElementClass) and not (aElementClass.ObjKind in FObjectKind) then exit;
- if not Assigned(aElementClass) and not (aElement is TPasAliasType) then exit;
- aParentNode:= nil;
- if aElement=Nil then
- aName:=FRootObjectName
- else if (aElement is TPasAliasType) then
- aName:=TPasAliasType(aElement).DestType.FullName
- else
- aName:=aElement.PathName;
- Result:=TPasElementNode(FElementList.Items[aName]);
- if (Result=Nil) then
- begin
- if Assigned(aElementClass) and (
- (aElementClass.AncestorType is TPasClassType) or
- (aElementClass.AncestorType is TPasAliasType)
- ) then
- aParentNode:=AddToList(aElementClass.AncestorType);
- if not Assigned(aParentNode) then
- aParentNode:=FRootNode;
- if (aElement is TPasAliasType) then
- Result:=TPasElementNode.Create(TPasAliasType(TPasType(aElement)).DestType)
- else
- Result:=TPasElementNode.Create(aElement);
- aParentNode.AddChild(Result);
- Result.FParentNode := aParentNode;
- FElementList.Add(aName,Result);
- end;
- end;
- function TClassTreeBuilder.BuildTree ( AObjects: TStringList ) : Integer;
- (*
- Procedure DumpNode(Prefix : String; N : TPasElementNode);
- Var
- I : Integer;
- begin
- Writeln(Prefix,N.FElement.Name);
- if Assigned(N.FChildren) then
- For I:=0 to N.FChildren.Count-1 do
- DumpNode(Prefix+' ',TPasElementNode(N.FChildren[i]));
- end;
- *)
- Var
- I : Integer;
- PC : TPasClassType;
- begin
- Result:=0;
- For I:=0 to AObjects.Count-1 do
- // Advanced records
- if AObjects.Objects[i] is TPasClassType then
- begin
- PC:=AObjects.Objects[i] as TPasClassType;
- AddToList(PC);
- end;
- end;
- function TClassTreeBuilder.GetPasElNode ( APasEl: TPasElement
- ) : TPasElementNode;
- begin
- Result:= TPasElementNode(FElementList.Items[APasEl.PathName]);
- end;
- procedure TClassTreeBuilder.SaveToXml ( AFileName: String );
- procedure AddPasElChildsToXml (ParentxmlEl : TDOMElement ; ParentPasEl: TPasElementNode ) ;
- var
- CounterVar: Integer;
- PasElNode: TPasElementNode;
- AXmlDoc: TDOMDocument;
- xmlEl: TDOMElement;
- M: TPasModule;
- begin
- if not Assigned(ParentPasEl) or (ParentPasEl.ChildCount = 0) then exit;
- AXmlDoc:= ParentxmlEl.OwnerDocument;
- for CounterVar := 0 to ParentPasEl.ChildCount-1 do
- begin
- PasElNode:= ParentPasEl.Children[CounterVar];
- xmlEl:= AXmlDoc.CreateElement(UTF8Decode(PasElNode.Element.Name));
- M:= PasElNode.Element.GetModule;
- xmlEl['unit'] := UTF8Decode(M.Name);
- xmlEl['package'] := UTF8Decode(M.PackageName);
- xmlEl['type'] := UTF8Decode(GetElementTypeName(PasElNode.Element));
- ParentxmlEl.AppendChild(xmlEl);
- AddPasElChildsToXml(xmlEl, PasElNode);
- end;
- end;
- var
- XmlDoc: TXMLDocument;
- XmlRootEl: TDOMElement;
- M: TPasModule;
- begin
- XmlDoc:= TXMLDocument.Create;
- XmlDoc.AppendChild(XmlDoc.CreateComment(UTF8Decode(SDocGeneratedByComment)));
- try
- XmlRootEl:= XmlDoc.CreateElement(UTF8Decode(FRootNode.Element.Name));
- M:= FRootNode.Element.GetModule;
- if Assigned(M) then
- begin
- XmlRootEl['unit'] := UTF8Decode(M.Name);
- XmlRootEl['package'] := UTF8Decode(M.PackageName);
- XmlRootEl['type'] := UTF8Decode(GetElementTypeName(FRootNode.Element));
- end
- else
- begin
- XmlRootEl['unit'] := 'system';
- XmlRootEl['package'] := 'rtl';
- if (okWithFields * FObjectKind) <> [] then
- XmlRootEl['type'] := 'class'
- else if (okInterface in FObjectKind) then
- XmlRootEl['type'] := 'interface'
- else
- XmlRootEl['type'] := 'class';
- end;
- XmlDoc.AppendChild(XmlRootEl);
- AddPasElChildsToXml(XmlRootEl, FRootNode);
- WriteXMLFile(XmlDoc, AFileName);
- finally
- XmlDoc.Free;
- end;
- end;
- end.
|