* Improved class tree building

git-svn-id: trunk@47537 -
This commit is contained in:
michael 2020-11-23 08:30:17 +00:00
parent bf8a020316
commit f1aca7f877
2 changed files with 149 additions and 161 deletions

View File

@ -2412,17 +2412,21 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
PushOutputNode(h);
end;
Procedure AppendClass(E : TDomElement);
Procedure AppendClass(E : TPasElementNode);
Var
N : TDomNode;
P,PM : TPasElement;
P,PM,M : TPasElement;
EN : String;
LL : TstringList;
I,J : Integer;
begin
EN:=Package.Name+'.'+UTF8Encode(E['unit'])+'.'+UTF8Encode(E.NodeName);
M:=E.Element.GetModule;
if (M<>Nil) then
EN:=Package.Name+'.'+UTF8Encode(M.Name)+'.'+UTF8Encode(E.Element.Name)
else
EN:=UTF8Encode(E.Element.Name);
J:=AList.IndexOf(EN);
If J<>-1 then
P:=AList.Objects[J] as TPasElement
@ -2442,30 +2446,17 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
end
end
else
AppendText(CurOutputNode,E.Nodename);
LL:=TStringList.Create;
try
N:=E.FirstChild;
While (N<>Nil) do
begin
if (N.NodeType=ELEMENT_NODE) then
LL.AddObject(UTF8Encode(N.NodeName),N);
N:=N.NextSibling;
end;
if (LL.Count>0) then
begin
LL.Sorted:=true;
PushClassList;
try
For I:=0 to LL.Count-1 do
AppendClass(LL.Objects[i] as TDomElement);
finally
PopOutputNode;
end;
end;
finally
LL.Free;
end;
AppendText(CurOutputNode,E.Element.Name);
if E.ChildCount>0 then
begin
PushClassList;
try
For I:=0 to E.ChildCount-1 do
AppendClass(E.Children[i] as TPasElementNode);
finally
PopOutputNode;
end;
end;
Finally
PopOutputNode;
end;
@ -2473,7 +2464,8 @@ procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Bo
Var
B : TClassTreeBuilder;
E : TDomElement;
E : TPasElementNode;
begin
PushOutputNode(BodyElement);
try
@ -2483,7 +2475,7 @@ begin
// Classes
// WriteXMLFile(B.ClassTree,'tree.xml');
// Dummy TObject
E:=B.ClassTree.DocumentElement;
E:=B.RootNode;
PushClassList;
try
AppendClass(E);

View File

@ -5,188 +5,184 @@ unit fpdocclasstree;
interface
uses
Classes, SysUtils, DOM, pastree;
Classes, SysUtils, DOM, pastree, contnrs;
Type
{ TPasElementNode }
TPasElementNode = Class
Private
FElement : TPasElement;
FChildren : TFPObjectList;
function GetChild(aIndex : Integer): TPasElementNode;
function GetChildCount: Integer;
Public
Constructor Create (aElement : TPaselement);
Destructor Destroy; override;
Procedure AddChild(C : TPasElementNode);
Procedure SortChildren;
Property Element : TPasElement Read FElement;
Property Children [aIndex : Integer] : TPasElementNode Read GetChild;
Property ChildCount : Integer Read GetChildCount;
end;
{ TClassTreeBuilder }
TClassTreeBuilder = Class
Private
FClassTree : TXMLDocument;
FTreeStart : TDomElement;
// Full name -> TDomElement;
FElementList : TFPObjectHashTable;
FObjectKind : TPasObjKind;
FPackage: TPasPackage;
FParentObject : TPasClassType;
FRootNode : TPasElementNode;
FRootObjectName : string;
Protected
function LookForElement(PE: TDomElement; AElement: TPasElement; NoPath : Boolean): TDomNode;
function NodeMatch(N: TDomNode; AElement: TPasElement; NoPath : Boolean): Boolean;
Function AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
function AddToList(aElement: TPasClassType): TPasElementNode;
Public
Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
Destructor Destroy; override;
Function BuildTree(AObjects : TStringList) : Integer;
Property ClassTree : TXMLDocument Read FClassTree;
Property RootNode : TPasElementNode Read FRootNode;
end;
implementation
{ 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: TPaselement);
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(APackage : TPasPackage;
AObjectKind: TPasObjKind);
begin
FCLassTree:=TXMLDocument.Create;
FPackage:=APAckage;
FObjectKind:=AObjectKind;
Case FObjectkind of
okObject : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
okClass : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
okInterface : FRootObjectName:='#rtl.System.IInterface';
okObject,
okClass : FRootObjectName:='#rtl.System.TObject';
else
FRootObjectName:='#rtl.System.TObject';
end;
FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
FParentObject.ObjKind:=FObjectKind;
FTreeStart:=FClassTree.CreateElement('TObject');
FTreeStart['unit']:='System';
ClassTree.AppendChild(FTreeStart);
FRootNode:=TPasElementNode.Create(FParentObject);
FElementList:=TFPObjectHashTable.Create(False);
FElementList.Add(FRootObjectName,FRootNode);
end;
destructor TClassTreeBuilder.Destroy;
begin
FreeAndNil(FParentObject);
FreeAndNil(FClassTree);
FreeAndNil(FRootNode);
FreeAndNil(FElementList);
Inherited;
end;
Function TClassTreeBuilder.AddToList(aElement : TPasClassType) : TPasElementNode;
Var
aParentNode : TPasElementNode;
aName : String;
begin
if aElement=Nil then
aName:=FRootObjectName
else
begin
aName:=aElement.PathName;
end;
Result:=TPasElementNode(FElementList.Items[aName]);
if (Result=Nil) then
begin
if aElement.AncestorType is TPasClassType then
aParentNode:=AddToList(aElement.AncestorType as TPasClassType)
else
aParentNode:=FRootNode;
Result:=TPasElementNode.Create(aElement);
aParentNode.AddChild(Result);
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;
AObjects.Sorted:=True;
For I:=0 to AObjects.Count-1 do
// Advanced records
if AObjects.Objects[i] is TPasClassType then
begin
PC:=AObjects.Objects[i] as TPasClassType;
If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
AddToClassTree(PC,Result);
AddToList(PC);
end;
end;
Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
Var
PN,S,EN : String;
begin
EN:=AELement.Name;
Result:=(N.NodeType=ELEMENT_NODE);
if Result then
begin
S:=UTF8Encode(N.NodeName);
if NoPath then
Begin
Result:=CompareText(S,EN)=0;
end
else
begin
IF Assigned(Aelement.GetModule) then
PN:=Aelement.GetModule.PackageName
else
PN:=FPackage.Name;
S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S;
Result:=(CompareText(S,AElement.PathName)=0);
end;
end;
end;
Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
Var
N : TDomNode;
begin
// Writeln('Enter TClassTreeBuilderLookForElement');
Result:=PE;
While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
Result:=Result.NextSibling;
If (Result=Nil) then
if Assigned(PE) then
begin
N:=PE.FirstChild;
While (Result=Nil) and (N<>Nil) do
begin
if (N.NodeType=ELEMENT_NODE) then
begin
Result:=LookForElement(N as TDomElement,AElement,NoPath);
end;
N:=N.NextSibling;
end;
end;
// Writeln('Exit TClassTreeBuilderLookForElement');
end;
Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
// there are several codepaths that use uninitialized variables. (N,PE)
// I initialized them to nil to at least make failures deterministic.
Var
PC : TPasClassType;
PE : TDomElement;
M : TPasModule;
N : TDomNode;
begin
// Writeln('Enter TClassTreeBuilder.AddToClassTree');
//if Assigned(AElement) then
//Writeln('Addtoclasstree : ',aElement.Name);
Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
If (AElement=Nil) then
begin
Result:=FTreeStart;
Exit;
end
else If (AElement is TPasUnresolvedTypeRef) then
begin
N:=LookForElement(FTreeStart,AElement,True);
If (N=Nil) then
PE:=FTreeStart;
end
else If (AElement is TPasClassType) then
begin
if (AElement=FParentObject) then
Result:=FTreeStart
else
begin
PC:=AElement as TPasClassType;
PE:=AddToClassTree(PC.AncestorType,ACount);
if PE=Nil then
PE:=FTreeStart;
N:=LookForElement(PE,PC,False);
end
end;
If (N<>Nil) then
begin
Result:=N as TDomElement
end
else if AElement.Name<>'' then
begin // N=NIL, PE might be nil.
Inc(ACount);
Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name));
If Not (AElement is TPasUnresolvedTypeRef) then
begin
M:=AElement.GetModule;
if Assigned(M) then
Result['unit']:=UTF8Decode(M.Name);
end;
if PE=Nil then
begin
PE:=FTreeStart
end;
// if not assigned, probably needs to be assigned to something else.
if assigned(PE) then
PE.AppendChild(Result);
end;
end;
end.