View Issue Details

IDProjectCategoryView StatusLast Update
0038141FPCUtilitiespublic2020-12-26 21:41
ReporterAndrey Sobol Assigned ToMichael Van Canneyt  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Platformi386OSWindows 
Fixed in Version3.3.1 
Summary0038141: The fpdoc generates docs with a hierarchy problems.
Description1. All classes without a parent are showed as TObject ancestors. For example #rtl.TThread , #rtl.TThreadList, #rtl.TCharacter and many other.
2. All unresolved and undocumented classes also are showed as TObject ancestors ( with mark "?"), may be that is Ok for class discription but the class hierarchy page Looks bad.
3. For the chm files which was produced from rtl.xct - class hierarchy page does not have of links to the #rtl packet classes. The picture is attached.
4. For many classes even of rtl.chm we do not have of links on TObject, For that classes also have been lost methods from TObject on page Class.methods. The picture applied

I want to write a patch for that. I am testing first version now.
Additional Informationrelated issue https://bugs.freepascal.org/view.php?id=38028
TagsNo tags attached.
Fixed in Revision47719
FPCOldBugId
FPCTarget3.2.2
Attached Files

Relationships

related to 0038250 resolvedJuha Manninen Patches Redone of lHelp 

Activities

Andrey Sobol

2020-11-27 20:09

reporter  

Marco van de Voort

2020-11-27 21:31

manager   ~0127215

I can click through the rom eiostreamerror to tobject by clickling the links in the class() and exception() lines. So tracking is possible. I suspect the tree code doesn't trace very well through the fcl->rtl separation

Andrey Sobol

2020-11-27 21:38

reporter   ~0127216

Yes the xct files have wrong data also.

Marco van de Voort

2020-11-27 21:44

manager   ~0127217

Well, xct works at least partially since clicking through class() and exception() links works

Marco van de Voort

2020-11-27 23:11

manager   ~0127218

My guess the problem has to do with dw_html:2425-2435:

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
    else
      P:=Engine.FindElement(EN);
    PushClassElement;

Michael Van Canneyt

2020-11-28 01:03

administrator   ~0127221

What is the problem with point 1 ? That is how it is supposed to be ?

Similar for point 2. If fpdoc works with incomplete information,
There is nothing you can do except attach 'unknown' objects to TObject.
(every object descends from TObject)
 
I don't understand what the pictures are supposed to demonstrate ?

For point 4, the documentation does not show methods from inherited classes, this is by design.
That you cannot click through to some ancestors ?
This is possible if the xct files are missing or incomplete.

Marco van de Voort

2020-11-28 05:14

manager   ~0127222

All the links in the pictures are clickable if you navigate the inheritence by repeatedly clicking on the ancestor in the class(ancestor) declaration

verified with 3.2.0 html (on site) and chm

Andrey Sobol

2020-11-28 09:37

reporter   ~0127225

Last edited: 2020-11-28 10:04

View 2 revisions

Picture 1.
[All the links in the pictures are clickable if you navigate the inheritence by repeatedly clicking on the ancestor in the class(ancestor) declaration]
 - The links work if you is into rtl.chm, but when you into fcl.chm then the links from class hierarchy page to rtl.chm do not work.
- At the same time the links from the class overview page work.
- The TObject link does not work always (from fcl.chm to rtl.chm)

[For point 4, the documentation does not show methods from inherited classes, this is by design.]
- When I have fixed crosslink into cxt files, the method and property pages show all ancestor items.

Picture 2.
- For all chm which use rtl.xct and other xct.

When I'll have the LCL.chm sample then you decide to do so or not.

Michael Van Canneyt

2020-11-28 10:42

administrator   ~0127229

Last edited: 2020-11-28 10:43

View 2 revisions

OK, so the point is that the .xct info is not always correctly processed (or generated) ?
That can be.

As it happens, I am working on the documentation engine (for other things).
I alread noticed that the makefile first generated the fcl and then only the rtl documentation.
This is of course wrong and must be corrected, I still need to check why this happens.

The method/property pages I never use, so quite possibly I didn't notice they're supposed to have all methods...

If you find bugs in the xct handling and have a patch, I will gladly apply it.

Thank you for looking into this !

Marco van de Voort

2020-11-29 13:05

manager   ~0127255

I suspect it is the findelement in dw_html.inc:2434 (createclasshierarcypage), and think it should be a resolve variant (that also checks between packages).

Andrey Sobol

2020-11-30 19:14

reporter   ~0127272

Hello, Marco
- attached patch
- attached description
- link to test files https://drive.google.com/file/d/1f08ONIZ-lJFadOWG8tk_gLPIwLdEE-WG/view?usp=sharing

Andrey.
patch_fpdoc_01.patch (48,435 bytes)   
Index: packages/chm/src/chmwriter.pas
===================================================================
--- packages/chm/src/chmwriter.pas	(revision 47408)
+++ packages/chm/src/chmwriter.pas	(working copy)
@@ -1664,14 +1664,15 @@
 
 procedure TChmWriter.CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec);
 var
-    TopicEntry: TTopicEntry;
-    ATitle: String;
+  TopicEntry: TTopicEntry;
+  ATitle: String;
 begin
-  if Pos('.ht', AFileEntry.Name) > 0 then
+  // Exclude Full text index for files starting from the dot
+  if (Pos('.', AFileEntry.Name) <> 1) and (Pos('.ht', AFileEntry.Name) > 0) then
   begin
     ATitle := FIndexedFiles.IndexFile(AStream, NextTopicIndex, FSearchTitlesOnly);
     AddTopic(ATitle,AFileEntry.Path+AFileEntry.Name,-1);
- end;
+  end;
 end;
 
 function TChmWriter.AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer;
@@ -1690,7 +1691,7 @@
     TopicEntry.URLTableOffset := AddURL(AnUrl, Result);
     if code=-1 then
       begin
-       if ATitle<>'' then
+       if Trim(ATitle) <> '' then
          TopicEntry.InContents := 6
        else
          TopicEntry.InContents := 2;
@@ -1720,8 +1721,8 @@
    ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]);
 
   // adhoc subsitutions. Replace with real code if exact behaviour is known.
-{  Atitle:=StringReplace(atitle, '&x27;', '''', [rfReplaceAll]);
-  if length(atitle)>0 then
+{  Atitle:=StringReplace(Atitle, '&x27;', '''', [rfReplaceAll]);
+  if length(Trim(Atitle))>0 then
     atitle[1]:=uppercase(atitle[1])[1];}
   {$ifdef binindex}
   writeln('Enter ',ATitle,' ',AnUrl);
@@ -1732,11 +1733,11 @@
        writeln('found:',result);
      {$endif}
    end
-   else
-    begin
-      result:=addtopic(atitle,anurl);
-      FDictTopicsUrlInd.add(anurl,result);
-    end;
+   else if Trim(ATitle) <> '' then
+      begin
+        result:=addtopic(ATitle,AnUrl);
+        FDictTopicsUrlInd.add(AnUrl,result);
+      end;
 end;
 
 procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap);
Index: utils/fpdoc/dglobals.pp
===================================================================
--- utils/fpdoc/dglobals.pp	(revision 47408)
+++ utils/fpdoc/dglobals.pp	(working copy)
@@ -36,9 +36,12 @@
 resourcestring
   // Output strings
   SDocPackageTitle           = 'Reference for package ''%s''';
+  SDocPackageMenuTitle       = 'Menu for package ''%s''';
+  SDocPackageLinkTitle       = 'Package';
   SDocPrograms               = 'Programs';
   SDocUnits                  = 'Units';
   SDocUnitTitle              = 'Reference for unit ''%s''';
+  SDocUnitMenuTitle          = 'Menu for unit ''%s''';
   SDocInheritanceHierarchy   = 'Inheritance Hierarchy';
   SDocInterfaceSection       = 'Interface section';
   SDocImplementationSection  = 'Implementation section';
@@ -52,7 +55,9 @@
   SDocProceduresAndFunctions = 'Procedures and functions';
   SDocVariables              = 'Variables';
   SDocIdentifierIndex        = 'Index';
-  SDocPackageClassHierarchy  = 'Class hierarchy';
+  SDocPackageClassHierarchy  = 'Classes hierarchy';
+  SDocPackageTObjectHierarchy = 'Hierarchy of TObject classes';
+  SDocPackageSimpleHierarchy = 'Hierarchy of simple classes';
   SDocModuleIndex            = 'Index of all identifiers in unit ''%s''';
   SDocPackageIndex           = 'Index of all identifiers in package ''%s''';
   SDocUnitOverview           = 'Overview of unit ''%s''';
@@ -317,9 +322,9 @@
     FAlwaysVisible : TStringList;
     DescrDocs: TObjectList;             // List of XML documents
     DescrDocNames: TStringList;         // Names of the XML documents
-    FRootLinkNode: TLinkNode;
-    FRootDocNode: TDocNode;
-    FPackages: TFPList;                   // List of TFPPackage objects
+    FRootLinkNode: TLinkNode;           // Global tree of TlinkNode from the imported .xct files
+    FRootDocNode: TDocNode;             // Global tree of TDocNode from the .xml documentation files
+    FPackages: TFPList;                 // Global list of TPasPackage objects and full tree of sources
     CurModule: TPasModule;
     CurPackageDocNode: TDocNode;
     function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual;
@@ -336,7 +341,9 @@
     constructor Create;
     destructor Destroy; override;
     procedure SetPackageName(const APackageName: String);
+    // process the import objects from external .xct file
     procedure ReadContentFile(const AFilename, ALinkPrefix: String);
+    // creation of an own .xct output file
     procedure WriteContentFile(const AFilename: String);
 
     function CreateElement(AClass: TPTreeElement; const AName: String;
@@ -343,6 +350,7 @@
       AParent: TPasElement; AVisibility: TPasMemberVisibility;
       const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
       override;
+    function FindInModule(const AName: String ; AModule: TPasModule): TPasElement;
     function FindElement(const AName: String): TPasElement; override;
     function FindModule(const AName: String): TPasModule; override;
     Function HintsToStr(Hints : TPasMemberHints) : String;
@@ -658,7 +666,9 @@
 procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
 var
   f: Text;
-  inheritanceinfo : TStringlist;
+  inheritanceinfo : TStringlist; // contents list of TPasClass with inheritance info
+                                 // like this #PackageName.ModuleName.ClassName
+  tmpLinkPrefix : string;
 
   procedure ReadLinkTree;
   var
@@ -706,8 +716,10 @@
       i := ThisSpaces + 1;
       while s[i] <> ' ' do
         Inc(i);
+      if ALinkPrefix <> '' then
+        tmpLinkPrefix := ExcludeTrailingPathDelimiter(ALinkPrefix)+'/';
       NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
-        ALinkPrefix + Copy(s, i + 1, Length(s)));
+        tmpLinkPrefix + Copy(s, i + 1, Length(s)));
       if pos(' ',newnode.link)>0 then
         writeln(stderr,'Bad format imported node: name="',newnode.name,'" link="',newnode.link,'"');
       if Assigned(PrevSibling) then
@@ -719,56 +731,56 @@
   end;
 
   function ResolvePackageModule(AName:String;out pkg:TPasPackage;out module:TPasModule;createnew:boolean):String;
-    var
-      DotPos, DotPos2, i: Integer;
-      s: String;
-      HPackage: TPasPackage;
+  var
+    DotPos, DotPos2, i: Integer;
+    s: String;
+    HPackage: TPasPackage;
 
-    begin
-      pkg:=nil; module:=nil; result:='';
+  begin
+    pkg:=nil; module:=nil; result:='';
 
-      // Find or create package
-      DotPos := Pos('.', AName);
-      s := Copy(AName, 1, DotPos - 1);
-      HPackage := nil;
-      for i := 0 to FPackages.Count - 1 do
-        if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
-        begin
-          HPackage := TPasPackage(FPackages[i]);
-          break;
-        end;
-      if not Assigned(HPackage) then
+    // Find or create package
+    DotPos := Pos('.', AName);
+    s := Copy(AName, 1, DotPos - 1);
+    HPackage := nil;
+    for i := 0 to FPackages.Count - 1 do
+      if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
       begin
-        if not CreateNew then
-          exit;
-        HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
-          '', 0));
-        FPackages.Add(HPackage);
+        HPackage := TPasPackage(FPackages[i]);
+        break;
       end;
+    if not Assigned(HPackage) then
+    begin
+      if not CreateNew then
+        exit;
+      HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
+        '', 0));
+      FPackages.Add(HPackage);
+    end;
 
-      // Find or create module
-      DotPos2 := DotPos;
-      repeat
-        Inc(DotPos2);
-      until AName[DotPos2] = '.';
-      s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
-      Module := nil;
-      for i := 0 to HPackage.Modules.Count - 1 do
-        if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
-        begin
-          Module := TPasModule(HPackage.Modules[i]);
-          break;
-        end;
-      if not Assigned(Module) then
+    // Find or create module
+    DotPos2 := DotPos;
+    repeat
+      Inc(DotPos2);
+    until AName[DotPos2] = '.';
+    s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
+    Module := nil;
+    for i := 0 to HPackage.Modules.Count - 1 do
+      if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
       begin
-        if not CreateNew then
-          exit;
-        Module := TPasExternalModule.Create(s, HPackage);
-        Module.InterfaceSection := TInterfaceSection.Create('', Module);
-        HPackage.Modules.Add(Module);
+        Module := TPasModule(HPackage.Modules[i]);
+        break;
       end;
-     pkg:=hpackage;
-     result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2);
+    if not Assigned(Module) then
+    begin
+      if not CreateNew then
+        exit;
+      Module := TPasExternalModule.Create(s, HPackage);
+      Module.InterfaceSection := TInterfaceSection.Create('', Module);
+      HPackage.Modules.Add(Module);
+    end;
+    pkg:=hpackage;
+    result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2);
   end;
 
   function SearchInList(clslist:TFPList;s:string):TPasElement;
@@ -832,9 +844,9 @@
         InheritanceInfo.AddObject(Inheritancestr,result);
     end;
 
-   procedure splitalias(var instr:string;out outstr:string);
-   var i,j:integer;
-   begin 
+    procedure splitalias(var instr:string;out outstr:string);
+    var i,j:integer;
+    begin
      if length(instr)=0 then exit;
      instr:=trim(instr);
      i:=pos('(',instr);
@@ -846,10 +858,10 @@
         outstr:=copy(instr,i+1,j);
         delete(instr,i,j+2);
       end
-   end;
+    end;
 
-   Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType;
-   begin
+    Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType;
+    begin
      result:=TPasClassType(ResolveClassType(clname)); 
      if assigned(result) and not (cls=result) then  // save from tobject=implicit tobject
        begin
@@ -868,47 +880,47 @@
      else
        if cls<>result then
          DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]);
-end;
+    end;
 
-function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType;
-// create alias clname =  alname
-var 
-  pkg     : TPasPackage;
-  module  : TPasModule; 
-  s       : string;  
-begin
-    Result:=nil;
-    s:=ResolvePackageModule(Alname,pkg,module,True);
-    if not assigned(module) then
-      exit;
-    cl2:=TPasClassType(ResolveClassType(alname));
-    if assigned( cl2) and not (parentclass=cl2) then  
-      begin
-        result:=ResolveAliasType(clname);
-        if assigned(result) then
+    function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType;
+    // create alias clname =  alname
+    var
+      pkg     : TPasPackage;
+      module  : TPasModule;
+      s       : string;
+    begin
+        Result:=nil;
+        s:=ResolvePackageModule(Alname,pkg,module,True);
+        if not assigned(module) then
+          exit;
+        cl2:=TPasClassType(ResolveClassType(alname));
+        if assigned( cl2) and not (parentclass=cl2) then  
           begin
-//            writeln('found alias ',clname,' (',s,') ',result.classname);  
+            result:=ResolveAliasType(clname);
+            if assigned(result) then
+              begin
+    //            writeln('found alias ',clname,' (',s,') ',result.classname);
+              end
+            else
+              begin
+    //            writeln('new alias ',clname,' (',s,') ');
+                cl2.addref;
+                Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0));
+                module.interfacesection.Declarations.Add(Result);
+                TPasAliasType(Result).DestType := cl2;
+              end
           end
-        else
-          begin
-//            writeln('new alias ',clname,' (',s,') ');
-            cl2.addref;
-            Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0));
-            module.interfacesection.Declarations.Add(Result);
-            TPasAliasType(Result).DestType := cl2;
-          end
-      end
-end;
+    end;
 
-   procedure ProcessInheritanceStrings(inhInfo:TStringList);
+    procedure ProcessInheritanceStrings(inhInfo:TStringList);
 
-   var i,j : integer;
-       cls : TPasClassType;  
+    var i,j : integer;
+       cls : TPasClassType;
        cls2: TPasClassType;
        clname,
        alname : string;
        inhclass   : TStringList;
-   begin
+    begin
      inhclass:=TStringList.Create;
      inhclass.delimiter:=',';
      if InhInfo.Count>0 then
@@ -920,12 +932,12 @@
 
            for j:= 0 to inhclass.count-1 do
              begin
-               //writeln('processing',inhclass[j]);
+               // writeln('processing',inhclass[j]);
                clname:=inhclass[j];
-               splitalias(clname,alname);               
+               splitalias(clname,alname);
                if alname<>'' then // the class//interface we refered to is an alias
                  begin
-                   // writeln('Found alias pair ',clname,' = ',alname);   
+                   // writeln('Found alias pair ',clname,' = ',alname);
                    if not assigned(CreateAliasType(alname,clname,cls,cls2)) then
                       DoLog('Warning: creating alias %s for %s failed!',[alname,clname]);
                  end 
@@ -934,7 +946,7 @@
              end;
          end;
     inhclass.free;
-   end;
+    end;
 
   var
     s, Name: String;
@@ -991,10 +1003,10 @@
           CurClass.Members.Add(Member);
         end;
       end;
-     ProcessInheritanceStrings(Inheritanceinfo);
+      ProcessInheritanceStrings(Inheritanceinfo);
     finally
-     inheritanceinfo.Free;
-     end;
+      inheritanceinfo.Free;
+    end;
   end;
 
 var
@@ -1042,11 +1054,13 @@
     end;
   end;
 
-  function CheckImplicitInterfaceLink(const s : String):String;
+  function CheckImplicitLink(const s : String):String;
   begin
-   if uppercase(s)='IUNKNOWN' then
+    if uppercase(s)='IUNKNOWN' then
      Result:='#rtl.System.IUnknown'
-   else 
+    else if uppercase(s)='TOBJECT' then
+     Result:='#rtl.System.TObject'
+   else
      Result:=s;
   end;
 var
@@ -1089,11 +1103,11 @@
       for j := 0 to Module.InterfaceSection.Classes.Count - 1 do
       begin
         ClassDecl := TPasClassType(Module.InterfaceSection.Classes[j]);
-        Write(ContentFile, CheckImplicitInterfaceLink(ClassDecl.PathName), ' ');
-        if Assigned(ClassDecl.AncestorType) then 
+        Write(ContentFile, CheckImplicitLink(ClassDecl.PathName), ' ');
+        if Assigned(ClassDecl.AncestorType) then // and (ClassDecl.ObjKind <> okClass) then
           begin
              // simple aliases to class types are coded as "alias(classtype)"
-             Write(ContentFile, CheckImplicitInterfaceLink(ClassDecl.AncestorType.PathName));
+             Write(ContentFile, CheckImplicitLink(ClassDecl.AncestorType.PathName));
              if ClassDecl.AncestorType is TPasAliasType then
                begin
                  alias:= TPasAliasType(ClassDecl.AncestorType);
@@ -1102,19 +1116,20 @@
                end;
           end
         else if ClassDecl.ObjKind = okClass then
-          Write(ContentFile, '#rtl.System.TObject')
+          //Write(ContentFile, '@NO_ANCESTOR_CLASS')
         else if ClassDecl.ObjKind = okInterface then
-          Write(ContentFile, '#rtl.System.IUnknown');
+          //Write(ContentFile, '@NO_ANCESTOR_INTERFACE')
+          ;
         if ClassDecl.Interfaces.Count>0 then
           begin
             for k:=0 to ClassDecl.Interfaces.count-1 do
               begin
-                write(contentfile,',',CheckImplicitInterfaceLink(TPasClassType(ClassDecl.Interfaces[k]).PathName));
+                write(contentfile,',',CheckImplicitLink(TPasClassType(ClassDecl.Interfaces[k]).PathName));
                 if TPasElement(ClassDecl.Interfaces[k]) is TPasAliasType then
                   begin
                     alias:= TPasAliasType(ClassDecl.Interfaces[k]);
                     if assigned(alias.desttype) and (alias.desttype is TPasClassType) then
-                      write(ContentFile,'(',CheckImplicitInterfaceLink(alias.desttype.PathName),')');   
+                      write(ContentFile,'(',CheckImplicitLink(alias.desttype.PathName),')');
                   end;
               end;
           end;
@@ -1163,34 +1178,34 @@
   Result.SourceLinenumber := ASourceLinenumber;
 end;
 
-function TFPDocEngine.FindElement(const AName: String): TPasElement;
+function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule
+  ) : TPasElement;
+var
+  l: TFPList;
+  i: Integer;
 
-  function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
-  
-  var
-    l: TFPList;
-    i: Integer;
-    
-  begin
-    If assigned(AModule.InterfaceSection) and 
-       Assigned(AModule.InterfaceSection.Declarations) then
+begin
+  If Assigned(AModule) and Assigned(AModule.InterfaceSection) and
+     Assigned(AModule.InterfaceSection.Declarations) then
+    begin
+    l:=AModule.InterfaceSection.Declarations;
+    for i := 0 to l.Count - 1 do
       begin
-      l:=AModule.InterfaceSection.Declarations;
-      for i := 0 to l.Count - 1 do
-        begin
-        Result := TPasElement(l[i]);
-        if  CompareText(Result.Name, LocalName) = 0 then
-          exit;
-        end;
-      end;  
-    Result := nil;
- end;
+      Result := TPasElement(l[i]);
+      if CompareText(Result.Name, AName) = 0 then
+        exit;
+      end;
+    end;
+  Result := nil;
+end;
 
+function TFPDocEngine.FindElement(const AName: String): TPasElement;
+
 var
   i: Integer;
   Module: TPasElement;
 begin
-  Result := FindInModule(CurModule, AName);
+  Result := FindInModule( AName, CurModule );
   if not Assigned(Result) and assigned (CurModule.InterfaceSection) then
     for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
     begin
@@ -1197,7 +1212,7 @@
       Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
       if Module.ClassType.InheritsFrom(TPasModule) then
       begin
-        Result := FindInModule(TPasModule(Module), AName);
+        Result := FindInModule(AName, TPasModule(Module));
         if Assigned(Result) then
           exit;
       end;
Index: utils/fpdoc/dw_html.pp
===================================================================
--- utils/fpdoc/dw_html.pp	(revision 47408)
+++ utils/fpdoc/dw_html.pp	(working copy)
@@ -231,7 +231,8 @@
     procedure CreatePackagePageBody;
     procedure CreatePackageIndex;
     procedure CreatePackageClassHierarchy;
-    procedure CreateClassHierarchyPage(AList: TStringList; AddUnit : Boolean);
+    procedure CreateClassHierarchyPage(AList:TStringList ; ClassTree :TDOMElement;
+                                  ShowRoot : Boolean);
     procedure AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
     Procedure CreateTopicPageBody(AElement : TTopicElement);
     procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer);
@@ -245,6 +246,7 @@
     procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False);
     procedure AppendTypeDecl(AType: TPasType; TableEl, CodeEl: TDomElement);
   public
+    // Creating all module hierarchy classes is here !!!!
     constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
     destructor Destroy; override;
 
@@ -252,7 +254,7 @@
     function CreateHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument;
     function CreateXHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument;
 
-    // For producing complete package documentation
+    // Start producing html complete package documentation
     procedure WriteHTMLPages; virtual;
     procedure WriteXHTMLPages;
     function  ModuleForElement(AnElement:TPasElement):TPasModule;
@@ -282,6 +284,7 @@
 implementation
 
 uses SysUtils, XMLRead, HTMWrite, sh_pas, fpdocclasstree,
+//  XMLWrite,
   chmsitemap;
 
 {$i css.inc}
@@ -324,13 +327,20 @@
 var
   n,s: String;
   i: Integer;
-
+  excl: Boolean; //search
 begin
   Result:='';
+  excl := False;
   if AElement.ClassType = TPasPackage then
-    Result := 'index'
+  begin
+    Result := 'index';
+    excl := True;
+  end
   else if AElement.ClassType = TPasModule then
-    Result := LowerCase(AElement.Name) + PathDelim + 'index'
+  begin
+    Result := LowerCase(AElement.Name) + PathDelim + 'index';
+    excl := True;
+  end
   else
   begin
     if AElement is TPasOperator then
@@ -359,8 +369,12 @@
       if (N<>'') and  (N[1]=':') then
         Delete(N,1,1);
       Result:=Result + '-'+ s + '-' + N;
-    end else
+    end
+      else
+    begin
       Result := LowerCase(AElement.PathName);
+      excl := (ASubindex > 0);
+    end;
     // searching for TPasModule - it is on the 2nd level
     if Assigned(AElement.Parent) then
       while Assigned(AElement.Parent.Parent) do
@@ -373,6 +387,14 @@
       Inc(i);
     if (i <= Length(Result)) and (i > 0) then
       Result[i] := PathDelim;
+    if excl or (Length(Result)=0) then
+      begin
+        // exclude the from full text search index
+        s:= '.'+ExtractFileName(Result + '.');
+        n:= ExtractFileDir(Result);
+        Result := n + DirectorySeparator + s;
+        Result := Copy(Result, 1, Length(Result)-1);
+      end;
   end;
 
   if ASubindex > 0 then
@@ -769,6 +791,7 @@
         Filename := Engine.Output + Allocator.GetFilename(Element, SubpageIndex);
         try
           CreatePath(Filename);
+          //writeln('Element: ',Element.PathName, ' FileName: ', Filename);
           WriteHTMLFile(PageDoc, Filename);
         except
           on E: Exception do
@@ -1532,7 +1555,8 @@
   end;
 end;
 
-Procedure THTMLWriter.AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode : TDocNode);
+procedure THTMLWriter.AppendShortDescr ( AContext: TPasElement;
+  Parent: TDOMNode; DocNode: TDocNode ) ;
 
 Var
   N : TDocNode;
@@ -2081,7 +2105,7 @@
 procedure THTMLWriter.AppendMenuBar(ASubpageIndex: Integer);
 
 var
-  TableEl, TREl, ParaEl, TitleEl: TDOMElement;
+  TableEl, TREl, TRE2, ParaEl, TitleEl: TDOMElement;
 
   procedure AddLink(ALinkSubpageIndex: Integer; const AName: String);
   begin
@@ -2118,9 +2142,34 @@
   TableEl['border'] := '0';
   TableEl['width'] := '100%';
   TableEl['class'] := 'bar';
+  // Title Row
   TREl := CreateTR(TableEl);
-  ParaEl := CreateEl(CreateTD(TREl), 'b');
+  // Menu title
+  ParaEl := CreateTD(TREl);
+  ParaEl['align'] := 'left';
+  TitleEl := CreateEl(ParaEl, 'span');
+  TitleEl['class'] := 'bartitle';
+  if Assigned(Module) then
+    AppendText(TitleEl, Format(SDocUnitMenuTitle, [Module.Name]))
+  else
+    AppendText(TitleEl, Format(SDocPackageMenuTitle, [Package.Name]));
 
+  // Package link title
+  ParaEl := CreateTD(TREl);
+  ParaEl['align'] := 'right';
+  TitleEl := CreateEl(ParaEl, 'span');
+  TitleEl['class'] := 'bartitle';
+  if Assigned(Module) and Assigned(Package) then // Displays a Package page
+  begin
+    AppendText(TitleEl, SDocPackageLinkTitle);
+  end;
+
+  // Links Row
+  TRE2 := CreateTR(TableEl);
+  ParaEl := CreateTD(TRE2);
+  ParaEl['align'] := 'left';
+  ParaEl := CreateEl(ParaEl, 'b');
+
   if Assigned(Module) then
     begin
     AddLink(0, SDocOverview);
@@ -2140,7 +2189,13 @@
     end
   else
     begin
+    // Overview
+    AppendText(ParaEl, '[');
+    AppendHyperlink(ParaEl, Package).TextContent:= UTF8Decode(SDocOverview);
+    AppendText(ParaEl, ']');
+    //Index
     AddPackageLink(IndexSubIndex, SDocIdentifierIndex);
+    // Class TObject tree
     AddPackageLink(ClassHierarchySubIndex, SDocPackageClassHierarchy);
     end;
 
@@ -2152,18 +2207,17 @@
     if FUseMenuBrackets then
       AppendText(ParaEl, ']');
   end;
-  ParaEl := CreateTD(TREl);
+
+  ParaEl := CreateTD(TRE2);
   ParaEl['align'] := 'right';
-  TitleEl := CreateEl(ParaEl, 'span');
-  TitleEl['class'] := 'bartitle';
-  if Assigned(Module) then
-    AppendText(TitleEl, Format(SDocUnitTitle, [Module.Name]));
-  if Assigned(Package) then
+  ParaEl := CreateEl(ParaEl, 'b');
+  if Assigned(Module) and Assigned(Package) then // Displays a Package page
   begin
-    AppendText(TitleEl, ' (');
-    AppendHyperlink(TitleEl, Package);
-    AppendText(TitleEl, ')');
+    AppendText(ParaEl, '[');
+    AppendHyperlink(ParaEl, Package);
+    AppendText(ParaEl, ']');
   end;
+
 end;
 
 procedure THTMLWriter.AppendSourceRef(AElement: TPasElement);
@@ -2172,7 +2226,8 @@
     [ExtractFileName(AElement.SourceFilename), AElement.SourceLinenumber]));
 end;
 
-Procedure THTMLWriter.AppendSeeAlsoSection(AElement : TPasElement;DocNode : TDocNode);
+procedure THTMLWriter.AppendSeeAlsoSection ( AElement: TPasElement;
+  DocNode: TDocNode ) ;
 
 var
   Node: TDOMNode;
@@ -2246,7 +2301,8 @@
      end; // While
 end;
 
-Procedure THTMLWriter.AppendExampleSection(AElement : TPasElement;DocNode : TDocNode);
+procedure THTMLWriter.AppendExampleSection ( AElement: TPasElement;
+  DocNode: TDocNode ) ;
 
 var
   Node: TDOMNode;
@@ -2367,7 +2423,8 @@
     end;
 end;
 
-procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Boolean);
+procedure THTMLWriter.CreateClassHierarchyPage ( AList: TStringList;
+  ClassTree: TDOMElement; ShowRoot: Boolean ) ;
 
   Procedure PushClassElement;
 
@@ -2395,7 +2452,7 @@
     PushOutputNode(h);
   end;
 
-  Procedure AppendClass(E : TDomElement);
+  Procedure AppendClass(E : TDomElement; Level: Integer);
 
   Var
     N : TDomNode;
@@ -2405,27 +2462,34 @@
     I,J : Integer;
 
   begin
+    if not Assigned(E) then exit;
+    //WriteLn('>> AppendClass NodeName = ',E.NodeName);
     EN:=Package.Name+'.'+UTF8Encode(E['unit'])+'.'+UTF8Encode(E.NodeName);
     J:=AList.IndexOf(EN);
     If J<>-1 then
       P:=AList.Objects[J] as TPasElement
     else
-      P:=Engine.FindElement(EN);
-    PushClassElement;
+      P:=Engine.FindInModule(UTF8Encode(E.NodeName),
+                       Engine.FindModule(UTF8Encode(E['unit'])));
     try
-      if (P<>Nil) then
+      inc(Level);
+      if Level > 0 then
         begin
-        AppendHyperLink(CurOutputNode,P);
-        PM:=ModuleForElement(P);
-        if (PM<>Nil) then
-          begin
-          AppendText(CurOutputNode,' (');
-          AppendHyperLink(CurOutputNode,PM);
-          AppendText(CurOutputNode,')');
-          end
-        end
-      else
-        AppendText(CurOutputNode,E.Nodename);
+          PushClassElement;
+          if (P<>Nil) then
+            begin
+            AppendHyperLink(CurOutputNode,P);
+            PM:=ModuleForElement(P);
+            if (PM<>Nil) then
+              begin
+              AppendText(CurOutputNode,' (');
+              AppendHyperLink(CurOutputNode,PM);
+              AppendText(CurOutputNode,')');
+              end
+            end
+          else
+            AppendText(CurOutputNode,E.Nodename);
+        end;
       LL:=TStringList.Create;
       try
         N:=E.FirstChild;
@@ -2436,48 +2500,39 @@
           N:=N.NextSibling;
           end;
         if (LL.Count>0) then
-          begin
+        begin
           LL.Sorted:=true;
           PushClassList;
           try
             For I:=0 to LL.Count-1 do
-              AppendClass(LL.Objects[i] as TDomElement);
+              AppendClass(LL.Objects[i] as TDomElement, Level);
           finally
-            PopOutputNode;
+            PopOutputNode; // classlist
           end;
-          end;
+        end;
       finally
         LL.Free;
       end;
     Finally
-      PopOutputNode;
+      if Level > 0 then PopOutputNode; // classelement
+      Dec(Level);
     end;
+    //WriteLn('<< AppendClass NodeName = ',E.NodeName);
   end;
-
-Var
-  B : TClassTreeBuilder;
-  E : TDomElement;
+var
+  lev: Integer;
 begin
-  PushOutputNode(BodyElement);
+  lev:= -1;
+  if ShowRoot then lev:= 0;
   try
-    B:=TClassTreeBuilder.Create(Package,okClass);
+    if lev = 0 then PushClassList;
     try
-      B.BuildTree(AList);
-      // Classes
-      // WriteXMLFile(B.ClassTree,'tree.xml');
-      // Dummy TObject
-      E:=B.ClassTree.DocumentElement;
-      PushClassList;
-      try
-        AppendClass(E);
-      finally
-        PopOutputNode;
-      end;
+      AppendClass(ClassTree, lev);
     finally
-      B.Free;
+      //PopOutputNode;
     end;
   finally
-    PopOutputNode;
+    if lev = 0 then PopOutputNode; //classlist
   end;
 end;
 
@@ -2496,6 +2551,8 @@
   M : TPasModule;
   S : String;
   SE : THTMLElement;
+  B : TClassTreeBuilder;
+  E : TDomElement;
 
 begin
   SE := Doc.CreateElement('script');
@@ -2514,8 +2571,30 @@
     S:=Package.Name;
     If Length(S)>0 then
       Delete(S,1,1);
-    AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S])));
-    CreateClassHierarchyPage(L,True);
+    try
+      B:=TClassTreeBuilder.Create(Package,okClass);
+      try
+        PushOutputNode(BodyElement);
+        B.BuildTree(L);
+        // Classes
+        //WriteXMLFile(B.ClassTree,'tree.xml');
+        // Dummy TObject
+        //AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S])));
+        AppendTitle(UTF8Decode(SDocPackageTObjectHierarchy));
+        E:=B.ClassTreeTObject;
+        // TObject Tree
+        CreateClassHierarchyPage(L,E, True);
+        // Simple Tree
+        //AppendTitle(UTF8Decode(Format(SDocPackageSimpleHierarchy, [S])));
+        AppendTitle(UTF8Decode(SDocPackageSimpleHierarchy));
+        E:=B.ClassTreeSimple;
+        CreateClassHierarchyPage(L,E, False);
+      finally
+        PopOutputNode;
+      end;
+    finally
+      B.Free;
+    end;
   Finally
     L.Free;
   end;
@@ -2664,7 +2743,8 @@
   end;  
 end;
 
-Procedure THTMLWriter.AddElementsFromList(L : TStrings; List : TFPList; UsePathName : Boolean = False);
+procedure THTMLWriter.AddElementsFromList ( L: TStrings; List: TFPList;
+  UsePathName: Boolean ) ;
 
 Var
   I : Integer;
@@ -2774,7 +2854,8 @@
     end;
 end;
 
-Procedure THTMLWriter.CreateTopicLinks(Node : TDocNode; PasElement : TPasElement);
+procedure THTMLWriter.CreateTopicLinks ( Node: TDocNode;
+  PasElement: TPasElement ) ;
 
 var
   DocNode: TDocNode;
@@ -3342,10 +3423,12 @@
     i: Integer;
     ThisInterface,
     ThisClass: TPasClassType;
-    HaveSeenTObject: Boolean;
+    SeenFullTree: Boolean;
     LName     : String;
+    LastClassName: String;
     ThisNode  : TPasUnresolvedTypeRef;
   begin
+    //WriteLn('@ClassPageBody.CreateMainPage Class=', AClass.Name);
     AppendMenuBar(-1);
     AppendTitle(UTF8Decode(AClass.Name),AClass.Hints);
 
@@ -3389,14 +3472,12 @@
     end;
     CreateMemberDeclarations(AClass, AClass.Members,TableEl, not AClass.IsShortDefinition);
 
-
-
     AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance));
     TableEl := CreateTable(BodyElement);
-    HaveSeenTObject := AClass.ObjKind <> okClass;
+    SeenFullTree := AClass.ObjKind <> okClass;
     // we try to track classes. But imported classes
     // are TLinkNode's not the TPasClassType generated by the parser.
-    ThisClass := AClass; ThisNode := Nil;
+    ThisClass := AClass; ThisNode := Nil; LastClassName := '';
     while True do
     begin
       TREl := CreateTR(TableEl);
@@ -3407,10 +3488,12 @@
         LName:=ThisClass.Name
       Else
         LName:=ThisNode.Name;
+      // add link to class hierarchy
       if Assigned(ThisClass) Then
         AppendHyperlink(CodeEl, ThisClass)
       else
         AppendHyperlink(CodeEl, ThisNode);
+      // link to class interfaces
       if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then
         begin
           for i:=0 to ThisClass.interfaces.count-1 do
@@ -3420,48 +3503,73 @@
               AppendHyperlink(CodeEl, ThisInterface);
             end;
         end;
-      AppendShortDescrCell(TREl, ThisClass);
-      if HaveSeenTObject or (CompareText(LName, 'TObject') = 0) then
-        HaveSeenTObject := True
-      else
-      begin
-        TDEl := CreateTD(CreateTR(TableEl));
-        TDEl['align'] := 'center';
-        AppendText(TDEl, '|');
-      end;
+      // short class description
+      if Assigned(ThisClass) then
+            AppendShortDescrCell(TREl, ThisClass);
 
-      if Assigned(ThisClass.AncestorType) then
-      begin
-        if ThisClass.AncestorType.InheritsFrom(TPasClassType) then
-          ThisClass := TPasClassType(ThisClass.AncestorType)
-        else
+      if Assigned(ThisClass) then
         begin
-          if thisclass.ancestortype is TPasUnresolvedTypeRef then
-            thisnode:=TPasUnresolvedTypeRef(ThisClass.ancestortype);
-          TDEl := CreateTD(CreateTR(TableEl));
-          TDEl['align'] := 'center';
-          AppendText(CreateCode(CreatePara(TDEl)), UTF8Decode(ThisClass.AncestorType.Name));
-          if CompareText(ThisClass.AncestorType.Name, 'TObject') = 0 then
-            HaveSeenTObject := True
-          else
+          if Assigned(ThisClass.AncestorType) then
           begin
             TDEl := CreateTD(CreateTR(TableEl));
             TDEl['align'] := 'center';
-            AppendText(TDEl, '?');
+            AppendText(TDEl, '|');
+            if ThisClass.AncestorType.InheritsFrom(TPasClassType) then
+               begin
+                 ThisClass := TPasClassType(ThisClass.AncestorType);
+                 ThisNode := nil;
+               end
+            else if ThisClass.ancestortype is TPasUnresolvedTypeRef then
+              begin
+                ThisNode:=TPasUnresolvedTypeRef(ThisClass.ancestortype);
+                ThisClass := nil;
+              end
+            else if ThisClass.ancestortype is TPasAliasType then
+              begin
+                LastClassName := TPasAliasType(ThisClass.AncestorType).ElementTypeName;
+                SeenFullTree := false;
+                break; // end class tree
+              end
+            else
+            begin
+              LastClassName := 'UNRESOLVED CLASS';
+              SeenFullTree := false;
+              break; // end class tree
+            end;
+          end
+            else
+          begin
+            SeenFullTree := true;
+            break; // end class tree
           end;
-          break;
         end
-      end else
-        break;
+      else if Assigned(ThisNode) then
+        begin
+          if Assigned(ThisNode.Parent) then
+          begin
+            ThisNode := TPasUnresolvedTypeRef(ThisNode.Parent);
+            ThisClass := nil;
+          end
+            else
+          begin
+            SeenFullTree := Pos(UpperCase(ThisNode.Name), 'TOBJECT') = 1; // last ClassName was TObject
+            break; // end class node
+          end;
+        end;
     end;
-
-    if not HaveSeenTObject then
-    begin
+    if not SeenFullTree then
+    begin  // we suggest that last parent is TObject
       TDEl := CreateTD(CreateTR(TableEl));
       TDEl['align'] := 'center';
-      AppendText(CreateCode(CreatePara(TDEl)), 'TObject');
+      if Length(LastClassName)=0 then
+        AppendText(TDEl, '?');
+      TDEl := CreateTD(CreateTR(TableEl));
+      TDEl['align'] := 'center';
+      if Length(LastClassName)>0 then
+        AppendText(CreateCode(CreatePara(TDEl)),LastClassName)
+      else
+        AppendText(CreateCode(CreatePara(TDEl)), 'TObject');
     end;
-
     FinishElementPage(AClass);
   end;
 
@@ -3838,7 +3946,7 @@
   FinishElementPage(AProc);
 end;
 
-Function THTMLWriter.InterPretOption(Const Cmd,Arg : String) : boolean;
+function THTMLWriter.InterPretOption ( const Cmd, Arg: String ) : boolean;
 
 begin
   Result:=True;
@@ -3907,7 +4015,7 @@
     end;
 end;
 
-Class Function THTMLWriter.FileNameExtension : String; 
+class function THTMLWriter.FileNameExtension: String;
 begin
   result:='';
 end;
Index: utils/fpdoc/dw_txt.pp
===================================================================
--- utils/fpdoc/dw_txt.pp	(revision 47408)
+++ utils/fpdoc/dw_txt.pp	(working copy)
@@ -158,18 +158,19 @@
 
 Var
   I,L : Integer;
-
+  SP: set of char;
 begin
   Result:=0;
+  SP := [#10,#13,' ',#9];
   I:=P;
   L:=Length(S);
-  While (I>0) and (I<=L) and not (S[i] in [#10,#13,' ',#9]) do
-    Dec(i);
+  While (I>0) and (I<=L) and not (S[i] in SP) do
+    Dec(I);
   If (I=0) then
     begin
-    I:=P;
-    While (I<=L) and not (S[i] in [#10,#13,' ',#9]) do
-      Inc(i);
+    Inc(I);
+    While (I<=L) and not (S[I] in SP) do
+      Inc(I);
     end;
   Result:=I;
 end;
@@ -186,7 +187,7 @@
     exit;
   N:=S;
   Repeat
-    If ((FCurrentPos+Length(N))>LineWidth) then
+    If ((FCurrentPos+Length(N)+1)>LineWidth) then
       begin
       L:=FindSpace(N,LineWidth-FCurrentPos+1);
       inherited Write(Copy(N,1,L-1));
@@ -195,8 +196,8 @@
       end
     else
       begin
-      L:=Length(N)+1;
-      inherited Write(Copy(N,1,L-1));
+      L:=Length(N);
+      inherited Write(Copy(N,1,L));
       Inc(FCurrentPos,L);
       If FCheckEOL then
         If (L>=LEOL) then
Index: utils/fpdoc/fpdoc.pp
===================================================================
--- utils/fpdoc/fpdoc.pp	(revision 47408)
+++ utils/fpdoc/fpdoc.pp	(working copy)
@@ -428,6 +428,8 @@
 end;
 
 begin
+  //AssignFile(Output, 'fpdoc.log');
+  //rewrite(Output);
   With TFPDocApplication.Create(Nil) do
     try
       Run;
Index: utils/fpdoc/fpdocclasstree.pp
===================================================================
--- utils/fpdoc/fpdocclasstree.pp	(revision 47408)
+++ utils/fpdoc/fpdocclasstree.pp	(working copy)
@@ -11,7 +11,9 @@
   TClassTreeBuilder = Class
   Private
     FClassTree : TXMLDocument;
-    FTreeStart : TDomElement;
+    FXmlRoot: TDomElement;
+    FClassTObjectRoot : TDomElement; // for TObject or IInterface childs
+    FClassSimpleRoot : TDomElement;  // for Classes without parent or undocumented parents
     FObjectKind : TPasObjKind;
     FPackage: TPasPackage;
     FParentObject : TPasClassType;
@@ -24,6 +26,8 @@
     Destructor Destroy; override;
     Function BuildTree(AObjects : TStringList) : Integer;
     Property ClassTree : TXMLDocument Read FClassTree;
+    Property ClassTreeTObject: TDomElement read FClassTObjectRoot;
+    Property ClassTreeSimple: TDomElement read FClassSimpleRoot;
   end;
 
 implementation
@@ -30,20 +34,31 @@
 
 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);
+    okObject, okClass:
+      begin
+        FParentObject:=TPasClassType.Create('System.TObject',FPackage);
+        FClassTObjectRoot:=FClassTree.CreateElement('TObject');
+        FClassTObjectRoot['unit']:='System';
+      end;
+    okInterface :
+      begin
+        FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
+        FClassTObjectRoot:=FClassTree.CreateElement('IInterface');
+        FClassTObjectRoot['unit']:='System';
+      end;
   end;
+  FXmlRoot:=FClassTree.CreateElement('ClassHierarchy');
+  ClassTree.AppendChild(FXmlRoot);
   FParentObject.ObjKind:=FObjectKind;
-  FTreeStart:=FClassTree.CreateElement('TObject');
-  FTreeStart['unit']:='System';
-  ClassTree.AppendChild(FTreeStart);
+  FXmlRoot.AppendChild(FClassTObjectRoot);
+  //FClassSimpleRoot := FXmlRoot;
+  FClassSimpleRoot:=FClassTree.CreateElement('SimpleClasses');
+  FXmlRoot.AppendChild(FClassSimpleRoot);
 end;
 
 destructor TClassTreeBuilder.Destroy;
@@ -65,6 +80,7 @@
     begin
     PC:=AObjects.Objects[i] as TPasClassType;
     If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
+      // Each our Pascal class inserted into tree
       AddToClassTree(PC,Result);
     end;
 end;
@@ -72,7 +88,7 @@
 Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
 
 Var
-  PN,S,EN : String;
+  PN,S,EN, EP : String;
 
 begin
   EN:=AELement.Name;
@@ -86,13 +102,24 @@
       end
     else
       begin
-      IF Assigned(Aelement.GetModule) then
-        PN:=Aelement.GetModule.PackageName
+      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);
+      if PN <> '' then
+      begin
+        S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S;
+        EP:=AElement.PathName;
+      end
+       else
+      begin
+        S:=UTF8Encode(TDomElement(N)['unit'])+'.'+S;
+        EP:=AElement.PathName;
+        if EP[1] = '#' then
+           EP := Copy(EP, Pos('.', EP)+1, Length(EP));
       end;
+      Result:=(CompareText(S,EP)=0);
+      end;
    end;
 end;
 
@@ -102,7 +129,7 @@
   N : TDomNode;
 
 begin
-//  Writeln('Enter TClassTreeBuilderLookForElement');
+//  Write('>> TClassTreeBuilder.LookForElement');
   Result:=PE;
   While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
     Result:=Result.NextSibling;
@@ -119,7 +146,7 @@
         N:=N.NextSibling;
         end;
       end;
-//  Writeln('Exit TClassTreeBuilderLookForElement');
+//  Write('<< TClassTreeBuilder.LookForElement');
 end;
 
 Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
@@ -127,62 +154,67 @@
 // I initialized them to nil to at least make failures deterministic.
 Var
   PC : TPasClassType;
-  PE : TDomElement;
+  PE : TDomElement;  // Parent Node elemet
   M : TPasModule;
   N : TDomNode;
 
 begin
 
-//  Writeln('Enter TClassTreeBuilder.AddToClassTree');
+  //Write('>> TClassTreeBuilder.AddToClassTree');
   //if Assigned(AElement) then
-    //Writeln('Addtoclasstree : ',aElement.Name);
+  //  WriteLn('    Addtoclasstree=', aElement.Name, ' cnt=', IntToStr(ACount))
+  //else
+  //  WriteLn('');
   Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
   If (AElement=Nil) then
-    begin
-    Result:=FTreeStart;
-    Exit;
-    end
+    Exit
   else If (AElement is TPasUnresolvedTypeRef) then
-    begin
-    N:=LookForElement(FTreeStart,AElement,True);
+    begin  // Search into NodeTree
+    N:=LookForElement(FClassTObjectRoot,AElement,True);
     If (N=Nil) then
-      PE:=FTreeStart;
+      PE:=FClassSimpleRoot;
     end
   else If (AElement is TPasClassType) then
     begin
-    if (AElement=FParentObject) then
-      Result:=FTreeStart
+    if (AElement=FParentObject) then  // Input Object is RootTObject
+      Result:=FClassTObjectRoot
     else
-      begin
-      PC:=AElement as TPasClassType;
-      PE:=AddToClassTree(PC.AncestorType,ACount);
-      if PE=Nil then
-        PE:=FTreeStart;
-      N:=LookForElement(PE,PC,False);
+      begin // Need Add ancestor
+        PC:=AElement as TPasClassType;
+        PE:=AddToClassTree(PC.AncestorType,ACount); // try add Ancestor
+        if PE=nil then
+        begin
+          N:=LookForElement(FClassTObjectRoot,PC,False); // Seek into root TObject classes
+          if N=Nil then
+            N:=LookForElement(FClassSimpleRoot,PC,False); // Seek into free classes
+        end;
       end
-    end;
-  If (N<>Nil) then
-    begin
+    end; // if
+  If (N <> Nil) then // Class node was found
     Result:=N as TDomElement
-    end
-  else if AElement.Name<>'' then
+  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
+      if Not (AElement is TPasUnresolvedTypeRef) then
+        begin
+          Inc(ACount);
+          if PE=Nil then
+            PE:=FClassSimpleRoot;
+        end;
+      Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name)); // Create new NodeElement
       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);
+      if Assigned(Result) then
+        begin
+          if Assigned(M) then
+            Result['unit']:=UTF8Decode(M.Name); // module name
+          if Assigned(PE)then
+            PE.AppendChild(Result);
+        end;
     end;
+  //Writeln('<< TClassTreeBuilder.AddToClassTree');
+  //if Assigned(AElement) then
+  //  WriteLn('    Addtoclasstree=', aElement.Name, ' cnt=', IntToStr(ACount))
+  //else
+  //  WriteLn('');
 end;
 
 end.
Index: utils/fpdoc/mkfpdoc.pp
===================================================================
--- utils/fpdoc/mkfpdoc.pp	(revision 47408)
+++ utils/fpdoc/mkfpdoc.pp	(working copy)
@@ -42,6 +42,8 @@
     procedure SetVerbose(AValue: Boolean); virtual;
     Procedure DoLog(Const Msg : String);
     procedure DoLog(Const Fmt : String; Args : Array of Const);
+    Procedure DoLogSender(Sender : TObject; Const Msg : String);
+    // Create documetation by specified Writer class
     procedure CreateOutput(APackage: TFPDocPackage; Engine: TFPDocEngine); virtual;
   Public
     Constructor Create(AOwner : TComponent); override;
@@ -96,6 +98,14 @@
   DoLog(Format(Fmt,Args));
 end;
 
+procedure TFPDocCreator.DoLogSender ( Sender: TObject; const Msg: String ) ;
+begin
+  if Assigned(Sender) then
+    DoLog(Format('%s - Sender: %s', [Msg, Sender.ClassName]))
+  else
+    DoLog(Msg);
+end;
+
 procedure TFPDocCreator.HandleOnParseUnit(Sender: TObject;
   const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String);
 
@@ -208,7 +218,9 @@
   Cmd,Arg : String;
 
 begin
+  // Now is used the specified writer
   WriterClass:=GetWriterClass(Options.Backend);
+  // ALL CONTENT CREATED HERE
   Writer:=WriterClass.Create(Engine.Package,Engine);
   With Writer do
     Try
@@ -225,10 +237,12 @@
           If not InterPretOption(Cmd,Arg) then
             DoLog(SCmdLineInvalidOption,[Cmd+'='+Arg]);
           end;
+      // Output created Documentation
       WriteDoc;
     Finally
       Free;
     end;
+  // Output content files
   Writeln('Content file : ',APackage.ContentFile);
   if Length(APackage.ContentFile) > 0 then
     Engine.WriteContentFile(APackage.ContentFile);
@@ -247,16 +261,21 @@
   Cmd:='';
   FCurPackage:=APackage;
   Engine:=TFPDocEngine.Create;
+  Engine.OnLog:= @DoLogSender;
   try
+    // get documentation Writer html, latex, and other
     WriterClass:=GetWriterClass(Options.Backend);
     For J:=0 to Apackage.Imports.Count-1 do
       begin
       Arg:=Apackage.Imports[j];
+      // conversion import FilePathes
       WriterClass.SplitImport(Arg,Cmd);
+      // create tree of imported objects
       Engine.ReadContentFile(Arg, Cmd);
       end;
     for i := 0 to APackage.Descriptions.Count - 1 do
       Engine.AddDocFile(FixDescrFile(APackage.Descriptions[i]),Options.donttrim);
+    // set engine options
     Engine.SetPackageName(APackage.Name);
     Engine.Output:=APackage.Output;
     Engine.OnLog:=Self.OnLog;
@@ -268,13 +287,18 @@
     Engine.WarnNoNode:=Options.WarnNoNode;
     if Length(Options.Language) > 0 then
       TranslateDocStrings(Options.Language);
+    // scan the input source files
     for i := 0 to APackage.Inputs.Count - 1 do
       try
+        // get options from input packages
         SplitInputFileOption(APackage.Inputs[i],Cmd,Arg);
+        // make absolute filepath
         Cmd:=FixInputFile(Cmd);
         if FProcessedUnits.IndexOf(Cmd)=-1 then
           begin
           FProcessedUnits.Add(Cmd);
+          // Parce sources for OS Target
+          //WriteLn(Format('Parcing unit: %s', [ExtractFilenameOnly(Cmd)]));
           ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]);
           end;
       except
@@ -290,6 +314,7 @@
     if Not ParseOnly then
       begin
       Engine.StartDocumenting;
+      // Create documentation
       CreateOutput(APackage,Engine);
       end;
   finally
patch_fpdoc_01.patch (48,435 bytes)   
patch_fpdoc_description_01_en.txt (3,416 bytes)   
Fix Description.

I apologize that I was placed a lot in this patch, but almost everything does not work separately. If you say that you need to divide on the parts, then I will do it. But I did not have the opportunity to make intermediate fixations in repo.

Changes:
1. Correction of the generation of XCT files. Unit dGlobal.pp. Now all classes have only full FilePath with the package name.
FUNSTION - TFPDOCENGINE.WRIPECONTENTFILE()

2. Small fixing of the assembly link to the internal pages
FUNCTION - TFPDOCENGINE.REDCONTENTFILE LINES 719 - 720.

3. Remake the classes tree for the pages of the classes hierarchy. Here are great changes.
Unit Fpdocclasstree.
 In this file, the XML document received two separate branches. One branch for TObject classes ancestors, the second branch for classes without ancestor and for unresolved classes.
 An example of a tree for my test is attached. (test.xml)
 The output of this file can be enabled in the DW_HTML.PP Line 2580 string

4. Remake the page with the display hierarchy of classes for the entire package.
Here you can see the two sections "Hierarchy of tobject Classes" and "Hierarchy of Simple Classes". It is better visible on the test.chm file.

5. Remake the main page of the class display page, so that there were no passages of the hierarchy. What is done no longer remember.
DW_HTML.PP Procedure CreatemainPage;

6. Fix small exception ino dw_txt.pas

7. As I have already written that after fixing the XCT file and some functions, all methods and properties of the ancestors appeared in all pages of Class-Functions Class-Properties Class-Events. After it, the chm file and the full-text index grew very much. Also began to load Lhelp for a long time. These pages not have a title and are useless for the index, so I tried to turn them off from full-text search. But in Packages / CHM / SRC / CHMWRITER.PAS, there is no possibility to remove some files from full-text search, you can only turn off all files. Here I apologize, I made a hack, you decide. But if this is not done, then everything made will be useless.
I added to Packages/CHM/SRC/CHMWRITER.PAS the hack code. Exception of files from a full-text index if they start from the point. That in general logical and then it will be possible to exclude other index pages. As a result, full-text search became beautiful. Under another, I don`t know how to do that another. I didn`t want use external index for that.

8. From beautiful, I only made a change in the upper bar, because it was very difficult to understande where I am now. Now I obviously signed when I displays the data of the unit or package.
DW_HTML.PP - Thtmlwriter.APPendMenubar

9. Misc 
- The situation with the RTF format is incomprehensible, it does not open with me.
- Also attached the generated tree objects for the classes hierarchy (test.xml)
- An XML mode produces exception when I start without created before an output directory (need to add the directory creation before output).

  
Attached:
- The test files TXT, IPF, MAN, CHTM, HTML modes, and a new LCL.CHM as an example.
- I have no opportunity to check LATEX on Windows, but the machine with Linux has already collected.
- New rtl.xct fcl.xct

Files:
https://drive.google.com/file/d/1f08ONIZ-lJFadOWG8tk_gLPIwLdEE-WG/view?usp=sharing

I hope that you can allocate time to work with this FIX.

Andrey Sobol.

Michael Van Canneyt

2020-11-30 19:34

administrator   ~0127273

Hello,

I looked at your patch.

I will apply what I can. The menu bar change seems nice to me.

Unfortunately, there are some remarks:
* You will need to redo the complete class tree work with current trunk.
   If you look at the current sources, you'll see that there is no more XML used in that unit.
   None of your code is usable.
* Classes without explicit parent always descend from TObject.
    Putting them in a separate tree is simply wrong.
   I can understand you want to put the 'unknown' ones in a separate tree, but the one without explict parents must go in the normal tree.

Andrey Sobol

2020-11-30 20:32

reporter   ~0127277

Sadly ... :(
I will see...
Classes I agree also, I forgot that.

Andrey Sobol

2020-11-30 20:35

reporter   ~0127278

Last edited: 2020-11-30 21:04

View 2 revisions

What are you think about exclusion of files from a full text index per the dot prefix?

Michael Van Canneyt

2020-12-01 10:06

administrator   ~0127287

A list of files to exclude seems the best way to me. It could contain wildchars.

Marco van de Voort

2020-12-01 17:10

manager   ~0127304

You can't put the . hack in CHMwriter anyway, that unit is for more applications than just fpdoc

Andrey Sobol

2020-12-01 17:19

reporter   ~0127305

But I don`t need this, I don`t include that files into full text index. You can see it into my fix, package/chm/chmwriter

Andrey Sobol

2020-12-02 18:52

reporter   ~0127322

Last edited: 2020-12-03 10:41

View 4 revisions

Hello
- attached the new patch version
- attached description
- link to test files https://drive.google.com/file/d/1myUOZGsGTl42aaji68WC6G0XczUZaT19/view?usp=sharing

To do
- add a tree output for xmlwriter.
- show unresolved sign '?' at ClassTree for classes without documentation.
- can be add an using TClassTreeBuilder for another pages.
patch_fpdoc_02.patch (52,198 bytes)   
Index: packages/chm/src/chmwriter.pas
===================================================================
--- packages/chm/src/chmwriter.pas	(revision 47408)
+++ packages/chm/src/chmwriter.pas	(working copy)
@@ -1664,14 +1664,15 @@
 
 procedure TChmWriter.CheckFileMakeSearchable(AStream: TStream; AFileEntry: TFileEntryRec);
 var
-    TopicEntry: TTopicEntry;
-    ATitle: String;
+  TopicEntry: TTopicEntry;
+  ATitle: String;
 begin
-  if Pos('.ht', AFileEntry.Name) > 0 then
+  // Exclude Full text index for files starting from the dot
+  if (Pos('.', AFileEntry.Name) <> 1) and (Pos('.ht', AFileEntry.Name) > 0) then
   begin
     ATitle := FIndexedFiles.IndexFile(AStream, NextTopicIndex, FSearchTitlesOnly);
     AddTopic(ATitle,AFileEntry.Path+AFileEntry.Name,-1);
- end;
+  end;
 end;
 
 function TChmWriter.AddTopic(ATitle,AnUrl:AnsiString;code:integer=-1):integer;
@@ -1690,7 +1691,7 @@
     TopicEntry.URLTableOffset := AddURL(AnUrl, Result);
     if code=-1 then
       begin
-       if ATitle<>'' then
+       if Trim(ATitle) <> '' then
          TopicEntry.InContents := 6
        else
          TopicEntry.InContents := 2;
@@ -1720,8 +1721,8 @@
    ATitle :=StringReplace(Atitle, '&x27;', '', [rfReplaceAll]);
 
   // adhoc subsitutions. Replace with real code if exact behaviour is known.
-{  Atitle:=StringReplace(atitle, '&x27;', '''', [rfReplaceAll]);
-  if length(atitle)>0 then
+{  Atitle:=StringReplace(Atitle, '&x27;', '''', [rfReplaceAll]);
+  if length(Trim(Atitle))>0 then
     atitle[1]:=uppercase(atitle[1])[1];}
   {$ifdef binindex}
   writeln('Enter ',ATitle,' ',AnUrl);
@@ -1732,11 +1733,11 @@
        writeln('found:',result);
      {$endif}
    end
-   else
-    begin
-      result:=addtopic(atitle,anurl);
-      FDictTopicsUrlInd.add(anurl,result);
-    end;
+   else if Trim(ATitle) <> '' then
+      begin
+        result:=addtopic(ATitle,AnUrl);
+        FDictTopicsUrlInd.add(AnUrl,result);
+      end;
 end;
 
 procedure TChmWriter.ScanSitemap(asitemap:TCHMSiteMap);
Index: utils/fpdoc/dglobals.pp
===================================================================
--- utils/fpdoc/dglobals.pp	(revision 47648)
+++ utils/fpdoc/dglobals.pp	(working copy)
@@ -36,9 +36,12 @@
 resourcestring
   // Output strings
   SDocPackageTitle           = 'Reference for package ''%s''';
+  SDocPackageMenuTitle       = 'Menu for package ''%s''';
+  SDocPackageLinkTitle       = 'Package';
   SDocPrograms               = 'Programs';
   SDocUnits                  = 'Units';
   SDocUnitTitle              = 'Reference for unit ''%s''';
+  SDocUnitMenuTitle          = 'Menu for unit ''%s''';
   SDocInheritanceHierarchy   = 'Inheritance Hierarchy';
   SDocInterfaceSection       = 'Interface section';
   SDocImplementationSection  = 'Implementation section';
@@ -205,7 +208,7 @@
 Const
   SVisibility: array[TPasMemberVisibility] of string =
        ('Default', 'Private', 'Protected', 'Public',
-       'Published', 'Automated','Strict Private','Strict Protected','Required','Optional');
+       'Published', 'Automated','Strict Private','Strict Protected');
 
 type
   TBufType = Array[1..ContentBufSize-1] of byte;
@@ -319,9 +322,9 @@
     FAlwaysVisible : TStringList;
     DescrDocs: TObjectList;             // List of XML documents
     DescrDocNames: TStringList;         // Names of the XML documents
-    FRootLinkNode: TLinkNode;
-    FRootDocNode: TDocNode;
-    FPackages: TFPList;                   // List of TFPPackage objects
+    FRootLinkNode: TLinkNode;           // Global tree of TlinkNode from the imported .xct files
+    FRootDocNode: TDocNode;             // Global tree of TDocNode from the .xml documentation files
+    FPackages: TFPList;                 // Global list of TPasPackage objects and full tree of sources
     CurModule: TPasModule;
     CurPackageDocNode: TDocNode;
     function ParseUsedUnit(AName, AInputLine,AOSTarget,ACPUTarget: String): TPasModule; virtual;
@@ -338,7 +341,9 @@
     constructor Create;
     destructor Destroy; override;
     procedure SetPackageName(const APackageName: String);
+    // process the import objects from external .xct file
     procedure ReadContentFile(const AFilename, ALinkPrefix: String);
+    // creation of an own .xct output file
     procedure WriteContentFile(const AFilename: String);
 
     function CreateElement(AClass: TPTreeElement; const AName: String;
@@ -345,6 +350,7 @@
       AParent: TPasElement; AVisibility: TPasMemberVisibility;
       const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
       override;
+    function FindInModule(const AName: String ; AModule: TPasModule): TPasElement;
     function FindElement(const AName: String): TPasElement; override;
     function FindModule(const AName: String): TPasModule; override;
     Function HintsToStr(Hints : TPasMemberHints) : String;
@@ -660,7 +666,9 @@
 procedure TFPDocEngine.ReadContentFile(const AFilename, ALinkPrefix: String);
 var
   f: Text;
-  inheritanceinfo : TStringlist;
+  inheritanceinfo : TStringlist; // contents list of TPasClass with inheritance info
+                                 // like this #PackageName.ModuleName.ClassName
+  tmpLinkPrefix : string;
 
   procedure ReadLinkTree;
   var
@@ -708,8 +716,10 @@
       i := ThisSpaces + 1;
       while s[i] <> ' ' do
         Inc(i);
+      if ALinkPrefix <> '' then
+        tmpLinkPrefix := ExcludeTrailingPathDelimiter(ALinkPrefix)+'/';
       NewNode := TLinkNode.Create(Copy(s, ThisSpaces + 1, i - ThisSpaces - 1),
-        ALinkPrefix + Copy(s, i + 1, Length(s)));
+        tmpLinkPrefix + Copy(s, i + 1, Length(s)));
       if pos(' ',newnode.link)>0 then
         writeln(stderr,'Bad format imported node: name="',newnode.name,'" link="',newnode.link,'"');
       if Assigned(PrevSibling) then
@@ -721,56 +731,57 @@
   end;
 
   function ResolvePackageModule(AName:String;out pkg:TPasPackage;out module:TPasModule;createnew:boolean):String;
-    var
-      DotPos, DotPos2, i: Integer;
-      s: String;
-      HPackage: TPasPackage;
+  var
+    DotPos, DotPos2, i: Integer;
+    s: String;
+    HPackage: TPasPackage;
 
-    begin
-      pkg:=nil; module:=nil; result:='';
+  begin
+    pkg:=nil; module:=nil; result:='';
 
-      // Find or create package
-      DotPos := Pos('.', AName);
-      s := Copy(AName, 1, DotPos - 1);
-      HPackage := nil;
-      for i := 0 to FPackages.Count - 1 do
-        if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
-        begin
-          HPackage := TPasPackage(FPackages[i]);
-          break;
-        end;
-      if not Assigned(HPackage) then
+    // Find or create package
+    DotPos := Pos('.', AName);
+    s := Copy(AName, 1, DotPos - 1);
+    HPackage := nil;
+    for i := 0 to FPackages.Count - 1 do
+      if CompareText(TPasPackage(FPackages[i]).Name, s) = 0 then
       begin
-        if not CreateNew then
-          exit;
-        HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
-          '', 0));
-        FPackages.Add(HPackage);
+        HPackage := TPasPackage(FPackages[i]);
+        break;
       end;
+    if not Assigned(HPackage) then
+    begin
+      if not CreateNew then
+        exit;
+      HPackage := TPasPackage(inherited CreateElement(TPasPackage, s, nil,
+        '', 0));
+      FPackages.Add(HPackage);
+    end;
 
-      // Find or create module
-      DotPos2 := DotPos;
-      repeat
-        Inc(DotPos2);
-      until AName[DotPos2] = '.';
-      s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
-      Module := nil;
-      for i := 0 to HPackage.Modules.Count - 1 do
-        if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
-        begin
-          Module := TPasModule(HPackage.Modules[i]);
-          break;
-        end;
-      if not Assigned(Module) then
+    // Find or create module
+    DotPos2 := DotPos;
+    repeat
+      Inc(DotPos2);
+    until AName[DotPos2] = '.';
+    s := Copy(AName, DotPos + 1, DotPos2 - DotPos - 1);
+    Module := nil;
+    for i := 0 to HPackage.Modules.Count - 1 do
+      if CompareText(TPasModule(HPackage.Modules[i]).Name, s) = 0 then
       begin
-        if not CreateNew then
-          exit;
-        Module := TPasExternalModule.Create(s, HPackage);
-        Module.InterfaceSection := TInterfaceSection.Create('', Module);
-        HPackage.Modules.Add(Module);
+        Module := TPasModule(HPackage.Modules[i]);
+        break;
       end;
-     pkg:=hpackage;
-     result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2);
+    if not Assigned(Module) then
+    begin
+      if not CreateNew then
+        exit;
+      Module := TPasExternalModule.Create(s, HPackage);
+      Module.InterfaceSection := TInterfaceSection.Create('', Module);
+      Module.PackageName:= HPackage.Name;
+      HPackage.Modules.Add(Module);
+    end;
+    pkg:=hpackage;
+    result:=Copy(AName, DotPos2 + 1, length(AName)-dotpos2);
   end;
 
   function SearchInList(clslist:TFPList;s:string):TPasElement;
@@ -834,9 +845,9 @@
         InheritanceInfo.AddObject(Inheritancestr,result);
     end;
 
-   procedure splitalias(var instr:string;out outstr:string);
-   var i,j:integer;
-   begin 
+    procedure splitalias(var instr:string;out outstr:string);
+    var i,j:integer;
+    begin
      if length(instr)=0 then exit;
      instr:=trim(instr);
      i:=pos('(',instr);
@@ -848,10 +859,10 @@
         outstr:=copy(instr,i+1,j);
         delete(instr,i,j+2);
       end
-   end;
+    end;
 
-   Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType;
-   begin
+    Function ResolveAndLinkClass(clname:String;IsClass:boolean;cls:TPasClassType):TPasClassType;
+    begin
      result:=TPasClassType(ResolveClassType(clname)); 
      if assigned(result) and not (cls=result) then  // save from tobject=implicit tobject
        begin
@@ -870,47 +881,47 @@
      else
        if cls<>result then
          DoLog('Warning : ancestor class %s of class %s could not be resolved',[clname,cls.name]);
-end;
+    end;
 
-function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType;
-// create alias clname =  alname
-var 
-  pkg     : TPasPackage;
-  module  : TPasModule; 
-  s       : string;  
-begin
-    Result:=nil;
-    s:=ResolvePackageModule(Alname,pkg,module,True);
-    if not assigned(module) then
-      exit;
-    cl2:=TPasClassType(ResolveClassType(alname));
-    if assigned( cl2) and not (parentclass=cl2) then  
-      begin
-        result:=ResolveAliasType(clname);
-        if assigned(result) then
+    function CreateAliasType (alname,clname : string;parentclass:TPasClassType; out cl2 :TPasClassType):TPasAliasType;
+    // create alias clname =  alname
+    var
+      pkg     : TPasPackage;
+      module  : TPasModule;
+      s       : string;
+    begin
+        Result:=nil;
+        s:=ResolvePackageModule(Alname,pkg,module,True);
+        if not assigned(module) then
+          exit;
+        cl2:=TPasClassType(ResolveClassType(alname));
+        if assigned( cl2) and not (parentclass=cl2) then  
           begin
-//            writeln('found alias ',clname,' (',s,') ',result.classname);  
+            result:=ResolveAliasType(clname);
+            if assigned(result) then
+              begin
+    //            writeln('found alias ',clname,' (',s,') ',result.classname);
+              end
+            else
+              begin
+    //            writeln('new alias ',clname,' (',s,') ');
+                cl2.addref;
+                Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0));
+                module.interfacesection.Declarations.Add(Result);
+                TPasAliasType(Result).DestType := cl2;
+              end
           end
-        else
-          begin
-//            writeln('new alias ',clname,' (',s,') ');
-            cl2.addref;
-            Result := TPasAliasType(CreateElement(TPasAliasType,s,module.interfacesection,vispublic,'',0));
-            module.interfacesection.Declarations.Add(Result);
-            TPasAliasType(Result).DestType := cl2;
-          end
-      end
-end;
+    end;
 
-   procedure ProcessInheritanceStrings(inhInfo:TStringList);
+    procedure ProcessInheritanceStrings(inhInfo:TStringList);
 
-   var i,j : integer;
-       cls : TPasClassType;  
+    var i,j : integer;
+       cls : TPasClassType;
        cls2: TPasClassType;
        clname,
        alname : string;
        inhclass   : TStringList;
-   begin
+    begin
      inhclass:=TStringList.Create;
      inhclass.delimiter:=',';
      if InhInfo.Count>0 then
@@ -922,12 +933,12 @@
 
            for j:= 0 to inhclass.count-1 do
              begin
-               //writeln('processing',inhclass[j]);
+               // writeln('processing',inhclass[j]);
                clname:=inhclass[j];
-               splitalias(clname,alname);               
+               splitalias(clname,alname);
                if alname<>'' then // the class//interface we refered to is an alias
                  begin
-                   // writeln('Found alias pair ',clname,' = ',alname);   
+                   // writeln('Found alias pair ',clname,' = ',alname);
                    if not assigned(CreateAliasType(alname,clname,cls,cls2)) then
                       DoLog('Warning: creating alias %s for %s failed!',[alname,clname]);
                  end 
@@ -936,7 +947,7 @@
              end;
          end;
     inhclass.free;
-   end;
+    end;
 
   var
     s, Name: String;
@@ -993,10 +1004,10 @@
           CurClass.Members.Add(Member);
         end;
       end;
-     ProcessInheritanceStrings(Inheritanceinfo);
+      ProcessInheritanceStrings(Inheritanceinfo);
     finally
-     inheritanceinfo.Free;
-     end;
+      inheritanceinfo.Free;
+    end;
   end;
 
 var
@@ -1044,11 +1055,13 @@
     end;
   end;
 
-  function CheckImplicitInterfaceLink(const s : String):String;
+  function CheckImplicitLink(const s : String):String;
   begin
-   if uppercase(s)='IUNKNOWN' then
+    if uppercase(s)='IUNKNOWN' then
      Result:='#rtl.System.IUnknown'
-   else 
+    else if uppercase(s)='TOBJECT' then
+     Result:='#rtl.System.TObject'
+   else
      Result:=s;
   end;
 var
@@ -1096,13 +1109,13 @@
           ClassLikeDecl:=MemberDecl as TPasClassType
         else
           ClassLikeDecl:=nil;
-        Write(ContentFile, CheckImplicitInterfaceLink(MemberDecl.PathName), ' ');
+        Write(ContentFile, CheckImplicitLink(MemberDecl.PathName), ' ');
         if Assigned(ClassLikeDecl) then
           begin
           if Assigned(ClassLikeDecl.AncestorType) then
             begin
             // simple aliases to class types are coded as "alias(classtype)"
-            Write(ContentFile, CheckImplicitInterfaceLink(ClassLikeDecl.AncestorType.PathName));
+            Write(ContentFile, CheckImplicitLink(ClassLikeDecl.AncestorType.PathName));
             if ClassLikeDecl.AncestorType is TPasAliasType then
                begin
                alias:= TPasAliasType(ClassLikeDecl.AncestorType);
@@ -1118,12 +1131,12 @@
             begin
             for k:=0 to ClassLikeDecl.Interfaces.count-1 do
               begin
-                write(contentfile,',',CheckImplicitInterfaceLink(TPasClassType(ClassLikeDecl.Interfaces[k]).PathName));
+                write(contentfile,',',CheckImplicitLink(TPasClassType(ClassLikeDecl.Interfaces[k]).PathName));
                 if TPasElement(ClassLikeDecl.Interfaces[k]) is TPasAliasType then
                   begin
                     alias:= TPasAliasType(ClassLikeDecl.Interfaces[k]);
                     if assigned(alias.desttype) and (alias.desttype is TPasClassType) then
-                      write(ContentFile,'(',CheckImplicitInterfaceLink(alias.desttype.PathName),')');   
+                      write(ContentFile,'(',CheckImplicitLink(alias.desttype.PathName),')');
                   end;
               end;
             end;
@@ -1173,34 +1186,34 @@
   Result.SourceLinenumber := ASourceLinenumber;
 end;
 
-function TFPDocEngine.FindElement(const AName: String): TPasElement;
+function TFPDocEngine.FindInModule ( const AName: String; AModule: TPasModule
+  ) : TPasElement;
+var
+  l: TFPList;
+  i: Integer;
 
-  function FindInModule(AModule: TPasModule; const LocalName: String): TPasElement;
-  
-  var
-    l: TFPList;
-    i: Integer;
-    
-  begin
-    If assigned(AModule.InterfaceSection) and 
-       Assigned(AModule.InterfaceSection.Declarations) then
+begin
+  If Assigned(AModule) and Assigned(AModule.InterfaceSection) and
+     Assigned(AModule.InterfaceSection.Declarations) then
+    begin
+    l:=AModule.InterfaceSection.Declarations;
+    for i := 0 to l.Count - 1 do
       begin
-      l:=AModule.InterfaceSection.Declarations;
-      for i := 0 to l.Count - 1 do
-        begin
-        Result := TPasElement(l[i]);
-        if  CompareText(Result.Name, LocalName) = 0 then
-          exit;
-        end;
-      end;  
-    Result := nil;
- end;
+      Result := TPasElement(l[i]);
+      if CompareText(Result.Name, AName) = 0 then
+        exit;
+      end;
+    end;
+  Result := nil;
+end;
 
+function TFPDocEngine.FindElement(const AName: String): TPasElement;
+
 var
   i: Integer;
   Module: TPasElement;
 begin
-  Result := FindInModule(CurModule, AName);
+  Result := FindInModule( AName, CurModule );
   if not Assigned(Result) and assigned (CurModule.InterfaceSection) then
     for i := CurModule.InterfaceSection.UsesList.Count - 1 downto 0 do
     begin
@@ -1207,7 +1220,7 @@
       Module := TPasElement(CurModule.InterfaceSection.UsesList[i]);
       if Module.ClassType.InheritsFrom(TPasModule) then
       begin
-        Result := FindInModule(TPasModule(Module), AName);
+        Result := FindInModule(AName, TPasModule(Module));
         if Assigned(Result) then
           exit;
       end;
Index: utils/fpdoc/dw_html.pp
===================================================================
--- utils/fpdoc/dw_html.pp	(revision 47648)
+++ utils/fpdoc/dw_html.pp	(working copy)
@@ -15,7 +15,7 @@
 {$mode objfpc}
 {$H+}
 
-unit dw_HTML;
+unit dw_html;
 {$WARN 5024 off : Parameter "$1" not used}
 interface
 
@@ -75,9 +75,7 @@
   THTMLWriter = class(TFPDocWriter)
   private
     FImageFileList: TStrings;
-
     FOnTest: TNotifyEvent;
-    FPackage: TPasPackage;
     FCharSet : String;
     procedure CreateMinusImage;
     procedure CreatePlusImage;
@@ -233,7 +231,7 @@
     procedure CreatePackagePageBody;
     procedure CreatePackageIndex;
     procedure CreatePackageClassHierarchy;
-    procedure CreateClassHierarchyPage(AList: TStringList; AddUnit : Boolean);
+    procedure CreateClassHierarchyPage(AddUnit : Boolean);
     procedure AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
     Procedure CreateTopicPageBody(AElement : TTopicElement);
     procedure CreateModulePageBody(AModule: TPasModule; ASubpageIndex: Integer);
@@ -244,9 +242,9 @@
     procedure CreateVarPageBody(AVar: TPasVariable);
     procedure CreateProcPageBody(AProc: TPasProcedureBase);
     Procedure CreateTopicLinks(Node : TDocNode; PasElement : TPasElement);
-    procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False);
     procedure AppendTypeDecl(AType: TPasType; TableEl, CodeEl: TDomElement);
   public
+    // Creating all module hierarchy classes is here !!!!
     constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
     destructor Destroy; override;
 
@@ -254,7 +252,7 @@
     function CreateHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument;
     function CreateXHTMLPage(AElement: TPasElement; ASubpageIndex: Integer): TXMLDocument;
 
-    // For producing complete package documentation
+    // Start producing html complete package documentation
     procedure WriteHTMLPages; virtual;
     procedure WriteXHTMLPages;
     function  ModuleForElement(AnElement:TPasElement):TPasModule;
@@ -266,7 +264,7 @@
     Class procedure SplitImport(var AFilename, ALinkPrefix: String); override;
     Property SearchPage: String Read FSearchPage Write FSearchPage;
     property Allocator: TFileAllocator read FAllocator;
-    property Package: TPasPackage read FPackage;
+
     property PageCount: Integer read GetPageCount;
     Property IncludeDateInFooter : Boolean Read FIDF Write FIDF;
     Property DateFormat : String Read FDateFormat Write FDateFormat;
@@ -326,13 +324,20 @@
 var
   n,s: String;
   i: Integer;
-
+  excl: Boolean; //search
 begin
   Result:='';
+  excl := False;
   if AElement.ClassType = TPasPackage then
-    Result := 'index'
+  begin
+    Result := 'index';
+    excl := True;
+  end
   else if AElement.ClassType = TPasModule then
-    Result := LowerCase(AElement.Name) + PathDelim + 'index'
+  begin
+    Result := LowerCase(AElement.Name) + PathDelim + 'index';
+    excl := True;
+  end
   else
   begin
     if AElement is TPasOperator then
@@ -361,8 +366,12 @@
       if (N<>'') and  (N[1]=':') then
         Delete(N,1,1);
       Result:=Result + '-'+ s + '-' + N;
-    end else
+    end
+      else
+    begin
       Result := LowerCase(AElement.PathName);
+      excl := (ASubindex > 0);
+    end;
     // searching for TPasModule - it is on the 2nd level
     if Assigned(AElement.Parent) then
       while Assigned(AElement.Parent.Parent) do
@@ -375,6 +384,14 @@
       Inc(i);
     if (i <= Length(Result)) and (i > 0) then
       Result[i] := PathDelim;
+    if excl or (Length(Result)=0) then
+      begin
+        // exclude the from full text search index
+        s:= '.'+ExtractFileName(Result + '.');
+        n:= ExtractFileDir(Result);
+        Result := n + DirectorySeparator + s;
+        Result := Copy(Result, 1, Length(Result)-1);
+      end;
   end;
 
   if ASubindex > 0 then
@@ -632,7 +649,7 @@
   H : Boolean;
 
 begin
-  inherited ;
+  inherited Create(APackage, AEngine);
 
   // should default to true since this is the old behavior
   UseMenuBrackets:=True;
@@ -640,7 +657,6 @@
   IndexColCount:=3;
   Charset:='iso-8859-1';
   CreateAllocator;
-  FPackage := APackage;
   OutputNodeStack := TList.Create;
 
   PageInfos := TObjectList.Create;
@@ -716,6 +732,7 @@
   HTMLEl.AppendChild(BodyElement);
 
   CreatePageBody(AElement, ASubpageIndex);
+
   AppendFooter;
 
   HeadEl.AppendChild(El);
@@ -771,6 +788,7 @@
         Filename := Engine.Output + Allocator.GetFilename(Element, SubpageIndex);
         try
           CreatePath(Filename);
+          //writeln('Element: ',Element.PathName, ' FileName: ', Filename);
           WriteHTMLFile(PageDoc, Filename);
         except
           on E: Exception do
@@ -1534,7 +1552,8 @@
   end;
 end;
 
-Procedure THTMLWriter.AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode : TDocNode);
+procedure THTMLWriter.AppendShortDescr ( AContext: TPasElement;
+  Parent: TDOMNode; DocNode: TDocNode ) ;
 
 Var
   N : TDocNode;
@@ -2093,7 +2112,7 @@
 procedure THTMLWriter.AppendMenuBar(ASubpageIndex: Integer);
 
 var
-  TableEl, TREl, ParaEl, TitleEl: TDOMElement;
+  TableEl, TREl, TRE2, ParaEl, TitleEl: TDOMElement;
 
   procedure AddLink(ALinkSubpageIndex: Integer; const AName: String);
   begin
@@ -2132,9 +2151,35 @@
   TableEl['border'] := '0';
   TableEl['width'] := '100%';
   TableEl['class'] := 'bar';
+  // Title Row
   TREl := CreateTR(TableEl);
-  ParaEl := CreateEl(CreateTD(TREl), 'b');
+  // Menu title
+  ParaEl := CreateTD(TREl);
+  ParaEl['align'] := 'left';
+  TitleEl := CreateEl(ParaEl, 'span');
+  TitleEl['class'] := 'bartitle';
+  if Assigned(Module) then
+    AppendText(TitleEl, Format(SDocUnitMenuTitle, [Module.Name]))
+  else
+    AppendText(TitleEl, Format(SDocPackageMenuTitle, [Package.Name]));
 
+  // Package link title
+  ParaEl := CreateTD(TREl);
+  ParaEl['align'] := 'right';
+  TitleEl := CreateEl(ParaEl, 'span');
+  TitleEl['class'] := 'bartitle';
+  if Assigned(Module) and Assigned(Package) then // Displays a Package page
+  begin
+    AppendText(TitleEl, SDocPackageLinkTitle);
+  end;
+
+  // Links Row
+  TRE2 := CreateTR(TableEl);
+  ParaEl := CreateTD(TRE2);
+  ParaEl['align'] := 'left';
+  ParaEl := CreateEl(ParaEl, 'span');
+  ParaEl['class']:= 'bartitle';
+
   if Assigned(Module) then
     begin
     AddLink(0, SDocOverview);
@@ -2150,12 +2195,18 @@
       AddLink(ProcsSubindex, SDocProceduresAndFunctions);
     if Module.InterfaceSection.Variables.Count > 0 then
       AddLink(VarsSubindex, SDocVariables);
-    AddLink(IndexSubIndex,SDocIdentifierIndex);  
+    AddLink(IndexSubIndex,SDocIdentifierIndex);
     AppendFragment(ParaEl, NavigatorHTML);
     end
   else
     begin
+    // Overview
+    AppendText(ParaEl, '[');
+    AppendHyperlink(ParaEl, Package).TextContent:= UTF8Decode(SDocOverview);
+    AppendText(ParaEl, ']');
+    //Index
     AddPackageLink(IndexSubIndex, SDocIdentifierIndex);
+    // Class TObject tree
     AddPackageLink(ClassHierarchySubIndex, SDocPackageClassHierarchy);
     AppendFragment(ParaEl, NavigatorHTML)
     end;
@@ -2168,17 +2219,16 @@
     if FUseMenuBrackets then
       AppendText(ParaEl, ']');
   end;
-  ParaEl := CreateTD(TREl);
+
+  ParaEl := CreateTD(TRE2);
   ParaEl['align'] := 'right';
-  TitleEl := CreateEl(ParaEl, 'span');
-  TitleEl['class'] := 'bartitle';
-  if Assigned(Module) then
-    AppendText(TitleEl, Format(SDocUnitTitle, [Module.Name]));
-  if Assigned(Package) then
+  ParaEl := CreateEl(ParaEl, 'span');
+  ParaEl['class']:= 'bartitle';
+  if Assigned(Module) and Assigned(Package) then // Displays a Package page
   begin
-    AppendText(TitleEl, ' (');
-    AppendHyperlink(TitleEl, Package);
-    AppendText(TitleEl, ')');
+    AppendText(ParaEl, '[');
+    AppendHyperlink(ParaEl, Package);
+    AppendText(ParaEl, ']');
   end;
   AppendFragment(BodyElement,HeaderHTML);
 end;
@@ -2189,7 +2239,8 @@
     [ExtractFileName(AElement.SourceFilename), AElement.SourceLinenumber]));
 end;
 
-Procedure THTMLWriter.AppendSeeAlsoSection(AElement : TPasElement;DocNode : TDocNode);
+procedure THTMLWriter.AppendSeeAlsoSection ( AElement: TPasElement;
+  DocNode: TDocNode ) ;
 
 var
   Node: TDOMNode;
@@ -2263,7 +2314,8 @@
      end; // While
 end;
 
-Procedure THTMLWriter.AppendExampleSection(AElement : TPasElement;DocNode : TDocNode);
+procedure THTMLWriter.AppendExampleSection ( AElement: TPasElement;
+  DocNode: TDocNode ) ;
 
 var
   Node: TDOMNode;
@@ -2384,10 +2436,11 @@
     end;
 end;
 
-procedure THTMLWriter.CreateClassHierarchyPage(AList : TStringList; AddUnit : Boolean);
+procedure THTMLWriter.CreateClassHierarchyPage(AddUnit : Boolean);
+type
+  TypeEN = (NPackage, NModule, NName);
 
   Procedure PushClassElement;
-
   Var
     H : THTMLElement;
   begin
@@ -2403,7 +2456,6 @@
   end;
 
   Procedure PushClassList;
-
   Var
     H : THTMLElement;
   begin
@@ -2412,32 +2464,39 @@
     PushOutputNode(h);
   end;
 
-  Procedure AppendClass(E : TPasElementNode);
+  function ExtractName(APathName: String; Tp: TypeEN):String;
+  var
+  l:TStringList;
+  begin
+    Result:= Trim(APathName);
+    if Result = '' then exit;
+    l:=TStringList.Create;
+    try
+      l.AddDelimitedText(Result, '.', True);
+      if l.Count=3 then
+        Result:= l.Strings[Integer(Tp)]
+      else
+        Result:='';
+    finally
+      l.free;
+    end;
+  end;
 
+  Procedure AppendClass(EN : TPasElementNode);
+
   Var
-    N : TDomNode;
-    P,PM,M : TPasElement;
-    EN : String;
-    LL : TstringList;
-    I,J : Integer;
+    PE,PM : TPasElement;
+    I : Integer;
 
   begin
-    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
-    else
-      P:=Engine.FindElement(EN);
+    if not Assigned(EN) then exit;
+    PE:=EN.Element;
     PushClassElement;
     try
-      if (P<>Nil) then
+      if (PE<>Nil) then
         begin
-        AppendHyperLink(CurOutputNode,P);
-        PM:=ModuleForElement(P);
+        AppendHyperLink(CurOutputNode,PE);
+        PM:=ModuleForElement(PE);
         if (PM<>Nil) then
           begin
           AppendText(CurOutputNode,' (');
@@ -2446,13 +2505,13 @@
           end
         end
       else
-        AppendText(CurOutputNode,E.Element.Name);
-      if E.ChildCount>0 then
+        AppendText(CurOutputNode,EN.Element.Name);
+      if EN.ChildCount>0 then
         begin
         PushClassList;
         try
-          For I:=0 to E.ChildCount-1 do
-            AppendClass(E.Children[i] as TPasElementNode);
+          For I:=0 to EN.ChildCount-1 do
+            AppendClass(EN.Children[i] as TPasElementNode);
         finally
           PopOutputNode;
         end;
@@ -2462,29 +2521,12 @@
     end;
   end;
 
-Var
-  B : TClassTreeBuilder;
-  E : TPasElementNode;
-
 begin
   PushOutputNode(BodyElement);
   try
-    B:=TClassTreeBuilder.Create(Package,okClass);
-    try
-      B.BuildTree(AList);
-      // Classes
-      // WriteXMLFile(B.ClassTree,'tree.xml');
-      // Dummy TObject
-      E:=B.RootNode;
-      PushClassList;
-      try
-        AppendClass(E);
-      finally
-        PopOutputNode;
-      end;
-    finally
-      B.Free;
-    end;
+    PushClassList;
+    AppendClass(TreeClass.RootNode);
+    //PopOutputNode;
   finally
     PopOutputNode;
   end;
@@ -2500,9 +2542,6 @@
           '}';
 
 Var
-  L : TStringList;
-  I : Integer;
-  M : TPasModule;
   S : String;
   SE : THTMLElement;
 
@@ -2510,24 +2549,12 @@
   SE := Doc.CreateElement('script');
   AppendText(SE,SFunc);
   HeadElement.AppendChild(SE);
-  L:=TStringList.Create;
-  try
-    L.Capacity:=PageInfos.Count; // Too much, but that doesn't hurt.
-    For I:=0 to Package.Modules.Count-1 do
-      begin
-      M:=TPasModule(Package.Modules[i]);
-      if Not (M is TPasExternalModule) and assigned(M.InterfaceSection) then
-        Self.AddElementsFromList(L,M.InterfaceSection.Classes,True)
-      end;
-    AppendMenuBar(ClassHierarchySubIndex);
-    S:=Package.Name;
-    If Length(S)>0 then
-      Delete(S,1,1);
-    AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S])));
-    CreateClassHierarchyPage(L,True);
-  Finally
-    L.Free;
-  end;
+  AppendMenuBar(ClassHierarchySubIndex);
+  S:=Package.Name;
+  If Length(S)>0 then
+    Delete(S,1,1);
+  AppendTitle(UTF8Decode(Format(SDocPackageClassHierarchy, [S])));
+  CreateClassHierarchyPage(True);
 end;
 
 procedure THTMLWriter.CreatePageBody(AElement: TPasElement;
@@ -2673,30 +2700,7 @@
   end;  
 end;
 
-Procedure THTMLWriter.AddElementsFromList(L : TStrings; List : TFPList; UsePathName : Boolean = False);
 
-Var
-  I : Integer;
-  El : TPasElement;
-  N : TDocNode;
-
-begin
-  For I:=0 to List.Count-1 do
-    begin
-    El:=TPasElement(List[I]);
-    N:=Engine.FindDocNode(El);
-    if (N=Nil) or (not N.IsSkipped) then
-      begin
-      if UsePathName then
-        L.AddObject(El.PathName,El)
-      else
-        L.AddObject(El.Name,El);
-      If el is TPasEnumType then
-        AddElementsFromList(L,TPasEnumType(el).Values);
-      end;
-    end;
-end;
-
 procedure THTMLWriter.AddModuleIdentifiers(AModule : TPasModule; L : TStrings);
 
 begin
@@ -2783,7 +2787,8 @@
     end;
 end;
 
-Procedure THTMLWriter.CreateTopicLinks(Node : TDocNode; PasElement : TPasElement);
+procedure THTMLWriter.CreateTopicLinks ( Node: TDocNode;
+  PasElement: TPasElement ) ;
 
 var
   DocNode: TDocNode;
@@ -3351,10 +3356,9 @@
     i: Integer;
     ThisInterface,
     ThisClass: TPasClassType;
-    HaveSeenTObject: Boolean;
-    LName     : String;
-    ThisNode  : TPasUnresolvedTypeRef;
+    ThisTreeNode: TPasElementNode;
   begin
+    //WriteLn('@ClassPageBody.CreateMainPage Class=', AClass.Name);
     AppendMenuBar(-1);
     AppendTitle(UTF8Decode(AClass.Name),AClass.Hints);
 
@@ -3398,14 +3402,16 @@
     end;
     CreateMemberDeclarations(AClass, AClass.Members,TableEl, not AClass.IsShortDefinition);
 
+    AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance));
+    TableEl := CreateTable(BodyElement);
 
+    // Now we are using only TreeClass for show inheritance
 
-    AppendText(CreateH2(BodyElement), UTF8Decode(SDocInheritance));
-    TableEl := CreateTable(BodyElement);
-    HaveSeenTObject := AClass.ObjKind <> okClass;
-    // we try to track classes. But imported classes
-    // are TLinkNode's not the TPasClassType generated by the parser.
-    ThisClass := AClass; ThisNode := Nil;
+    ThisClass := AClass; ThisTreeNode := Nil;
+    if AClass.ObjKind = okInterface then
+      ThisTreeNode := TreeInterface.GetPasElNode(AClass)
+    else
+      ThisTreeNode := TreeClass.GetPasElNode(AClass);
     while True do
     begin
       TREl := CreateTR(TableEl);
@@ -3412,14 +3418,13 @@
       TDEl := CreateTD_vtop(TREl);
       TDEl['align'] := 'center';
       CodeEl := CreateCode(CreatePara(TDEl));
-      if Assigned(ThisClass) then
-        LName:=ThisClass.Name
-      Else
-        LName:=ThisNode.Name;
+
+      // Show class item
       if Assigned(ThisClass) Then
-        AppendHyperlink(CodeEl, ThisClass)
-      else
-        AppendHyperlink(CodeEl, ThisNode);
+        AppendHyperlink(CodeEl, ThisClass);
+      //else
+      //  AppendHyperlink(CodeEl, ThisTreeNode);
+      // Show links to class interfaces
       if Assigned(ThisClass) and (ThisClass.Interfaces.count>0) then
         begin
           for i:=0 to ThisClass.interfaces.count-1 do
@@ -3429,48 +3434,28 @@
               AppendHyperlink(CodeEl, ThisInterface);
             end;
         end;
-      AppendShortDescrCell(TREl, ThisClass);
-      if HaveSeenTObject or (CompareText(LName, 'TObject') = 0) then
-        HaveSeenTObject := True
-      else
-      begin
-        TDEl := CreateTD(CreateTR(TableEl));
-        TDEl['align'] := 'center';
-        AppendText(TDEl, '|');
-      end;
+      // short class description
+      if Assigned(ThisClass) then
+            AppendShortDescrCell(TREl, ThisClass);
 
-      if Assigned(ThisClass.AncestorType) then
-      begin
-        if ThisClass.AncestorType.InheritsFrom(TPasClassType) then
-          ThisClass := TPasClassType(ThisClass.AncestorType)
-        else
+      if Assigned(ThisTreeNode) then
+        if Assigned(ThisTreeNode.ParentNode) then
         begin
-          if thisclass.ancestortype is TPasUnresolvedTypeRef then
-            thisnode:=TPasUnresolvedTypeRef(ThisClass.ancestortype);
           TDEl := CreateTD(CreateTR(TableEl));
           TDEl['align'] := 'center';
-          AppendText(CreateCode(CreatePara(TDEl)), UTF8Decode(ThisClass.AncestorType.Name));
-          if CompareText(ThisClass.AncestorType.Name, 'TObject') = 0 then
-            HaveSeenTObject := True
+          AppendText(TDEl, '|');
+          ThisClass := ThisTreeNode.ParentNode.Element;
+          ThisTreeNode := ThisTreeNode.ParentNode;
+        end
           else
-          begin
-            TDEl := CreateTD(CreateTR(TableEl));
-            TDEl['align'] := 'center';
-            AppendText(TDEl, '?');
-          end;
+        begin
+          ThisClass := nil;
+          ThisTreeNode:= nil;
           break;
         end
-      end else
+      else
         break;
     end;
-
-    if not HaveSeenTObject then
-    begin
-      TDEl := CreateTD(CreateTR(TableEl));
-      TDEl['align'] := 'center';
-      AppendText(CreateCode(CreatePara(TDEl)), 'TObject');
-    end;
-
     FinishElementPage(AClass);
   end;
 
@@ -3847,11 +3832,12 @@
   FinishElementPage(AProc);
 end;
 
-Function THTMLWriter.InterPretOption(Const Cmd,Arg : String) : boolean;
+function THTMLWriter.InterPretOption ( const Cmd, Arg: String ) : boolean;
 
   Function ReadFile(aFileName : string) : TstringStream;
 
   begin
+    aFileName:= SetDirSeparators(aFileName);
     try
       if copy(aFileName,1,1)<>'@' then
         Result:=TStringStream.Create(aFileName)
@@ -3942,7 +3928,7 @@
     end;
 end;
 
-Class Function THTMLWriter.FileNameExtension : String; 
+class function THTMLWriter.FileNameExtension: String;
 begin
   result:='';
 end;
Index: utils/fpdoc/dw_txt.pp
===================================================================
--- utils/fpdoc/dw_txt.pp	(revision 47648)
+++ utils/fpdoc/dw_txt.pp	(working copy)
@@ -158,18 +158,19 @@
 
 Var
   I,L : Integer;
-
+  SP: set of char;
 begin
   Result:=0;
+  SP := [#10,#13,' ',#9];
   I:=P;
   L:=Length(S);
-  While (I>0) and (I<=L) and not (S[i] in [#10,#13,' ',#9]) do
-    Dec(i);
+  While (I>0) and (I<=L) and not (S[i] in SP) do
+    Dec(I);
   If (I=0) then
     begin
-    I:=P;
-    While (I<=L) and not (S[i] in [#10,#13,' ',#9]) do
-      Inc(i);
+    Inc(I);
+    While (I<=L) and not (S[I] in SP) do
+      Inc(I);
     end;
   Result:=I;
 end;
@@ -186,7 +187,7 @@
     exit;
   N:=S;
   Repeat
-    If ((FCurrentPos+Length(N))>LineWidth) then
+    If ((FCurrentPos+Length(N)+1)>LineWidth) then
       begin
       L:=FindSpace(N,LineWidth-FCurrentPos+1);
       inherited Write(Copy(N,1,L-1));
@@ -195,8 +196,8 @@
       end
     else
       begin
-      L:=Length(N)+1;
-      inherited Write(Copy(N,1,L-1));
+      L:=Length(N);
+      inherited Write(Copy(N,1,L));
       Inc(FCurrentPos,L);
       If FCheckEOL then
         If (L>=LEOL) then
Index: utils/fpdoc/dwriter.pp
===================================================================
--- utils/fpdoc/dwriter.pp	(revision 47648)
+++ utils/fpdoc/dwriter.pp	(working copy)
@@ -25,7 +25,7 @@
 {$WARN 5024 off : Parameter "$1" not used}
 interface
 
-uses Classes, DOM, dGlobals, PasTree, SysUtils;
+uses Classes, DOM, dGlobals, PasTree, SysUtils, fpdocclasstree;
 
 resourcestring
   SErrFileWriting = 'An error occurred during writing of file "%s": %s';
@@ -80,8 +80,12 @@
     FImgExt : String;
     FBeforeEmitNote : TWriterNoteEvent;
     procedure ConvertURL(AContext: TPasElement; El: TDOMElement);
-    
+    procedure CreateClassTree;
   protected
+    TreeClass: TClassTreeBuilder;      // Global class tree
+    TreeInterface: TClassTreeBuilder;  // Global interface tree
+
+    procedure AddElementsFromList(L: TStrings; List: TFPList; UsePathName : Boolean = False);
     Procedure DoLog(Const Msg : String);
     Procedure DoLog(Const Fmt : String; Args : Array of const);
     procedure Warning(AContext: TPasElement; const AMsg: String);
@@ -339,7 +343,8 @@
 
 
 }
-Constructor TFPDocWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
+constructor TFPDocWriter.Create ( APackage: TPasPackage; AEngine: TFPDocEngine
+  ) ;
 
 begin
   inherited Create;
@@ -347,6 +352,9 @@
   FPackage := APackage;
   FTopics:=Tlist.Create;
   FImgExt:='.png';
+  TreeClass:= TClassTreeBuilder.Create(FEngine, FPackage, okClass);
+  TreeInterface:= TClassTreeBuilder.Create(FEngine, FPackage, okInterface);
+  CreateClassTree;
 end;
 
 destructor TFPDocWriter.Destroy;
@@ -358,6 +366,8 @@
   For I:=0 to FTopics.Count-1 do
     TTopicElement(FTopics[i]).Free;
   FTopics.Free;
+  TreeClass.free;
+  TreeInterface.Free;
   Inherited;
 end;
 
@@ -390,7 +400,7 @@
     end;
 end;
 
-Function TFPDocWriter.FindTopicElement(Node : TDocNode): TTopicElement;
+function TFPDocWriter.FindTopicElement ( Node: TDocNode ) : TTopicElement;
 
 Var
   I : Integer;
@@ -713,6 +723,55 @@
   DescrEndURL;
 end;
 
+procedure TFPDocWriter.AddElementsFromList ( L: TStrings; List: TFPList;
+  UsePathName: Boolean ) ;
+Var
+  I : Integer;
+  El : TPasElement;
+  N : TDocNode;
+
+begin
+  For I:=0 to List.Count-1 do
+    begin
+    El:=TPasElement(List[I]);
+    N:=Engine.FindDocNode(El);
+    if (N=Nil) or (not N.IsSkipped) then
+      begin
+      if UsePathName then
+        L.AddObject(El.PathName,El)
+      else
+        L.AddObject(El.Name,El);
+      If el is TPasEnumType then
+        AddElementsFromList(L,TPasEnumType(el).Values);
+      end;
+    end;
+end;
+
+procedure TFPDocWriter.CreateClassTree;
+var
+   L: TStringList;
+   M: TPasModule;
+   I:Integer;
+begin
+  L:=TStringList.Create;
+  try
+    For I:=0 to Package.Modules.Count-1 do
+      begin
+      M:=TPasModule(Package.Modules[i]);
+      if Not (M is TPasExternalModule) and assigned(M.InterfaceSection) then
+        Self.AddElementsFromList(L,M.InterfaceSection.Classes,True)
+      end;
+      TreeClass.BuildTree(L);
+      TreeInterface.BuildTree(L);
+      {$IFDEF TREE_TEST}
+      TreeClass.SaveToXml('TreeClass.xml');
+      TreeInterface.SaveToXml('TreeInterface.xml');
+      {$ENDIF}
+  Finally
+    L.Free;
+  end;
+end;
+
 procedure TFPDocWriter.DoLog(const Msg: String);
 begin
   If Assigned(FEngine.OnLog) then
@@ -1126,7 +1185,7 @@
     Result := False;
 end;
 
-Procedure TFPDocWriter.ConvertImage(El : TDomElement);
+procedure TFPDocWriter.ConvertImage ( El: TDomElement ) ;
 
 Var
   FN,Cap,LinkName : DOMString;
@@ -1169,7 +1228,7 @@
   Inherited;
 end;
 
-Function TFPDocWriter.WriteDescr(Element: TPasElement) : TDocNode;
+function TFPDocWriter.WriteDescr ( Element: TPasElement ) : TDocNode;
 
 begin
   Result:=Engine.FindDocNode(Element);
@@ -1211,7 +1270,8 @@
     Result:=Not ((M.Visibility=visProtected) and Engine.HideProtected)
 end;
 
-Procedure TFPDocWriter.GetMethodList(ClassDecl: TPasClassType; List : TStringList);
+procedure TFPDocWriter.GetMethodList ( ClassDecl: TPasClassType;
+  List: TStringList ) ;
 
 Var
   I : Integer;
Index: utils/fpdoc/fpdoc.pp
===================================================================
--- utils/fpdoc/fpdoc.pp	(revision 47648)
+++ utils/fpdoc/fpdoc.pp	(working copy)
@@ -428,6 +428,8 @@
 end;
 
 begin
+  //AssignFile(Output, 'fpdoc.log');
+  //rewrite(Output);
   With TFPDocApplication.Create(Nil) do
     try
       Run;
Index: utils/fpdoc/fpdocclasstree.pp
===================================================================
--- utils/fpdoc/fpdocclasstree.pp	(revision 47648)
+++ utils/fpdoc/fpdocclasstree.pp	(working copy)
@@ -5,7 +5,7 @@
 interface
 
 uses
-  Classes, SysUtils, DOM, pastree, contnrs;
+  Classes, SysUtils, dGlobals, pastree, contnrs, DOM ,XMLWrite;
 
 Type
 
@@ -13,16 +13,18 @@
 
   TPasElementNode = Class
   Private
-    FElement : TPasElement;
+    FElement : TPasClassType;
+    FParentNode: TPasElementNode;
     FChildren : TFPObjectList;
     function GetChild(aIndex : Integer): TPasElementNode;
     function GetChildCount: Integer;
   Public
-    Constructor Create (aElement : TPaselement);
+    Constructor Create (aElement : TPasClassType);
     Destructor Destroy; override;
     Procedure AddChild(C : TPasElementNode);
     Procedure SortChildren;
-    Property Element : TPasElement Read FElement;
+    Property Element : TPasClassType Read FElement;
+    Property ParentNode : TPasElementNode read  FParentNode;
     Property Children [aIndex : Integer] : TPasElementNode Read GetChild;
     Property ChildCount : Integer Read GetChildCount;
   end;
@@ -31,7 +33,7 @@
 
   TClassTreeBuilder = Class
   Private
-    // Full name -> TDomElement;
+    FEngine:TFPDocEngine;
     FElementList : TFPObjectHashTable;
     FObjectKind : TPasObjKind;
     FPackage: TPasPackage;
@@ -38,13 +40,20 @@
     FParentObject : TPasClassType;
     FRootNode : TPasElementNode;
     FRootObjectName : string;
+    FRootObjectPathName : string;
   Protected
     function AddToList(aElement: TPasClassType): TPasElementNode;
   Public
-    Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
+    Constructor Create(AEngine:TFPDocEngine; APackage : TPasPackage;
+                          AObjectKind : TPasObjKind = okClass);
     Destructor Destroy; override;
     Function BuildTree(AObjects : TStringList) : Integer;
+{$IFDEF TREE_TEST}
+    Procedure SaveToXml(AFileName: String);
+{$ENDIF}
     Property RootNode : TPasElementNode Read FRootNode;
+    Property PasElToNodes: TFPObjectHashTable read FElementList;
+    function GetPasElNode (APasEl: TPasElement) : TPasElementNode;
   end;
 
 implementation
@@ -72,7 +81,7 @@
     Result:=0
 end;
 
-constructor TPasElementNode.Create(aElement: TPaselement);
+constructor TPasElementNode.Create(aElement: TPasClassType);
 begin
   FElement:=aElement;
 end;
@@ -96,24 +105,38 @@
     FChildren.Sort(@SortOnElementName);
 end;
 
-constructor TClassTreeBuilder.Create(APackage : TPasPackage;
+constructor TClassTreeBuilder.Create(AEngine:TFPDocEngine; APackage : TPasPackage;
   AObjectKind: TPasObjKind);
 
 begin
-  FPackage:=APAckage;
+  FEngine:= AEngine;
+  FPackage:= APAckage;
   FObjectKind:=AObjectKind;
   Case FObjectkind of
-    okInterface : FRootObjectName:='#rtl.System.IInterface';
-    okObject,
-    okClass    : FRootObjectName:='#rtl.System.TObject';
+    okInterface :
+      begin
+        FRootObjectPathName:='#rtl.System.IInterface';
+        FRootObjectName:= 'IInterface';
+      end;
+    okObject, okClass :
+      begin
+        FRootObjectPathName:='#rtl.System.TObject';
+        FRootObjectName:= 'TObject';
+      end
   else
-    FRootObjectName:='#rtl.System.TObject';
+    begin
+      FRootObjectPathName:='#rtl.System.TObject';
+      FRootObjectName:= 'TObject';
+    end;
   end;
-  FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
+  FParentObject:=TPasClassType.Create(FRootObjectName,FEngine.FindModule('System'));
+  if not Assigned(FParentObject) then
+    FParentObject:=TPasClassType.Create(FRootObjectName,FPackage);
   FParentObject.ObjKind:=FObjectKind;
   FRootNode:=TPasElementNode.Create(FParentObject);
+  FRootNode.FParentNode := nil;
   FElementList:=TFPObjectHashTable.Create(False);
-  FElementList.Add(FRootObjectName,FRootNode);
+  FElementList.Add(FRootObjectPathName,FRootNode);
 end;
 
 destructor TClassTreeBuilder.Destroy;
@@ -124,7 +147,8 @@
   Inherited;
 end;
 
-Function TClassTreeBuilder.AddToList(aElement : TPasClassType) : TPasElementNode;
+function TClassTreeBuilder.AddToList ( aElement: TPasClassType
+  ) : TPasElementNode;
 
 Var
   aParentNode : TPasElementNode;
@@ -131,27 +155,29 @@
   aName : String;
 
 begin
+  Result:= nil;
+  if (aElement.ObjKind <> FObjectKind) then exit;
+  aParentNode:= nil;
   if aElement=Nil then
     aName:=FRootObjectName
   else
-    begin
     aName:=aElement.PathName;
-    end;
   Result:=TPasElementNode(FElementList.Items[aName]);
   if (Result=Nil) then
-    begin
+  begin
     if aElement.AncestorType is TPasClassType then
-      aParentNode:=AddToList(aElement.AncestorType as TPasClassType)
-    else
+      aParentNode:=AddToList(aElement.AncestorType as TPasClassType);
+    if not Assigned(aParentNode) then
       aParentNode:=FRootNode;
     Result:=TPasElementNode.Create(aElement);
     aParentNode.AddChild(Result);
+    Result.FParentNode := aParentNode;
     FElementList.Add(aName,Result);
-    end;
+  end;
 end;
 
 
-Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
+function TClassTreeBuilder.BuildTree ( AObjects: TStringList ) : Integer;
 
 (*
 Procedure DumpNode(Prefix : String; N : TPasElementNode);
@@ -182,7 +208,63 @@
       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(UnicodeString(PasElNode.Element.Name));
+      M:= PasElNode.Element.GetModule;
+      xmlEl['unit'] := UnicodeString(M.Name);
+      xmlEl['package'] := UnicodeString(M.PackageName);
+      ParentxmlEl.AppendChild(xmlEl);
+      AddPasElChildsToXml(xmlEl, PasElNode);
+    end;
+  end;
+
+var
+  XmlDoc: TXMLDocument;
+  XmlRootEl: TDOMElement;
+  M: TPasModule;
+begin
+  XmlDoc:= TXMLDocument.Create;
+  try
+    XmlRootEl:= XmlDoc.CreateElement(UnicodeString(FRootNode.Element.Name));
+    M:= FRootNode.Element.GetModule;
+    if Assigned(M) then
+    begin
+      XmlRootEl['unit'] := UnicodeString(M.Name);
+      XmlRootEl['package'] := UnicodeString(M.PackageName);
+    end
+      else
+    begin
+      XmlRootEl['unit'] := 'system';
+      XmlRootEl['package'] := 'rtl';
+    end;
+    XmlDoc.AppendChild(XmlRootEl);
+    AddPasElChildsToXml(XmlRootEl, FRootNode);
+    WriteXMLFile(XmlDoc, AFileName);
+  finally
+    XmlDoc.Free;
+  end;
+end;
+
+
 end.
 
Index: utils/fpdoc/mkfpdoc.pp
===================================================================
--- utils/fpdoc/mkfpdoc.pp	(revision 47648)
+++ utils/fpdoc/mkfpdoc.pp	(working copy)
@@ -42,6 +42,8 @@
     procedure SetVerbose(AValue: Boolean); virtual;
     Procedure DoLog(Const Msg : String);
     procedure DoLog(Const Fmt : String; Args : Array of Const);
+    Procedure DoLogSender(Sender : TObject; Const Msg : String);
+    // Create documetation by specified Writer class
     procedure CreateOutput(APackage: TFPDocPackage; Engine: TFPDocEngine); virtual;
   Public
     Constructor Create(AOwner : TComponent); override;
@@ -96,6 +98,14 @@
   DoLog(Format(Fmt,Args));
 end;
 
+procedure TFPDocCreator.DoLogSender ( Sender: TObject; const Msg: String ) ;
+begin
+  if Assigned(Sender) then
+    DoLog(Format('%s - Sender: %s', [Msg, Sender.ClassName]))
+  else
+    DoLog(Msg);
+end;
+
 procedure TFPDocCreator.HandleOnParseUnit(Sender: TObject;
   const AUnitName: String; out AInputFile, OSTarget, CPUTarget: String);
 
@@ -208,7 +218,9 @@
   Cmd,Arg : String;
 
 begin
+  // Now is used the specified writer
   WriterClass:=GetWriterClass(Options.Backend);
+  // ALL CONTENT CREATED HERE
   Writer:=WriterClass.Create(Engine.Package,Engine);
   With Writer do
     Try
@@ -225,10 +237,12 @@
           If not InterPretOption(Cmd,Arg) then
             DoLog(SCmdLineInvalidOption,[Cmd+'='+Arg]);
           end;
+      // Output created Documentation
       WriteDoc;
     Finally
       Free;
     end;
+  // Output content files
   Writeln('Content file : ',APackage.ContentFile);
   if Length(APackage.ContentFile) > 0 then
     Engine.WriteContentFile(APackage.ContentFile);
@@ -247,16 +261,21 @@
   Cmd:='';
   FCurPackage:=APackage;
   Engine:=TFPDocEngine.Create;
+  Engine.OnLog:= @DoLogSender;
   try
+    // get documentation Writer html, latex, and other
     WriterClass:=GetWriterClass(Options.Backend);
     For J:=0 to Apackage.Imports.Count-1 do
       begin
       Arg:=Apackage.Imports[j];
+      // conversion import FilePathes
       WriterClass.SplitImport(Arg,Cmd);
+      // create tree of imported objects
       Engine.ReadContentFile(Arg, Cmd);
       end;
     for i := 0 to APackage.Descriptions.Count - 1 do
       Engine.AddDocFile(FixDescrFile(APackage.Descriptions[i]),Options.donttrim);
+    // set engine options
     Engine.SetPackageName(APackage.Name);
     Engine.Output:=APackage.Output;
     Engine.OnLog:=Self.OnLog;
@@ -268,13 +287,18 @@
     Engine.WarnNoNode:=Options.WarnNoNode;
     if Length(Options.Language) > 0 then
       TranslateDocStrings(Options.Language);
+    // scan the input source files
     for i := 0 to APackage.Inputs.Count - 1 do
       try
+        // get options from input packages
         SplitInputFileOption(APackage.Inputs[i],Cmd,Arg);
+        // make absolute filepath
         Cmd:=FixInputFile(Cmd);
         if FProcessedUnits.IndexOf(Cmd)=-1 then
           begin
           FProcessedUnits.Add(Cmd);
+          // Parce sources for OS Target
+          //WriteLn(Format('Parcing unit: %s', [ExtractFilenameOnly(Cmd)]));
           ParseSource(Engine,Cmd+' '+Arg, Options.OSTarget, Options.CPUTarget,[poUseStreams]);
           end;
       except
@@ -290,6 +314,7 @@
     if Not ParseOnly then
       begin
       Engine.StartDocumenting;
+      // Create documentation
       CreateOutput(APackage,Engine);
       end;
   finally
patch_fpdoc_02.patch (52,198 bytes)   
patch_fpdoc_description_02_en.txt (3,231 bytes)   
Fix Description.

I apologize that I was placed a lot in this patch, but almost everything does not work separately. If you say that you need to divide on the parts, then I will do it. But I did not have the opportunity to make intermediate fixations in repo.

Changes:
1. Correction of the generation of XCT files. Unit dGlobal.pp. Now all classes have only full FilePath with the package name.
FUNSTION - TFPDOCENGINE.WRIPECONTENTFILE()

2. Small fixing of the assembly link to the internal pages
FUNCTION - TFPDOCENGINE.REDCONTENTFILE LINES 719 - 720.

3. Remake the classes tree for the pages of the classes hierarchy. Here are great changes.
Unit Fpdocclasstree.
 Now this class is used for building the class pages.
 Two Instance of this class are created in TFPDocWriter. Now trees (TreeClasse, TreeInterface) is available for another writer classes.
 An example of a tree for my test is attached. (TreeClass.xml, TreeInterface.xml)
 OutPut of that class will be used by TXMLWriter.

4. Remake the page with the display hierarchy of classes for the entire package.

5. Remake the main page of the class display page, so that there were no passages of the hierarchy. Use the Fpdocclasstree classe.
DW_HTML.PP Procedure CreatemainPage;

6. Fix small exception ino dw_txt.pas

7. After fixing the XCT file and some functions, all methods and properties of the ancestors appeared in all pages of Class-Functions Class-Properties Class-Events. After it, the chm file and the full-text index grew very much. Also began to load Lhelp for a long time. These pages not have a title and are useless for the index, so I tried to turn them off from full-text search. But in Packages / CHM / SRC / CHMWRITER.PAS, there is no possibility to remove some files from full-text search, you can only turn off all files. Here I apologize, I made a hack, you decide. But if this is not done, then everything made will be useless.
I added to Packages/CHM/SRC/CHMWRITER.PAS the hack code. The exclution of files from a full-text index if they start from the point. That in general logical and then it will be possible to exclude other index pages. As a result, full-text search became beautiful. I don`t know how to do that another. I didn`t want use external index for that.

8. Change in the upper bar, because it was very difficult to understande where I am now. Now I obviously signed when I displays the data of the unit or package.
DW_HTML.PP - Thtmlwriter.APPendMenubar

9. Misc 
- The situation with the RTF format is incomprehensible, it does not open with me.
- Also attached the generated tree objects for the classes hierarchy (TreeClass.xml, TreeInterface.xml)
- An XML mode produces exception when I start without created before an output directory (need to add the directory creation before output).

  
Attached:
- The test files TXT, IPF, MAN, CHTM, HTML modes, and a new LCL.CHM as an example.
- I have no opportunity to check LATEX on Windows, but the machine with Linux has already collected.
- New rtl.xct fcl.xct

Files:
https://drive.google.com/file/d/1myUOZGsGTl42aaji68WC6G0XczUZaT19/view?usp=sharing

I hope that you can allocate time to work with this FIX.

Andrey Sobol.

Marco van de Voort

2020-12-06 21:30

manager   ~0127384

Again: the "." search modification is not necessary in chmwriter, which is general code.

chmwriter.fileadd can be overriden in a fpdoc dependent derived class if need be.

Andrey Sobol

2020-12-07 05:11

reporter   ~0127390

Ok, I will change that.

Michael Van Canneyt

2020-12-07 13:01

administrator   ~0127414

Applied what could be applied in rev 47710.

Your code did not compile:
* fpclasschart didn't compile, you added an engine argument to class tree builder constructor
* visibility names missed 2 elements (required, optional)
* missing IFDEF TEST_TREE around SaveToXML method implementation.

After fixing that and a cosmetic change in output, all seems to work for html.
Thank you for your efforts !

I'm not closing this yet, so you can create a proper patch for the chm writer.

Andrey Sobol

2020-12-07 14:31

reporter   ~0127420

Last edited: 2020-12-07 14:39

View 4 revisions

I will watch yours changes.
Thank you for yours spent time.

Andrey Sobol

2020-12-07 19:08

reporter   ~0127429

The patch for exclude the chmWriter dependency.
I want check the docs more thoroughly when I will have a linux machine and full build of docs. How is better to send changes. By issue only?
In advance thank for answer.
Andrey.
patch_fpdoc_03.patch (1,905 bytes)   
Index: dw_html.pp
===================================================================
--- dw_html.pp	(revision 47710)
+++ dw_html.pp	(working copy)
@@ -19,7 +19,7 @@
 {$WARN 5024 off : Parameter "$1" not used}
 interface
 
-uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter;
+uses Classes, DOM, DOM_HTML, dGlobals, PasTree, dWriter, ChmWriter, chmtypes;
 
 const
   // Subpage indices for modules
Index: dw_htmlchm.inc
===================================================================
--- dw_htmlchm.inc	(revision 47710)
+++ dw_htmlchm.inc	(working copy)
@@ -2,12 +2,19 @@
 {$IFDEF chmInterface}
 type
 
+  { TFpDocChmWriter }
+
+  TFpDocChmWriter = class (TChmWriter)
+  protected
+    procedure FileAdded(AStream: TStream; const AEntry: TFileEntryRec); override;
+  end;
+
   { TCHMHTMLWriter }
 
   TCHMHTMLWriter = class(THTMLWriter)
   private
     FOutChm: TStream;
-    FChm: TChmWriter;
+    FChm: TFpDocChmWriter;
     FTempUncompressed: TStream;
     FTempUncompressedName: String;
     FChmTitle: String;
@@ -37,6 +44,17 @@
   end;
 {$ELSE} // implementation
 
+{ TFpDocChmWriter }
+
+procedure TFpDocChmWriter.FileAdded ( AStream: TStream;
+  const AEntry: TFileEntryRec ) ;
+begin
+  // Exclude Full text index for files starting from the dot
+  if Pos('.', AEntry.Name) <> 1 then
+    inherited FileAdded(AStream, AEntry);
+
+end;
+
 { TCHMHTMLWriter }
 
 function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString;
@@ -466,7 +484,7 @@
 
   FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
   FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite  or fmCreate);
-  FChm := TChmWriter.Create(FOutChm, False);
+  FChm := TFpDocChmWriter.Create(FOutChm, False);
   FChm.Title := FChmTitle;
   FChm.TempRawStream := FTempUncompressed;
   FChm.OnGetFileData := @RetrieveOtherFiles;
patch_fpdoc_03.patch (1,905 bytes)   

Marco van de Voort

2020-12-07 21:28

manager   ~0127435

Updated chms and object tree dependencies looks fine:

http://www.stack.nl/~marcov/doc-chm.zip

Andrey Sobol

2020-12-07 21:38

reporter   ~0127436

Send me please xct files also

Andrey Sobol

2020-12-07 21:50

reporter   ~0127438

We will have a clean search result when you apply the last patch.

Marco van de Voort

2020-12-07 23:09

manager   ~0127439

Andrey they are in the http://www.stack.nl/~marcov/doc-chmbeta.zip archive, which also contains lazutils/lcl

serbod

2020-12-08 08:11

reporter   ~0127442

User guide (user.chm)
Contents page


<meta content="text/html; charset=iso8859-1" http-equiv="Content-Type">

<div class="author"><span class="cmss-12">Micha</span><span class="cmss-12">?l Van Canneyt</span><br class="newline"><span class="cmss-12">Florian Kl</span><span class="cmss-12">?mpfl</span></div> <br class="newline">____________________________________________________________________________


Non-ASCII characters missed, and replaced by SPAN tag.

Andrey Sobol

2020-12-08 08:47

reporter   ~0127444

How is it joined to this issue? It was and before. You can change it or open new issue.

Marco van de Voort

2020-12-08 09:39

manager   ~0127446

serbod I think that is the latex->html conversion, and not the archiving of the result. But I can have a look, please file a separate issue.

serbod

2020-12-08 10:07

reporter   ~0127447

Submitted as 0038184

Michael Van Canneyt

2020-12-08 10:50

administrator   ~0127450

Applied your latest patch. Please test and close if OK.

Thank you for your efforts, it is a real improvement !

Andrey Sobol

2020-12-08 14:14

reporter   ~0127456

That is fine :) Index includes only usefull info.
Thank you for spent your time.

Issue History

Date Modified Username Field Change
2020-11-27 20:09 Andrey Sobol New Issue
2020-11-27 20:09 Andrey Sobol File Added: 2020-11-03 16_22_17-LHelp - (FCL) Free Component Library [(FCL) Free Pascal Resources support, FPDoc.jpg
2020-11-27 20:09 Andrey Sobol File Added: 2020-11-27 21_28_39-(RTL) Runtime Library.jpg
2020-11-27 20:09 Andrey Sobol File Added: 2020-11-27 21_43_34-mk_@MSITStore_M__lazarus_docs_chm_fcl.chm___iostream_eiostreamerror-3.html - Int.jpg
2020-11-27 21:31 Marco van de Voort Note Added: 0127215
2020-11-27 21:38 Andrey Sobol Note Added: 0127216
2020-11-27 21:44 Marco van de Voort Note Added: 0127217
2020-11-27 23:11 Marco van de Voort Note Added: 0127218
2020-11-28 00:55 Michael Van Canneyt Assigned To => Michael Van Canneyt
2020-11-28 00:55 Michael Van Canneyt Status new => assigned
2020-11-28 01:03 Michael Van Canneyt Note Added: 0127221
2020-11-28 05:14 Marco van de Voort Note Added: 0127222
2020-11-28 09:37 Andrey Sobol Note Added: 0127225
2020-11-28 10:04 Andrey Sobol Note Edited: 0127225 View Revisions
2020-11-28 10:42 Michael Van Canneyt Note Added: 0127229
2020-11-28 10:43 Michael Van Canneyt Note Edited: 0127229 View Revisions
2020-11-29 13:05 Marco van de Voort Note Added: 0127255
2020-11-30 19:14 Andrey Sobol Note Added: 0127272
2020-11-30 19:14 Andrey Sobol File Added: patch_fpdoc_01.patch
2020-11-30 19:14 Andrey Sobol File Added: patch_fpdoc_description_01_en.txt
2020-11-30 19:34 Michael Van Canneyt Note Added: 0127273
2020-11-30 19:34 Michael Van Canneyt Status assigned => feedback
2020-11-30 19:34 Michael Van Canneyt FPCTarget => -
2020-11-30 20:32 Andrey Sobol Note Added: 0127277
2020-11-30 20:32 Andrey Sobol Status feedback => assigned
2020-11-30 20:35 Andrey Sobol Note Added: 0127278
2020-11-30 21:04 Andrey Sobol Note Edited: 0127278 View Revisions
2020-12-01 10:06 Michael Van Canneyt Note Added: 0127287
2020-12-01 17:10 Marco van de Voort Note Added: 0127304
2020-12-01 17:19 Andrey Sobol Note Added: 0127305
2020-12-02 18:52 Andrey Sobol Note Added: 0127322
2020-12-02 18:52 Andrey Sobol File Added: patch_fpdoc_02.patch
2020-12-02 18:52 Andrey Sobol File Added: patch_fpdoc_description_02_en.txt
2020-12-02 18:59 Andrey Sobol Note Edited: 0127322 View Revisions
2020-12-02 19:00 Andrey Sobol Note Edited: 0127322 View Revisions
2020-12-03 10:41 Andrey Sobol Note Edited: 0127322 View Revisions
2020-12-06 21:30 Marco van de Voort Note Added: 0127384
2020-12-07 05:11 Andrey Sobol Note Added: 0127390
2020-12-07 13:01 Michael Van Canneyt Note Added: 0127414
2020-12-07 14:31 Andrey Sobol Note Added: 0127420
2020-12-07 14:32 Andrey Sobol Note Edited: 0127420 View Revisions
2020-12-07 14:38 Andrey Sobol Note Edited: 0127420 View Revisions
2020-12-07 14:39 Andrey Sobol Note Edited: 0127420 View Revisions
2020-12-07 19:08 Andrey Sobol Note Added: 0127429
2020-12-07 19:08 Andrey Sobol File Added: patch_fpdoc_03.patch
2020-12-07 21:28 Marco van de Voort Note Added: 0127435
2020-12-07 21:38 Andrey Sobol Note Added: 0127436
2020-12-07 21:50 Andrey Sobol Note Added: 0127438
2020-12-07 21:50 Andrey Sobol File Added: 2020-12-07 23_41_52-LHelp - test [(FCL) Free Component Library, My FCL-image, (FCL) Free Pascal Reso-2.jpg
2020-12-07 23:09 Marco van de Voort Note Added: 0127439
2020-12-08 08:11 serbod Note Added: 0127442
2020-12-08 08:47 Andrey Sobol Note Added: 0127444
2020-12-08 09:39 Marco van de Voort Note Added: 0127446
2020-12-08 10:07 serbod Note Added: 0127447
2020-12-08 10:50 Michael Van Canneyt Status assigned => resolved
2020-12-08 10:50 Michael Van Canneyt Resolution open => fixed
2020-12-08 10:50 Michael Van Canneyt Fixed in Version => 3.3.1
2020-12-08 10:50 Michael Van Canneyt Fixed in Revision => 47719
2020-12-08 10:50 Michael Van Canneyt FPCTarget - => 3.2.2
2020-12-08 10:50 Michael Van Canneyt Note Added: 0127450
2020-12-08 14:14 Andrey Sobol Note Added: 0127456
2020-12-08 14:14 Andrey Sobol File Added: 2020-12-08 16_11_32-Lazarus IDE v2.0.11 - FPDoc Documentation generator.jpg
2020-12-08 14:14 Andrey Sobol File Added: 2020-12-08 16_10_39-Lazarus IDE v2.0.11 - FPDoc Documentation generator.jpg
2020-12-26 21:41 Juha Manninen Relationship added related to 0038250